feat: 内容管理
This commit is contained in:
@@ -12,7 +12,7 @@
|
||||
"!**/mock",
|
||||
"!**/dist",
|
||||
"!**/server",
|
||||
"!**/public/**/*",
|
||||
"!**/public",
|
||||
"!**/coverage",
|
||||
"!**/node_modules",
|
||||
"!biome.json"
|
||||
|
||||
@@ -20,6 +20,7 @@ const Settings: ProLayoutProps & {
|
||||
logo: '/logo.svg',
|
||||
iconfontUrl: '',
|
||||
splitMenus: true,
|
||||
|
||||
token: {
|
||||
// 参见ts声明,demo 见文档,通过token 修改样式
|
||||
// 设置内容区域的边距
|
||||
|
||||
@@ -13,13 +13,10 @@ export default {
|
||||
// 如果需要自定义本地开发服务器 请取消注释按需调整
|
||||
dev: {
|
||||
// localhost:8000/api/** -> https://preview.pro.ant.design/api/**
|
||||
"/admin-api/": {
|
||||
// 要代理的地址
|
||||
'/admin-api/': {
|
||||
// http://192.168.1.231:48080 伟强
|
||||
// https://petshy.tashowz.com/
|
||||
target: "https://petshy.tashowz.com/",
|
||||
// 配置了这个可以从 http 代理到 https
|
||||
// 依赖 origin 的功能可能需要这个,比如 cookie
|
||||
target: 'https://petshy.tashowz.com',
|
||||
changeOrigin: true,
|
||||
},
|
||||
},
|
||||
@@ -29,17 +26,17 @@ export default {
|
||||
*/
|
||||
test: {
|
||||
// localhost:8000/api/** -> https://preview.pro.ant.design/api/**
|
||||
"/api/": {
|
||||
target: "https://petshy.tashowz.com/",
|
||||
'/api/': {
|
||||
target: 'https://petshy.tashowz.com/',
|
||||
changeOrigin: true,
|
||||
pathRewrite: { "^": "" },
|
||||
pathRewrite: { '^': '' },
|
||||
},
|
||||
},
|
||||
pre: {
|
||||
"/api/": {
|
||||
target: "your pre url",
|
||||
'/api/': {
|
||||
target: 'https://petshy.tashowz.com/',
|
||||
changeOrigin: true,
|
||||
pathRewrite: { "^": "" },
|
||||
pathRewrite: { '^': '' },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -34,35 +34,26 @@ export default [
|
||||
path: '/',
|
||||
redirect: '/welcome',
|
||||
},
|
||||
{
|
||||
path: '/trade',
|
||||
name: '交易管理',
|
||||
routes: [
|
||||
{
|
||||
name: '订单管理',
|
||||
path: '/trade/order',
|
||||
component: './trade/order/index',
|
||||
},
|
||||
],
|
||||
},
|
||||
// {
|
||||
// path: "/trade",
|
||||
// name: "交易管理",
|
||||
// routes: [
|
||||
// {
|
||||
// name: "订单管理",
|
||||
// path: "/trade/order",
|
||||
// component: "./trade/order/index",
|
||||
// },
|
||||
// ],
|
||||
|
||||
// },
|
||||
{
|
||||
path: '/prod1',
|
||||
name: '商品管理1',
|
||||
path: '/ai1',
|
||||
name: 'AI1',
|
||||
routes: [
|
||||
{
|
||||
path: '', // 空路径,匹配 /prod
|
||||
redirect: 'list', // 相对路径重定向
|
||||
},
|
||||
{
|
||||
name: '商品1',
|
||||
path: '/prod1/list',
|
||||
component: './prod/list/index',
|
||||
},
|
||||
{
|
||||
name: '类目管理',
|
||||
path: '/prod1/category',
|
||||
component: './prod/category/index',
|
||||
name: 'ai样本',
|
||||
path: '/ai1/tag',
|
||||
component: './ai/sample-tag',
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -77,6 +68,26 @@ export default [
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// path: "/prod1",
|
||||
// name: "商品管理2",
|
||||
// routes: [
|
||||
// // { index: true, component: "./prod/list/index" },
|
||||
// {
|
||||
// name: "商品管理",
|
||||
// path: "list",
|
||||
// component: "./prod/list/index",
|
||||
// routes: [
|
||||
// {
|
||||
// name: "类目管理",
|
||||
// path: "detail",
|
||||
// component: "./prod/category/index",
|
||||
// hideInMenu: true,
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
{
|
||||
component: '404',
|
||||
layout: false,
|
||||
|
||||
3128
mock/dict.ts
Normal file
3128
mock/dict.ts
Normal file
File diff suppressed because it is too large
Load Diff
706
mock/order.ts
706
mock/order.ts
@@ -5,193 +5,223 @@ const getOrderPage = (_req: Request, res: Response) => {
|
||||
list: [
|
||||
{
|
||||
id: 1,
|
||||
orderNum: "BZ000548787",
|
||||
createTime: "2025-10-1 14:00:00",
|
||||
orderCategoryName: "宠物殡葬", // 订单类目
|
||||
orderTerminal: 0, // 订单来源
|
||||
userId: 0, // 用户编号
|
||||
userName: "", // 用户姓名
|
||||
userNickName: "张宁清", // 用户昵称
|
||||
userAvatar: "", // 用户头像
|
||||
userMobile: "18634556151", // 用户手机号
|
||||
orderStatus: 10, // 订单状态
|
||||
picUrl: "", // 商品图片
|
||||
spuName:
|
||||
"商品主标题商品主标题商品主标题商品主标题商品主题商品主标题商品主标题商品主", // 商品名称
|
||||
skuName: "标准,单独火化,基础清洁", // 商品规格
|
||||
count: 1, // 购买商品数量
|
||||
price: 100, // 单价
|
||||
handedPrice: 80, // 到手价
|
||||
payPrice: "500", // 应付金额
|
||||
unit: "", // 单位
|
||||
subTime: 1760585499000, // 预约时间
|
||||
serveAddress: "张宁清,18659156151,福州 台江区 鳌峰路 万达中心甲",
|
||||
userRemark: "你好呀你好元", // 用户备注
|
||||
payType: "wx", // 微信
|
||||
financeStatus: "1", // 财务状态
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
orderNum: "3214421412",
|
||||
createTime: "",
|
||||
orderCategoryName: "宠物殡葬",
|
||||
orderTerminal: 0,
|
||||
userId: 0,
|
||||
userName: "",
|
||||
userNickName: "",
|
||||
userAvatar: "",
|
||||
userMobile: "",
|
||||
orderStatus: 20,
|
||||
picUrl: "",
|
||||
spuName: "",
|
||||
skuName: "",
|
||||
subTime: 1760585499000, // 预约时间
|
||||
count: 0,
|
||||
price: 0,
|
||||
handedPrice: 0,
|
||||
payPrice: 0,
|
||||
unit: "",
|
||||
orderTime: "",
|
||||
serveAddress: "",
|
||||
userRemark: "",
|
||||
payType: "",
|
||||
financeStatus: "",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
orderNum: "3214421412",
|
||||
createTime: "",
|
||||
orderCategoryName: "宠物殡葬",
|
||||
orderTerminal: 0,
|
||||
userId: 0,
|
||||
userName: "",
|
||||
subTime: 1760585499000, // 预约时间
|
||||
userNickName: "",
|
||||
userAvatar: "",
|
||||
userMobile: "",
|
||||
orderStatus: 30,
|
||||
picUrl: "",
|
||||
spuName: "",
|
||||
skuName: "",
|
||||
count: 0,
|
||||
price: 0,
|
||||
handedPrice: 0,
|
||||
payPrice: 0,
|
||||
unit: "",
|
||||
orderTime: "",
|
||||
serveAddress: "",
|
||||
userRemark: "",
|
||||
payType: "",
|
||||
financeStatus: "",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
orderNum: "3214421412",
|
||||
createTime: "",
|
||||
orderCategoryName: "宠物殡葬",
|
||||
orderTerminal: 0,
|
||||
userId: 0,
|
||||
userName: "",
|
||||
subTime: 1760585499000, // 预约时间
|
||||
userNickName: "",
|
||||
userAvatar: "",
|
||||
userMobile: "",
|
||||
orderStatus: 40,
|
||||
picUrl: "",
|
||||
spuName: "",
|
||||
skuName: "",
|
||||
count: 0,
|
||||
price: 0,
|
||||
handedPrice: 0,
|
||||
payPrice: 0,
|
||||
unit: "",
|
||||
orderTime: "",
|
||||
serveAddress: "",
|
||||
userRemark: "",
|
||||
payType: "",
|
||||
financeStatus: "",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
orderNum: "3214421412",
|
||||
createTime: "",
|
||||
orderCategoryName: "宠物殡葬",
|
||||
orderTerminal: 0,
|
||||
userId: 0,
|
||||
userName: "",
|
||||
subTime: 1760585499000, // 预约时间
|
||||
userNickName: "",
|
||||
userAvatar: "",
|
||||
userMobile: "",
|
||||
orderStatus: 50,
|
||||
picUrl: "",
|
||||
spuName: "",
|
||||
skuName: "",
|
||||
count: 0,
|
||||
price: 0,
|
||||
handedPrice: 0,
|
||||
payPrice: 0,
|
||||
unit: "",
|
||||
orderTime: "",
|
||||
serveAddress: "",
|
||||
userRemark: "",
|
||||
payType: "",
|
||||
financeStatus: "",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
orderNum: "3214421412",
|
||||
createTime: "",
|
||||
orderCategoryName: "宠物殡葬",
|
||||
orderTerminal: 0,
|
||||
userId: 0,
|
||||
userName: "",
|
||||
subTime: 1760585499000, // 预约时间
|
||||
userNickName: "",
|
||||
userAvatar: "",
|
||||
userMobile: "",
|
||||
orderStatus: 60,
|
||||
picUrl: "",
|
||||
spuName: "",
|
||||
skuName: "",
|
||||
count: 0,
|
||||
price: 0,
|
||||
handedPrice: 0,
|
||||
payPrice: 0,
|
||||
unit: "",
|
||||
orderTime: "",
|
||||
serveAddress: "",
|
||||
userRemark: "",
|
||||
payType: "",
|
||||
financeStatus: "",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
orderNum: "3214421412",
|
||||
createTime: "",
|
||||
orderCategoryName: "宠物殡葬",
|
||||
orderTerminal: 0,
|
||||
userId: 0,
|
||||
userName: "",
|
||||
subTime: 1760585499000, // 预约时间
|
||||
userNickName: "",
|
||||
userAvatar: "",
|
||||
userMobile: "",
|
||||
orderStatus: 70,
|
||||
picUrl: "",
|
||||
spuName: "",
|
||||
skuName: "",
|
||||
count: 0,
|
||||
price: 0,
|
||||
handedPrice: 0,
|
||||
payPrice: 0,
|
||||
unit: "",
|
||||
orderTime: "",
|
||||
serveAddress: "",
|
||||
userRemark: "",
|
||||
payType: "",
|
||||
financeStatus: "",
|
||||
orderNum: "123333333333",
|
||||
orderType: 1,
|
||||
orderTerminal: 1,
|
||||
orderStatus: 10,
|
||||
userId: 1,
|
||||
userName: "李老师",
|
||||
userNickName: null,
|
||||
userAvatar: null,
|
||||
userMobile: "17609087876",
|
||||
userRemark: "测试用户备注",
|
||||
createTime: "2025-10-16 11:31:39",
|
||||
finishTime: "2025-10-16 11:28:55",
|
||||
items: [
|
||||
{
|
||||
picUrl:
|
||||
"https://inews.gtimg.com/news_bt/OBkbmPLeWLy4IM4oUDGvOIqSDSZ9lYOtW3qSXCYh78KXcAA/1000",
|
||||
spuName: "测试商品名称",
|
||||
skuName: "规格名称",
|
||||
count: 1,
|
||||
price: 1,
|
||||
discountPrice: 1,
|
||||
handedPrice: 0,
|
||||
payPrice: 1,
|
||||
unit: "件",
|
||||
subTime: "2025-10-16 11:34:10",
|
||||
serveAddress: "11232",
|
||||
},
|
||||
],
|
||||
shopName: null,
|
||||
shopLogo: null,
|
||||
payLastTime: null,
|
||||
},
|
||||
// {
|
||||
// orderTerminal: 0, // 订单来源
|
||||
// userId: 0, // 用户编号
|
||||
// userName: "", // 用户姓名
|
||||
// userNickName: "张宁清", // 用户昵称
|
||||
// userAvatar: "", // 用户头像
|
||||
// userMobile: "18634556151", // 用户手机号
|
||||
// orderStatus: 10, // 订单状态
|
||||
// picUrl: "", // 商品图片
|
||||
// spuName:
|
||||
// "商品主标题商品主标题商品主标题商品主标题商品主题商品主标题商品主标题商品主", // 商品名称
|
||||
// skuName: "标准,单独火化,基础清洁", // 商品规格
|
||||
// count: 1, // 购买商品数量
|
||||
// price: 100, // 单价
|
||||
// handedPrice: 80, // 到手价
|
||||
// payPrice: "500", // 应付金额
|
||||
// unit: "", // 单位
|
||||
// subTime: 1760585499000, // 预约时间
|
||||
// serveAddress: "张宁清,18659156151,福州 台江区 鳌峰路 万达中心甲",
|
||||
// userRemark: "你好呀你好元", // 用户备注
|
||||
// payType: "wx", // 微信
|
||||
// financeStatus: "1", // 财务状态
|
||||
// },
|
||||
// {
|
||||
// id: 2,
|
||||
// orderNum: "3214421412",
|
||||
// createTime: "",
|
||||
// orderCategoryName: "宠物殡葬",
|
||||
// orderTerminal: 0,
|
||||
// userId: 0,
|
||||
// userName: "",
|
||||
// userNickName: "",
|
||||
// userAvatar: "",
|
||||
// userMobile: "",
|
||||
// orderStatus: 20,
|
||||
// picUrl: "",
|
||||
// spuName: "",
|
||||
// skuName: "",
|
||||
// subTime: 1760585499000, // 预约时间
|
||||
// count: 0,
|
||||
// price: 0,
|
||||
// handedPrice: 0,
|
||||
// payPrice: 0,
|
||||
// unit: "",
|
||||
// orderTime: "",
|
||||
// serveAddress: "",
|
||||
// userRemark: "",
|
||||
// payType: "",
|
||||
// financeStatus: "",
|
||||
// },
|
||||
// {
|
||||
// id: 3,
|
||||
// orderNum: "3214421412",
|
||||
// createTime: "",
|
||||
// orderCategoryName: "宠物殡葬",
|
||||
// orderTerminal: 0,
|
||||
// userId: 0,
|
||||
// userName: "",
|
||||
// subTime: 1760585499000, // 预约时间
|
||||
// userNickName: "",
|
||||
// userAvatar: "",
|
||||
// userMobile: "",
|
||||
// orderStatus: 30,
|
||||
// picUrl: "",
|
||||
// spuName: "",
|
||||
// skuName: "",
|
||||
// count: 0,
|
||||
// price: 0,
|
||||
// handedPrice: 0,
|
||||
// payPrice: 0,
|
||||
// unit: "",
|
||||
// orderTime: "",
|
||||
// serveAddress: "",
|
||||
// userRemark: "",
|
||||
// payType: "",
|
||||
// financeStatus: "",
|
||||
// },
|
||||
// {
|
||||
// id: 4,
|
||||
// orderNum: "3214421412",
|
||||
// createTime: "",
|
||||
// orderCategoryName: "宠物殡葬",
|
||||
// orderTerminal: 0,
|
||||
// userId: 0,
|
||||
// userName: "",
|
||||
// subTime: 1760585499000, // 预约时间
|
||||
// userNickName: "",
|
||||
// userAvatar: "",
|
||||
// userMobile: "",
|
||||
// orderStatus: 40,
|
||||
// picUrl: "",
|
||||
// spuName: "",
|
||||
// skuName: "",
|
||||
// count: 0,
|
||||
// price: 0,
|
||||
// handedPrice: 0,
|
||||
// payPrice: 0,
|
||||
// unit: "",
|
||||
// orderTime: "",
|
||||
// serveAddress: "",
|
||||
// userRemark: "",
|
||||
// payType: "",
|
||||
// financeStatus: "",
|
||||
// },
|
||||
// {
|
||||
// id: 5,
|
||||
// orderNum: "3214421412",
|
||||
// createTime: "",
|
||||
// orderCategoryName: "宠物殡葬",
|
||||
// orderTerminal: 0,
|
||||
// userId: 0,
|
||||
// userName: "",
|
||||
// subTime: 1760585499000, // 预约时间
|
||||
// userNickName: "",
|
||||
// userAvatar: "",
|
||||
// userMobile: "",
|
||||
// orderStatus: 50,
|
||||
// picUrl: "",
|
||||
// spuName: "",
|
||||
// skuName: "",
|
||||
// count: 0,
|
||||
// price: 0,
|
||||
// handedPrice: 0,
|
||||
// payPrice: 0,
|
||||
// unit: "",
|
||||
// orderTime: "",
|
||||
// serveAddress: "",
|
||||
// userRemark: "",
|
||||
// payType: "",
|
||||
// financeStatus: "",
|
||||
// },
|
||||
// {
|
||||
// id: 6,
|
||||
// orderNum: "3214421412",
|
||||
// createTime: "",
|
||||
// orderCategoryName: "宠物殡葬",
|
||||
// orderTerminal: 0,
|
||||
// userId: 0,
|
||||
// userName: "",
|
||||
// subTime: 1760585499000, // 预约时间
|
||||
// userNickName: "",
|
||||
// userAvatar: "",
|
||||
// userMobile: "",
|
||||
// orderStatus: 60,
|
||||
// picUrl: "",
|
||||
// spuName: "",
|
||||
// skuName: "",
|
||||
// count: 0,
|
||||
// price: 0,
|
||||
// handedPrice: 0,
|
||||
// payPrice: 0,
|
||||
// unit: "",
|
||||
// orderTime: "",
|
||||
// serveAddress: "",
|
||||
// userRemark: "",
|
||||
// payType: "",
|
||||
// financeStatus: "",
|
||||
// },
|
||||
// {
|
||||
// id: 7,
|
||||
// orderNum: "3214421412",
|
||||
// createTime: "",
|
||||
// orderCategoryName: "宠物殡葬",
|
||||
// orderTerminal: 0,
|
||||
// userId: 0,
|
||||
// userName: "",
|
||||
// subTime: 1760585499000, // 预约时间
|
||||
// userNickName: "",
|
||||
// userAvatar: "",
|
||||
// userMobile: "",
|
||||
// orderStatus: 70,
|
||||
// picUrl: "",
|
||||
// spuName: "",
|
||||
// skuName: "",
|
||||
// count: 0,
|
||||
// price: 0,
|
||||
// handedPrice: 0,
|
||||
// payPrice: 0,
|
||||
// unit: "",
|
||||
// orderTime: "",
|
||||
// serveAddress: "",
|
||||
// userRemark: "",
|
||||
// payType: "",
|
||||
// financeStatus: "",
|
||||
// },
|
||||
],
|
||||
total: 0,
|
||||
},
|
||||
@@ -202,70 +232,254 @@ const getOrderPage = (_req: Request, res: Response) => {
|
||||
const getOrderDetail = (_req: Request, res: Response) => {
|
||||
res.json({
|
||||
data: {
|
||||
tradeOrderInfoBase: {
|
||||
id: "7655265",
|
||||
orderNo: "BZ000548787",
|
||||
orderStatus: "50",
|
||||
orderType: "1",
|
||||
orderCategoryName: "宠物殡葬", // 订单类目
|
||||
orderCategoryId: "3232321",
|
||||
orderTerminal: "微信小程序",
|
||||
userInfo: null,
|
||||
userAvatar: null,
|
||||
cancelTime: "2025-10-16T11:28:57",
|
||||
cancelReason: "非常",
|
||||
merchantRemark: "测试商家备注",
|
||||
refundTime: null,
|
||||
propertyTime: null,
|
||||
propertyStatus: null,
|
||||
price: null,
|
||||
discountPrice: null,
|
||||
payPrice: null,
|
||||
refundPrice: null,
|
||||
livePrice: null,
|
||||
payType: "1",
|
||||
payChannelCode: "1",
|
||||
payOrderId: "12323123123",
|
||||
payTime: 1760585391000,
|
||||
createTime: 1760585499000,
|
||||
finishTime: 1760585335000,
|
||||
},
|
||||
tradeProductInfo: {
|
||||
shopLogoUrl: "",
|
||||
shopName: "",
|
||||
spuId: 0,
|
||||
skuId: 0,
|
||||
skuPicUrl: "",
|
||||
spuName: "",
|
||||
skuName: "",
|
||||
count: 0,
|
||||
price: 0,
|
||||
unit: "",
|
||||
handedPrice: 0,
|
||||
expensePrice: 0,
|
||||
properties: [""],
|
||||
serveContent: "",
|
||||
totalPrice: 0,
|
||||
discountPrice: 0,
|
||||
payPrice: 0,
|
||||
refundPrice: 0,
|
||||
refundCount: 0,
|
||||
},
|
||||
id: 1,
|
||||
orderNum: "123333333333",
|
||||
orderType: 1,
|
||||
orderTerminal: 1,
|
||||
orderStatus: 10,
|
||||
userId: 1,
|
||||
userName: "李老师",
|
||||
userNickName: null,
|
||||
userAvatar: null,
|
||||
userMobile: "17609087876",
|
||||
userRemark: "测试用户备注",
|
||||
createTime: "2025-10-16 11:31:39",
|
||||
finishTime: "2025-10-16 11:28:55",
|
||||
orderCategoryId: 1,
|
||||
orderCategoryName: "222",
|
||||
cancelReason: "非常",
|
||||
merchantRemark: "测试商家备注",
|
||||
refundTime: null,
|
||||
propertyTime: null,
|
||||
propertyStatus: null,
|
||||
price: null,
|
||||
payPrice: null,
|
||||
discountPrice: null,
|
||||
refundPrice: null,
|
||||
livePrice: null,
|
||||
payType: 1,
|
||||
payChannelCode: 1,
|
||||
financeStatus: null,
|
||||
payOrderId: "12323123123",
|
||||
payTime: "2025-10-16 11:29:51",
|
||||
cancelTime: "2025-10-16 11:28:57",
|
||||
statusList: [
|
||||
{
|
||||
id: 1,
|
||||
orderId: 1,
|
||||
beforeStatus: 10,
|
||||
afterStatus: 20,
|
||||
operateType: 1,
|
||||
content: "1",
|
||||
createTime: 1760952084000,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
orderId: 1,
|
||||
beforeStatus: 20,
|
||||
afterStatus: 30,
|
||||
operateType: 1,
|
||||
content: "测试内容",
|
||||
createTime: null,
|
||||
},
|
||||
],
|
||||
items: [
|
||||
{
|
||||
id: 1,
|
||||
shopName: "22",
|
||||
shopLogo: null,
|
||||
spuId: 1,
|
||||
skuId: 1,
|
||||
picUrl:
|
||||
"https://inews.gtimg.com/news_bt/OBkbmPLeWLy4IM4oUDGvOIqSDSZ9lYOtW3qSXCYh78KXcAA/1000",
|
||||
spuName: "测试商品名称",
|
||||
skuName: "规格名称",
|
||||
orderCategoryId: 1,
|
||||
orderCategoryName: "222",
|
||||
count: 1,
|
||||
price: 1,
|
||||
unit: "件",
|
||||
totalPrice: 0,
|
||||
discountPrice: 1,
|
||||
payPrice: 1,
|
||||
refundPrice: null,
|
||||
refundCount: null,
|
||||
handedPrice: 0,
|
||||
expensePrice: 1,
|
||||
properties: null,
|
||||
serveContent: null,
|
||||
},
|
||||
],
|
||||
tradeServeInfo: {
|
||||
properties: {
|
||||
"": {},
|
||||
},
|
||||
changeRule: "bbbb",
|
||||
userRemark: "bbbb",
|
||||
subOrder: "bbbb",
|
||||
pickUpAddress: "bbbb",
|
||||
subType: "bbbb",
|
||||
merchantRemark: "bbbb",
|
||||
sendAddress: "bbbb",
|
||||
petName: "aaa",
|
||||
boneUrl: "aaa",
|
||||
petType: "aaa",
|
||||
diedTime: "aaa",
|
||||
weight: "aaa",
|
||||
diedReason: "aaa",
|
||||
},
|
||||
tradeExtendServeInfo: {
|
||||
properties: {
|
||||
"": {},
|
||||
tradeExtendServeInfo: [
|
||||
{
|
||||
refundCount: "ccc",
|
||||
totalPrice: "ccc",
|
||||
payPrice: "ccc",
|
||||
discountPrice: "ccc",
|
||||
refundMoney: "ccc",
|
||||
serve: {
|
||||
serveName: "ccc",
|
||||
serveUrl: "ccc",
|
||||
price: "ccc",
|
||||
serveDesc: "ccc",
|
||||
handPrice: "ccc",
|
||||
count: "ccc",
|
||||
},
|
||||
tempType: 1,
|
||||
},
|
||||
},
|
||||
tradeExtendCostInfo: {
|
||||
properties: {
|
||||
"": {},
|
||||
{
|
||||
refundCount: "ccc",
|
||||
totalPrice: "ccc",
|
||||
payPrice: "ccc",
|
||||
discountPrice: "ccc",
|
||||
refundMoney: "ccc",
|
||||
serve: [
|
||||
{
|
||||
serveName: "ccc",
|
||||
serveUrl: "ccc",
|
||||
price: "ccc",
|
||||
serveDesc: "ccc",
|
||||
handPrice: "ccc",
|
||||
count: "ccc",
|
||||
riteAddress: "ccc",
|
||||
parentActive: "ccc",
|
||||
},
|
||||
],
|
||||
tempType: 2,
|
||||
},
|
||||
},
|
||||
{
|
||||
refundCount: "ccc",
|
||||
deliveryInfo: {
|
||||
address: "收货地址",
|
||||
userMobile: "手机号码",
|
||||
deliveryType: "配送方式",
|
||||
user: "收货人/提货人",
|
||||
},
|
||||
serveTitle: "骨灰处理",
|
||||
totalPrice: "ccc",
|
||||
payPrice: "ccc",
|
||||
serveType: "处理方式",
|
||||
discountPrice: "ccc",
|
||||
refundMoney: "ccc",
|
||||
serve: [
|
||||
{
|
||||
serveName: "ccc",
|
||||
serveUrl: "ccc",
|
||||
price: "ccc",
|
||||
serveDesc: "ccc",
|
||||
handPrice: "ccc",
|
||||
count: "ccc",
|
||||
},
|
||||
{
|
||||
serveName: "ccc",
|
||||
serveUrl: "ccc",
|
||||
price: "ccc",
|
||||
serveDesc: "ccc",
|
||||
handPrice: "ccc",
|
||||
count: "ccc",
|
||||
},
|
||||
],
|
||||
tempType: 3,
|
||||
},
|
||||
{
|
||||
refundCount: "ccc",
|
||||
deliveryInfo: {
|
||||
address: "收货地址",
|
||||
userMobile: "手机号码",
|
||||
deliveryType: "配送方式",
|
||||
user: "收货人/提货人",
|
||||
},
|
||||
totalPrice: "ccc",
|
||||
payPrice: "ccc",
|
||||
discountPrice: "ccc",
|
||||
refundMoney: "ccc",
|
||||
serve: {
|
||||
parentActivity: "ccc",
|
||||
prodUrl: "ccc",
|
||||
price: "ccc",
|
||||
handPrice: "ccc",
|
||||
count: "ccc",
|
||||
prodName: "ccc",
|
||||
prodType: "ccc",
|
||||
prodDesc: "ccc",
|
||||
},
|
||||
tempType: 4,
|
||||
},
|
||||
],
|
||||
tradeExtendCostInfo: [
|
||||
{
|
||||
costDetail: {
|
||||
costName: "超区域服务费",
|
||||
targetArea: "目标区域",
|
||||
chargeType: "收费方式",
|
||||
serveArea: "可服务区域",
|
||||
},
|
||||
serveExtFee: "",
|
||||
refundPrice: "11",
|
||||
payInfo: {
|
||||
totalPrice: "11",
|
||||
payPrice: "333",
|
||||
discountPrice: "222",
|
||||
},
|
||||
},
|
||||
{
|
||||
costDetail: {
|
||||
respMode: "响应模式",
|
||||
respTime: "响应时间",
|
||||
chargeType: "收费方式",
|
||||
},
|
||||
serveExtFee: "",
|
||||
refundPrice: "11",
|
||||
payInfo: {
|
||||
totalPrice: "11",
|
||||
payPrice: "333",
|
||||
discountPrice: "222",
|
||||
},
|
||||
},
|
||||
{
|
||||
costDetail: {
|
||||
costName: "超区域服务费",
|
||||
chargeType: "收费方式",
|
||||
weight: "体型/体重",
|
||||
},
|
||||
serveExtFee: "",
|
||||
refundPrice: "11",
|
||||
payInfo: {
|
||||
totalPrice: "11",
|
||||
payPrice: "333",
|
||||
discountPrice: "222",
|
||||
},
|
||||
},
|
||||
{
|
||||
costDetail: {
|
||||
costName: "超区域服务费",
|
||||
chargeTime: "收费时段",
|
||||
chargeType: "收费方式",
|
||||
},
|
||||
serveExtFee: "",
|
||||
refundPrice: "11",
|
||||
payInfo: {
|
||||
totalPrice: "11",
|
||||
payPrice: "333",
|
||||
discountPrice: "222",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
code: 0,
|
||||
});
|
||||
|
||||
@@ -39,9 +39,13 @@
|
||||
"@ant-design/icons": "^5.6.1",
|
||||
"@ant-design/pro-components": "^2.8.9",
|
||||
"@ant-design/v5-patch-for-react-19": "^1.0.3",
|
||||
"@dnd-kit/core": "^6.3.1",
|
||||
"@dnd-kit/sortable": "^10.0.0",
|
||||
"@dnd-kit/utilities": "^3.2.2",
|
||||
"@tinymce/tinymce-react": "^6.3.0",
|
||||
"antd": "^5.26.4",
|
||||
"antd": "^5.27.3",
|
||||
"antd-style": "^3.7.0",
|
||||
"browser-id3-writer": "^6.3.1",
|
||||
"classnames": "^2.5.1",
|
||||
"dayjs": "^1.11.13",
|
||||
"jsencrypt": "^3.5.4",
|
||||
@@ -49,6 +53,7 @@
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"react-infinite-scroll-component": "^6.1.0",
|
||||
"react-video-thumbnail": "^0.1.3",
|
||||
"tinymce": "^8.1.2",
|
||||
"web-storage-cache": "^1.1.1"
|
||||
},
|
||||
|
||||
40
pnpm-lock.yaml
generated
40
pnpm-lock.yaml
generated
@@ -17,15 +17,27 @@ importers:
|
||||
'@ant-design/v5-patch-for-react-19':
|
||||
specifier: ^1.0.3
|
||||
version: 1.0.3(antd@5.27.3(date-fns@2.30.0)(moment@2.30.1)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@dnd-kit/core':
|
||||
specifier: ^6.3.1
|
||||
version: 6.3.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@dnd-kit/sortable':
|
||||
specifier: ^10.0.0
|
||||
version: 10.0.0(@dnd-kit/core@6.3.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)
|
||||
'@dnd-kit/utilities':
|
||||
specifier: ^3.2.2
|
||||
version: 3.2.2(react@19.1.1)
|
||||
'@tinymce/tinymce-react':
|
||||
specifier: ^6.3.0
|
||||
version: 6.3.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(tinymce@8.1.2)
|
||||
antd:
|
||||
specifier: ^5.26.4
|
||||
specifier: ^5.27.3
|
||||
version: 5.27.3(date-fns@2.30.0)(moment@2.30.1)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
antd-style:
|
||||
specifier: ^3.7.0
|
||||
version: 3.7.1(@types/react@19.1.12)(antd@5.27.3(date-fns@2.30.0)(moment@2.30.1)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
browser-id3-writer:
|
||||
specifier: ^6.3.1
|
||||
version: 6.3.1
|
||||
classnames:
|
||||
specifier: ^2.5.1
|
||||
version: 2.5.1
|
||||
@@ -47,6 +59,9 @@ importers:
|
||||
react-infinite-scroll-component:
|
||||
specifier: ^6.1.0
|
||||
version: 6.1.0(react@19.1.1)
|
||||
react-video-thumbnail:
|
||||
specifier: ^0.1.3
|
||||
version: 0.1.3
|
||||
tinymce:
|
||||
specifier: ^8.1.2
|
||||
version: 8.1.2
|
||||
@@ -1410,6 +1425,12 @@ packages:
|
||||
'@dnd-kit/core': ^6.0.6
|
||||
react: '>=16.8.0'
|
||||
|
||||
'@dnd-kit/sortable@10.0.0':
|
||||
resolution: {integrity: sha512-+xqhmIIzvAYMGfBYYnbKuNicfSsk4RksY2XdmJhT+HAC01nix6fHCztU68jooFiMUB01Ky3F0FyOvhG/BZrWkg==}
|
||||
peerDependencies:
|
||||
'@dnd-kit/core': ^6.3.0
|
||||
react: '>=16.8.0'
|
||||
|
||||
'@dnd-kit/sortable@7.0.2':
|
||||
resolution: {integrity: sha512-wDkBHHf9iCi1veM834Gbk1429bd4lHX4RpAwT0y2cHLf246GAvU2sVw/oxWNpPKQNQRQaeGXhAVgrOl1IT+iyA==}
|
||||
peerDependencies:
|
||||
@@ -3850,6 +3871,9 @@ packages:
|
||||
brorand@1.1.0:
|
||||
resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==}
|
||||
|
||||
browser-id3-writer@6.3.1:
|
||||
resolution: {integrity: sha512-sRA4Uq9Q3NsmXiVpLvIDxzomtgCdbw6SY85A6fw7dUQGRVoOBg1/buFv6spPhYiSo6FlVtN5OJQTvvhbmfx9rQ==}
|
||||
|
||||
browserify-aes@1.2.0:
|
||||
resolution: {integrity: sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==}
|
||||
|
||||
@@ -9148,6 +9172,9 @@ packages:
|
||||
react-tween-state@0.1.5:
|
||||
resolution: {integrity: sha512-sJQpjsdn0wjlDIUpfpb7jQGnOG8hAEW2e8k0KPA+xmf5KFa6Xat2JldbmxBhaqP0S/uIXhVE5ymKyH/b9X8nYA==}
|
||||
|
||||
react-video-thumbnail@0.1.3:
|
||||
resolution: {integrity: sha512-ZakEVv9RNFcziAnHHtwod5tf0yMVv4aLZ8/QsCxt1HTnKRHrlylvolPKv1hr63GCwnPu6tgPjUTDKRqfl30lOQ==}
|
||||
|
||||
react@18.3.1:
|
||||
resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -13394,6 +13421,13 @@ snapshots:
|
||||
react: 19.1.1
|
||||
tslib: 2.8.1
|
||||
|
||||
'@dnd-kit/sortable@10.0.0(@dnd-kit/core@6.3.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)':
|
||||
dependencies:
|
||||
'@dnd-kit/core': 6.3.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@dnd-kit/utilities': 3.2.2(react@19.1.1)
|
||||
react: 19.1.1
|
||||
tslib: 2.8.1
|
||||
|
||||
'@dnd-kit/sortable@7.0.2(@dnd-kit/core@6.3.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)':
|
||||
dependencies:
|
||||
'@dnd-kit/core': 6.3.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
@@ -16921,6 +16955,8 @@ snapshots:
|
||||
|
||||
brorand@1.1.0: {}
|
||||
|
||||
browser-id3-writer@6.3.1: {}
|
||||
|
||||
browserify-aes@1.2.0:
|
||||
dependencies:
|
||||
buffer-xor: 1.0.3
|
||||
@@ -23468,6 +23504,8 @@ snapshots:
|
||||
raf: 3.4.1
|
||||
tween-functions: 1.2.0
|
||||
|
||||
react-video-thumbnail@0.1.3: {}
|
||||
|
||||
react@18.3.1:
|
||||
dependencies:
|
||||
loose-envify: 1.4.0
|
||||
|
||||
100
src/app.tsx
100
src/app.tsx
@@ -1,28 +1,28 @@
|
||||
import type { Settings as LayoutSettings } from "@ant-design/pro-components";
|
||||
import { SettingDrawer } from "@ant-design/pro-components";
|
||||
import type { RequestConfig, RunTimeLayoutConfig } from "@umijs/max";
|
||||
import { history } from "@umijs/max";
|
||||
import type { Settings as LayoutSettings } from '@ant-design/pro-components';
|
||||
import { SettingDrawer } from '@ant-design/pro-components';
|
||||
import type { RequestConfig, RunTimeLayoutConfig } from '@umijs/max';
|
||||
import { history } from '@umijs/max';
|
||||
import {
|
||||
AvatarDropdown,
|
||||
AvatarName,
|
||||
Footer,
|
||||
Question,
|
||||
SelectLang,
|
||||
} from "@/components";
|
||||
import { getInfo } from "@/services/login";
|
||||
import type { UserInfoVO } from "@/services/login/types";
|
||||
import defaultSettings from "../config/defaultSettings";
|
||||
import { errorConfig } from "./requestErrorConfig";
|
||||
import "@ant-design/v5-patch-for-react-19";
|
||||
import { useDictStore } from "@/hooks/stores/dict";
|
||||
import { getAccessToken, getTenantId } from "@/utils/auth";
|
||||
import { CACHE_KEY, useCache } from "./hooks/web/useCache";
|
||||
import type { MenuVO } from "./services/system/menu";
|
||||
import { loopMenuItem } from "./utils/menuUtils";
|
||||
} from '@/components';
|
||||
import { getInfo } from '@/services/login';
|
||||
import type { UserInfoVO } from '@/services/login/types';
|
||||
import defaultSettings from '../config/defaultSettings';
|
||||
import { errorConfig } from './requestErrorConfig';
|
||||
import '@ant-design/v5-patch-for-react-19';
|
||||
import { useDictStore } from '@/hooks/stores/dict';
|
||||
import { getAccessToken, getTenantId } from '@/utils/auth';
|
||||
import { CACHE_KEY, useCache } from './hooks/web/useCache';
|
||||
import type { MenuVO } from './services/system/menu';
|
||||
import { loopMenuItem } from './utils/menuUtils';
|
||||
|
||||
const isDev = process.env.NODE_ENV === "development";
|
||||
const isDev = process.env.NODE_ENV === 'development';
|
||||
const isDevOrTest = isDev || process.env.CI;
|
||||
const loginPath = "/user/login";
|
||||
const loginPath = '/user/login';
|
||||
|
||||
// 标记是否已添加动态路由
|
||||
/**
|
||||
@@ -42,7 +42,7 @@ export async function getInitialState(): Promise<{
|
||||
try {
|
||||
const token = getAccessToken();
|
||||
if (!token) {
|
||||
throw new Error("No token found");
|
||||
throw new Error('No token found');
|
||||
}
|
||||
const data = await getInfo();
|
||||
wsCache.set(CACHE_KEY.USER, data);
|
||||
@@ -64,8 +64,8 @@ export async function getInitialState(): Promise<{
|
||||
const { location } = history;
|
||||
|
||||
if (
|
||||
![loginPath, "/user/register", "/user/register-result"].includes(
|
||||
location.pathname
|
||||
![loginPath, '/user/register', '/user/register-result'].includes(
|
||||
location.pathname,
|
||||
)
|
||||
) {
|
||||
const currentUser = wsCache.get(CACHE_KEY.USER);
|
||||
@@ -122,24 +122,29 @@ export const layout: RunTimeLayoutConfig = ({
|
||||
},
|
||||
bgLayoutImgList: [
|
||||
{
|
||||
src: "https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/D2LWSqNny4sAAAAAAAAAAAAAFl94AQBr",
|
||||
src: 'https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/D2LWSqNny4sAAAAAAAAAAAAAFl94AQBr',
|
||||
left: 85,
|
||||
bottom: 100,
|
||||
height: "303px",
|
||||
height: '303px',
|
||||
},
|
||||
{
|
||||
src: "https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/C2TWRpJpiC0AAAAAAAAAAAAAFl94AQBr",
|
||||
src: 'https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/C2TWRpJpiC0AAAAAAAAAAAAAFl94AQBr',
|
||||
bottom: -68,
|
||||
right: -45,
|
||||
height: "303px",
|
||||
height: '303px',
|
||||
},
|
||||
{
|
||||
src: "https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/F6vSTbj8KpYAAAAAAAAAAAAAFl94AQBr",
|
||||
src: 'https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/F6vSTbj8KpYAAAAAAAAAAAAAFl94AQBr',
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
width: "331px",
|
||||
width: '331px',
|
||||
},
|
||||
],
|
||||
// 面包屑配置
|
||||
breadcrumb: {
|
||||
enable: true,
|
||||
useRoutes: true,
|
||||
},
|
||||
menuHeaderRender: undefined,
|
||||
// 自定义 403 页面
|
||||
unAccessible: <div>unAccessible</div>,
|
||||
@@ -175,57 +180,30 @@ export const layout: RunTimeLayoutConfig = ({
|
||||
* @doc https://umijs.org/docs/max/request#配置
|
||||
*/
|
||||
export const request: RequestConfig = {
|
||||
baseURL: isDev ? "" : "https://proapi.azurewebsites.net",
|
||||
baseURL: isDev ? '' : 'https://proapi.azurewebsites.net',
|
||||
...errorConfig,
|
||||
// 添加请求拦截器
|
||||
requestInterceptors: [
|
||||
(url, options) => {
|
||||
// 为所有请求添加 API 前缀
|
||||
if (url && !url.startsWith(process.env.API_PREFIX || "/admin-api")) {
|
||||
url = (process.env.API_PREFIX || "/admin-api") + url;
|
||||
if (url && !url.startsWith(process.env.API_PREFIX || '/admin-api')) {
|
||||
url = (process.env.API_PREFIX || '/admin-api') + url;
|
||||
}
|
||||
// 获取存储在本地的 token 和 tenantId
|
||||
const token = getAccessToken();
|
||||
const tenantId = getTenantId(); // 默认租户ID为1
|
||||
const contentType: string = options.headers?.["Content-Type"] as string;
|
||||
// 设置统一的请求头
|
||||
const headers: Record<string, string> = {
|
||||
...options.headers,
|
||||
Accept: "*",
|
||||
"tenant-id": tenantId,
|
||||
Accept: '*',
|
||||
'tenant-id': tenantId,
|
||||
};
|
||||
// 如果有token,则添加Authorization头
|
||||
if (token) {
|
||||
headers.Authorization = `Bearer ${getAccessToken()}`;
|
||||
headers["Content-Type"] = contentType || "application/json";
|
||||
}
|
||||
return { url, options: { ...options, headers } };
|
||||
},
|
||||
// requestInterceptors: [
|
||||
// (url, options) => {
|
||||
// // 为所有请求添加 API 前缀
|
||||
// if (url && !url.startsWith(process.env.API_PREFIX || "/admin-api")) {
|
||||
// url = (process.env.API_PREFIX || "/admin-api") + url;
|
||||
// }
|
||||
// // 获取存储在本地的 token 和 tenantId
|
||||
// const token = getAccessToken();
|
||||
// const tenantId = getTenantId(); // 默认租户ID为1
|
||||
// console.log("request", options);
|
||||
// // 设置统一的请求头
|
||||
// const contentType: string = options.headers?.["Content-Type"] as string;
|
||||
// const headers: Record<string, string> = {
|
||||
// ...options.headers,
|
||||
// Accept: "*",
|
||||
// "Content-Type": contentType || "application/json",
|
||||
// "tenant-id": tenantId,
|
||||
// };
|
||||
// // 如果有token,则添加Authorization头
|
||||
// if (token) {
|
||||
// headers.Authorization = `Bearer ${getAccessToken()}`;
|
||||
// }
|
||||
// console.log("headers", headers);
|
||||
// return { url, options: { ...options, ...headers } };
|
||||
// },
|
||||
],
|
||||
|
||||
// 添加参数序列化配置
|
||||
@@ -234,7 +212,7 @@ export const request: RequestConfig = {
|
||||
const appendParams = (key: string, value: any) => {
|
||||
if (Array.isArray(value)) {
|
||||
// 特殊处理 createTime 数组,转换为 createTime[0] 和 createTime[1] 格式
|
||||
if (key === "createTime") {
|
||||
if (key === 'createTime') {
|
||||
value.forEach((val, index) => {
|
||||
searchParams.append(`${key}[${index}]`, val);
|
||||
});
|
||||
@@ -272,7 +250,7 @@ export async function patchClientRoutes({ routes }: any) {
|
||||
wsCache.set(CACHE_KEY.ROLE_ROUTERS, data.menus);
|
||||
menus = data.menus;
|
||||
} catch (error) {
|
||||
console.error("获取菜单失败:", error);
|
||||
console.error('获取菜单失败:', error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -280,7 +258,7 @@ export async function patchClientRoutes({ routes }: any) {
|
||||
if (!menus || menus.length === 0) {
|
||||
return;
|
||||
}
|
||||
const routerIndex = routes.findIndex((item: any) => item.path === "/");
|
||||
const routerIndex = routes.findIndex((item: any) => item.path === '/');
|
||||
const parentId = routes[routerIndex].id;
|
||||
|
||||
if (menus) {
|
||||
|
||||
61
src/components/Draggable/DragOverlayTag/index.less
Normal file
61
src/components/Draggable/DragOverlayTag/index.less
Normal file
@@ -0,0 +1,61 @@
|
||||
.drag-overlay-tag {
|
||||
cursor: grabbing;
|
||||
|
||||
.overlay-tag {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 8px 12px;
|
||||
font-size: 14px;
|
||||
user-select: none;
|
||||
border-radius: 6px;
|
||||
background: #fff;
|
||||
border: 2px solid #1890ff;
|
||||
box-shadow: 0 8px 24px rgba(24, 144, 255, 0.4);
|
||||
|
||||
.tag-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
|
||||
.drag-handle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #1890ff;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.tag-label {
|
||||
font-weight: 600;
|
||||
color: #262626;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
|
||||
.sort-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 20px;
|
||||
height: 20px;
|
||||
padding: 0 6px;
|
||||
background: #1890ff;
|
||||
color: #fff;
|
||||
border-radius: 10px;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes float {
|
||||
0% {
|
||||
transform: scale(1);
|
||||
opacity: 0.8;
|
||||
}
|
||||
100% {
|
||||
transform: scale(1.1);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
30
src/components/Draggable/DragOverlayTag/index.tsx
Normal file
30
src/components/Draggable/DragOverlayTag/index.tsx
Normal file
@@ -0,0 +1,30 @@
|
||||
import { DragOutlined } from '@ant-design/icons';
|
||||
import { Tag } from 'antd';
|
||||
import React, { memo } from 'react';
|
||||
import type { TagItem } from '../types';
|
||||
import './index.less';
|
||||
|
||||
interface DragOverlayTagProps {
|
||||
tag: TagItem;
|
||||
}
|
||||
|
||||
const DragOverlayTag: React.FC<DragOverlayTagProps> = memo(({ tag }) => {
|
||||
return (
|
||||
<div className="drag-overlay-tag">
|
||||
<Tag className="overlay-tag">
|
||||
<div className="tag-content">
|
||||
<span className="drag-handle">
|
||||
<DragOutlined />
|
||||
</span>
|
||||
<span className="tag-label">
|
||||
{tag.label}
|
||||
<span className="sort-badge">{tag.sort}</span>
|
||||
</span>
|
||||
</div>
|
||||
</Tag>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
DragOverlayTag.displayName = 'DragOverlayTag';
|
||||
export default DragOverlayTag;
|
||||
179
src/components/Draggable/DraggableTagList/index.less
Normal file
179
src/components/Draggable/DraggableTagList/index.less
Normal file
@@ -0,0 +1,179 @@
|
||||
.draggable-tag-list {
|
||||
padding: 24px;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
|
||||
.tag-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
padding: 20px;
|
||||
background: #fafafa;
|
||||
border-radius: 6px;
|
||||
min-height: 120px;
|
||||
border: 2px dashed #d9d9d9;
|
||||
transition: border-color 0.3s;
|
||||
|
||||
&:hover {
|
||||
border-color: #40a9ff;
|
||||
}
|
||||
}
|
||||
|
||||
.sortable-tag {
|
||||
display: inline-block;
|
||||
// 使用 will-change 优化动画性能
|
||||
will-change: opacity, transform;
|
||||
|
||||
// 拖拽中的标签 - 原位置透明度降低
|
||||
&.active {
|
||||
opacity: 0.3;
|
||||
transition: opacity 0.2s ease;
|
||||
|
||||
.custom-tag {
|
||||
border-color: #1890ff;
|
||||
background: #e6f7ff;
|
||||
}
|
||||
}
|
||||
|
||||
// 经过的目标标签 - 高亮显示
|
||||
&.over {
|
||||
.custom-tag {
|
||||
border-color: #52c41a;
|
||||
background: #f6ffed;
|
||||
box-shadow: 0 0 0 4px rgba(82, 196, 26, 0.2);
|
||||
transform: scale(1.08);
|
||||
// 使用 transform 而不是复杂动画
|
||||
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// 禁用状态
|
||||
&.disabled {
|
||||
.custom-tag {
|
||||
background: #f5f5f5;
|
||||
border-color: #d9d9d9;
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
cursor: not-allowed;
|
||||
|
||||
.drag-handle {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.custom-tag {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 8px 12px;
|
||||
font-size: 14px;
|
||||
user-select: none;
|
||||
border-radius: 6px;
|
||||
// 优化过渡效果
|
||||
transition: border-color 0.2s ease, box-shadow 0.2s ease;
|
||||
background: #fff;
|
||||
border: 2px solid #d9d9d9;
|
||||
// 使用 GPU 加速
|
||||
transform: translateZ(0);
|
||||
|
||||
&:hover:not(.disabled) {
|
||||
border-color: #40a9ff;
|
||||
box-shadow: 0 2px 8px rgba(24, 144, 255, 0.15);
|
||||
}
|
||||
|
||||
.tag-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
|
||||
.drag-handle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: grab;
|
||||
color: #8c8c8c;
|
||||
transition: color 0.2s;
|
||||
font-size: 16px;
|
||||
|
||||
&:hover {
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
&:active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
}
|
||||
|
||||
.tag-label {
|
||||
flex: 1;
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
|
||||
.sort-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 20px;
|
||||
height: 20px;
|
||||
padding: 0 6px;
|
||||
background: #1890ff;
|
||||
color: #fff;
|
||||
border-radius: 10px;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.edit-icon {
|
||||
cursor: pointer;
|
||||
color: #8c8c8c;
|
||||
transition: color 0.2s;
|
||||
font-size: 14px;
|
||||
|
||||
&:hover {
|
||||
color: #1890ff;
|
||||
}
|
||||
}
|
||||
|
||||
.disabled-badge {
|
||||
padding: 2px 8px;
|
||||
background: #ff4d4f;
|
||||
color: #fff;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
margin-left: 4px;
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sort-info {
|
||||
padding: 16px;
|
||||
background: #f0f2f5;
|
||||
border-radius: 6px;
|
||||
border: 1px solid #d9d9d9;
|
||||
|
||||
h4 {
|
||||
margin: 0 0 12px 0;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #262626;
|
||||
}
|
||||
|
||||
.sort-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
|
||||
.sort-item {
|
||||
padding: 4px 12px;
|
||||
background: #fff;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 4px;
|
||||
font-size: 13px;
|
||||
color: #595959;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
318
src/components/Draggable/DraggableTagList/index.tsx
Normal file
318
src/components/Draggable/DraggableTagList/index.tsx
Normal file
@@ -0,0 +1,318 @@
|
||||
import { PlusOutlined } from '@ant-design/icons';
|
||||
import {
|
||||
DndContext,
|
||||
type DragEndEvent,
|
||||
type DragOverEvent,
|
||||
DragOverlay,
|
||||
type DragStartEvent,
|
||||
PointerSensor,
|
||||
useSensor,
|
||||
useSensors,
|
||||
} from '@dnd-kit/core';
|
||||
import { rectSortingStrategy, SortableContext } from '@dnd-kit/sortable';
|
||||
import { Button, Form, Input, Modal, message, Space, Switch } from 'antd';
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
import DragOverlayTag from '../DragOverlayTag';
|
||||
import { SortableTag } from '../SortableTag';
|
||||
import type { TagItem } from '../types';
|
||||
import './index.less';
|
||||
|
||||
const DraggableTagList: React.FC = () => {
|
||||
const [tags, setTags] = useState<TagItem[]>([
|
||||
{ id: '1', label: '标签1', disabled: false, sort: 1 },
|
||||
{ id: '2', label: '标签2', disabled: false, sort: 2 },
|
||||
{ id: '3', label: '标签3', disabled: true, sort: 3 },
|
||||
{ id: '4', label: '标签4', disabled: false, sort: 4 },
|
||||
{ id: '5', label: '标签5', disabled: false, sort: 5 },
|
||||
]);
|
||||
|
||||
const [isModalVisible, setIsModalVisible] = useState(false);
|
||||
const [editingTag, setEditingTag] = useState<TagItem | null>(null);
|
||||
const [activeId, setActiveId] = useState<string | null>(null);
|
||||
const [overId, setOverId] = useState<string | null>(null);
|
||||
const [form] = Form.useForm();
|
||||
|
||||
// 优化传感器配置
|
||||
const sensors = useSensors(
|
||||
useSensor(PointerSensor, {
|
||||
activationConstraint: {
|
||||
distance: 8,
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
// 创建标签映射,避免重复查找
|
||||
const tagMap = useMemo(() => {
|
||||
const map = new Map<string, TagItem>();
|
||||
tags.forEach((tag) => {
|
||||
map.set(tag.id, tag);
|
||||
});
|
||||
return map;
|
||||
}, [tags]);
|
||||
|
||||
// 拖拽开始 - 使用 useCallback 避免重复创建
|
||||
const handleDragStart = useCallback(
|
||||
(event: DragStartEvent) => {
|
||||
const { active } = event;
|
||||
const activeTag = tagMap.get(active.id as string);
|
||||
|
||||
if (activeTag?.disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
setActiveId(active.id as string);
|
||||
},
|
||||
[tagMap],
|
||||
);
|
||||
|
||||
// 拖拽取消
|
||||
const handleDragCancel = useCallback(() => {
|
||||
setActiveId(null);
|
||||
setOverId(null);
|
||||
}, []);
|
||||
|
||||
// 优化拖拽经过 - 减少不必要的状态更新
|
||||
const handleDragOver = useCallback(
|
||||
(event: DragOverEvent) => {
|
||||
const { over, active } = event;
|
||||
|
||||
// 如果没有 over 或 active,清除 overId
|
||||
if (!over || !active) {
|
||||
if (overId !== null) {
|
||||
setOverId(null);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const newOverId = over.id as string;
|
||||
|
||||
// 如果 overId 没有变化,不更新状态
|
||||
if (newOverId === overId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const activeTag = tagMap.get(active.id as string);
|
||||
const overTag = tagMap.get(newOverId);
|
||||
|
||||
// 检查是否可以高亮
|
||||
if (
|
||||
!activeTag ||
|
||||
activeTag.disabled ||
|
||||
!overTag ||
|
||||
overTag.disabled ||
|
||||
newOverId === active.id
|
||||
) {
|
||||
if (overId !== null) {
|
||||
setOverId(null);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
setOverId(newOverId);
|
||||
},
|
||||
[overId, tagMap],
|
||||
);
|
||||
|
||||
// 拖拽结束 - 使用 useCallback
|
||||
const handleDragEnd = useCallback((event: DragEndEvent) => {
|
||||
const { active, over } = event;
|
||||
|
||||
setActiveId(null);
|
||||
setOverId(null);
|
||||
|
||||
if (!over || active.id === over.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
setTags((items) => {
|
||||
const activeIndex = items.findIndex((item) => item.id === active.id);
|
||||
const overIndex = items.findIndex((item) => item.id === over.id);
|
||||
|
||||
if (activeIndex === -1 || overIndex === -1) {
|
||||
return items;
|
||||
}
|
||||
|
||||
if (items[activeIndex].disabled) {
|
||||
message.warning('禁用的标签不可拖拽');
|
||||
return items;
|
||||
}
|
||||
|
||||
if (items[overIndex].disabled) {
|
||||
message.warning('不能与禁用的标签交换位置');
|
||||
return items;
|
||||
}
|
||||
|
||||
const newItems = [...items];
|
||||
|
||||
// 交换sort值
|
||||
const tempSort = newItems[activeIndex].sort;
|
||||
newItems[activeIndex] = {
|
||||
...newItems[activeIndex],
|
||||
sort: newItems[overIndex].sort,
|
||||
};
|
||||
newItems[overIndex] = {
|
||||
...newItems[overIndex],
|
||||
sort: tempSort,
|
||||
};
|
||||
|
||||
// 交换位置
|
||||
[newItems[activeIndex], newItems[overIndex]] = [
|
||||
newItems[overIndex],
|
||||
newItems[activeIndex],
|
||||
];
|
||||
|
||||
message.success('交换成功');
|
||||
return newItems;
|
||||
});
|
||||
}, []);
|
||||
|
||||
// 添加标签
|
||||
const handleAddTag = useCallback(() => {
|
||||
setEditingTag(null);
|
||||
form.resetFields();
|
||||
setIsModalVisible(true);
|
||||
}, [form]);
|
||||
|
||||
// 编辑标签
|
||||
const handleEditTag = useCallback(
|
||||
(tag: TagItem) => {
|
||||
setEditingTag(tag);
|
||||
form.setFieldsValue(tag);
|
||||
setIsModalVisible(true);
|
||||
},
|
||||
[form],
|
||||
);
|
||||
|
||||
// 删除标签
|
||||
const handleDeleteTag = useCallback((id: string) => {
|
||||
setTags((prevTags) => prevTags.filter((tag) => tag.id !== id));
|
||||
message.success('删除成功');
|
||||
}, []);
|
||||
|
||||
// 保存标签
|
||||
const handleSaveTag = useCallback(async () => {
|
||||
try {
|
||||
const values = await form.validateFields();
|
||||
|
||||
if (editingTag) {
|
||||
setTags((prevTags) =>
|
||||
prevTags.map((tag) =>
|
||||
tag.id === editingTag.id ? { ...tag, ...values } : tag,
|
||||
),
|
||||
);
|
||||
message.success('编辑成功');
|
||||
} else {
|
||||
setTags((prevTags) => {
|
||||
const maxSort = Math.max(...prevTags.map((t) => t.sort), 0);
|
||||
const newTag: TagItem = {
|
||||
id: Date.now().toString(),
|
||||
disabled: false,
|
||||
sort: maxSort + 1,
|
||||
...values,
|
||||
};
|
||||
return [...prevTags, newTag];
|
||||
});
|
||||
message.success('添加成功');
|
||||
}
|
||||
|
||||
setIsModalVisible(false);
|
||||
form.resetFields();
|
||||
} catch (error) {
|
||||
console.error('验证失败:', error);
|
||||
}
|
||||
}, [editingTag, form]);
|
||||
|
||||
// 获取当前拖拽的标签
|
||||
const activeTag = useMemo(
|
||||
() => (activeId ? tagMap.get(activeId) : null),
|
||||
[activeId, tagMap],
|
||||
);
|
||||
|
||||
// 生成 sortable items
|
||||
const sortableItems = useMemo(() => tags.map((tag) => tag.id), [tags]);
|
||||
|
||||
return (
|
||||
<div className="draggable-tag-list">
|
||||
<Space direction="vertical" style={{ width: '100%' }} size="large">
|
||||
<Button type="dashed" icon={<PlusOutlined />} onClick={handleAddTag}>
|
||||
添加标签
|
||||
</Button>
|
||||
|
||||
<DndContext
|
||||
sensors={sensors}
|
||||
onDragStart={handleDragStart}
|
||||
onDragOver={handleDragOver}
|
||||
onDragEnd={handleDragEnd}
|
||||
onDragCancel={handleDragCancel}
|
||||
>
|
||||
<SortableContext items={sortableItems} strategy={rectSortingStrategy}>
|
||||
<div className="tag-container">
|
||||
{tags.map((tag) => (
|
||||
<SortableTag
|
||||
key={tag.id}
|
||||
tag={tag}
|
||||
isActive={activeId === tag.id}
|
||||
isOver={overId === tag.id}
|
||||
onEdit={handleEditTag}
|
||||
onDelete={handleDeleteTag}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</SortableContext>
|
||||
|
||||
<DragOverlay dropAnimation={null}>
|
||||
{activeTag ? <DragOverlayTag tag={activeTag} /> : null}
|
||||
</DragOverlay>
|
||||
</DndContext>
|
||||
|
||||
<div className="sort-info">
|
||||
<h4>当前排序:</h4>
|
||||
<div className="sort-list">
|
||||
{tags.map((tag) => (
|
||||
<span key={tag.id} className="sort-item">
|
||||
{tag.label} (sort: {tag.sort})
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</Space>
|
||||
|
||||
<Modal
|
||||
title={editingTag ? '编辑标签' : '添加标签'}
|
||||
open={isModalVisible}
|
||||
onOk={handleSaveTag}
|
||||
onCancel={() => {
|
||||
setIsModalVisible(false);
|
||||
form.resetFields();
|
||||
}}
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
>
|
||||
<Form form={form} layout="vertical">
|
||||
<Form.Item
|
||||
name="label"
|
||||
label="标签名称"
|
||||
rules={[
|
||||
{ required: true, message: '请输入标签名称' },
|
||||
{ max: 20, message: '标签名称不能超过20个字符' },
|
||||
]}
|
||||
>
|
||||
<Input placeholder="请输入标签名称" maxLength={20} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="disabled"
|
||||
label="禁用状态"
|
||||
valuePropName="checked"
|
||||
initialValue={false}
|
||||
tooltip="禁用后的标签不可拖拽、不可删除、不可作为交换目标"
|
||||
>
|
||||
<Switch checkedChildren="禁用" unCheckedChildren="启用" />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DraggableTagList;
|
||||
86
src/components/Draggable/SortableTag/index.tsx
Normal file
86
src/components/Draggable/SortableTag/index.tsx
Normal file
@@ -0,0 +1,86 @@
|
||||
import { DragOutlined, EditOutlined } from '@ant-design/icons';
|
||||
import { useSortable } from '@dnd-kit/sortable';
|
||||
import { Tag } from 'antd';
|
||||
import React, { memo } from 'react';
|
||||
import type { TagItem } from '../types';
|
||||
|
||||
interface SortableTagProps {
|
||||
tag: TagItem;
|
||||
isActive: boolean;
|
||||
isOver: boolean;
|
||||
onEdit: (tag: TagItem) => void;
|
||||
onDelete: (id: string) => void;
|
||||
}
|
||||
|
||||
export const SortableTag: React.FC<SortableTagProps> = memo(
|
||||
({ tag, isActive, isOver, onEdit, onDelete }) => {
|
||||
const { attributes, listeners, setNodeRef } = useSortable({
|
||||
id: tag.id,
|
||||
disabled: tag.disabled,
|
||||
});
|
||||
|
||||
// 计算样式类名
|
||||
const className = [
|
||||
'sortable-tag',
|
||||
tag.disabled && 'disabled',
|
||||
isActive && 'active',
|
||||
isOver && !tag.disabled && 'over',
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(' ');
|
||||
|
||||
// 处理删除
|
||||
const handleDelete = (e: React.MouseEvent) => {
|
||||
e.preventDefault();
|
||||
if (!tag.disabled) {
|
||||
onDelete(tag.id);
|
||||
}
|
||||
};
|
||||
|
||||
// 处理编辑
|
||||
const handleEdit = (e: React.MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
onEdit(tag);
|
||||
};
|
||||
|
||||
return (
|
||||
<div ref={setNodeRef} className={className}>
|
||||
<Tag
|
||||
className="custom-tag"
|
||||
closable={!tag.disabled}
|
||||
onClose={handleDelete}
|
||||
>
|
||||
<div className="tag-content">
|
||||
{!tag.disabled && (
|
||||
<span className="drag-handle" {...attributes} {...listeners}>
|
||||
<DragOutlined />
|
||||
</span>
|
||||
)}
|
||||
|
||||
<span className="tag-label">
|
||||
{tag.label}
|
||||
<span className="sort-badge">{tag.sort}</span>
|
||||
</span>
|
||||
|
||||
<EditOutlined className="edit-icon" onClick={handleEdit} />
|
||||
|
||||
{tag.disabled && <span className="disabled-badge">禁用</span>}
|
||||
</div>
|
||||
</Tag>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
// 自定义比较函数,只在必要时重新渲染
|
||||
(prevProps, nextProps) => {
|
||||
return (
|
||||
prevProps.tag.id === nextProps.tag.id &&
|
||||
prevProps.tag.label === nextProps.tag.label &&
|
||||
prevProps.tag.disabled === nextProps.tag.disabled &&
|
||||
prevProps.tag.sort === nextProps.tag.sort &&
|
||||
prevProps.isActive === nextProps.isActive &&
|
||||
prevProps.isOver === nextProps.isOver
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
SortableTag.displayName = 'SortableTag';
|
||||
8
src/components/Draggable/types.ts
Normal file
8
src/components/Draggable/types.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
export interface TagItem {
|
||||
id: string;
|
||||
label: string;
|
||||
disabled?: boolean;
|
||||
sort: number; // 添加排序字段
|
||||
isExpire?: number; // 是否失效是否失效0否1是
|
||||
state?: number; // 状态 0正常1禁用
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
import type { ProFormColumnsType } from "@ant-design/pro-components";
|
||||
import { BetaSchemaForm } from "@ant-design/pro-components";
|
||||
import { Button, type ColProps, Drawer, Space } from "antd";
|
||||
import type { FormInstance } from "antd/lib";
|
||||
import type { ProFormColumnsType } from '@ant-design/pro-components';
|
||||
import { BetaSchemaForm } from '@ant-design/pro-components';
|
||||
import { Button, type ColProps, Drawer, Space } from 'antd';
|
||||
import type { FormInstance } from 'antd/lib';
|
||||
import React, {
|
||||
Children,
|
||||
cloneElement,
|
||||
forwardRef,
|
||||
useImperativeHandle,
|
||||
} from "react";
|
||||
} from 'react';
|
||||
|
||||
interface ConfigurableDrawerFormProps {
|
||||
title?: string;
|
||||
@@ -33,18 +33,18 @@ const ConfigurableDrawerForm = forwardRef<
|
||||
>(
|
||||
(
|
||||
{
|
||||
title = "表单",
|
||||
labelCol = { span: 4 },
|
||||
wrapperCol = { span: 20 },
|
||||
title = '表单',
|
||||
labelCol = { span: 3 },
|
||||
wrapperCol = { span: 21 },
|
||||
columns,
|
||||
onSubmit,
|
||||
initialValues,
|
||||
width = 600,
|
||||
width = 700,
|
||||
footer,
|
||||
children,
|
||||
bodyStyle = {},
|
||||
},
|
||||
ref
|
||||
ref,
|
||||
) => {
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const [formData, setFormData] = React.useState(initialValues || {});
|
||||
@@ -56,7 +56,7 @@ const ConfigurableDrawerForm = forwardRef<
|
||||
if (data) {
|
||||
setFormData(data);
|
||||
}
|
||||
console.log("open");
|
||||
console.log('open');
|
||||
setOpen(true);
|
||||
},
|
||||
close: () => setOpen(false),
|
||||
@@ -66,7 +66,8 @@ const ConfigurableDrawerForm = forwardRef<
|
||||
if (React.isValidElement(child)) {
|
||||
// 使用更安全的方式传递属性,避免 TypeScript 错误
|
||||
return cloneElement(child, {
|
||||
...formData,
|
||||
data: formData,
|
||||
formRef,
|
||||
} as any);
|
||||
}
|
||||
return child;
|
||||
@@ -96,12 +97,12 @@ const ConfigurableDrawerForm = forwardRef<
|
||||
title={title}
|
||||
styles={{
|
||||
header: {
|
||||
textAlign: "left",
|
||||
position: "relative",
|
||||
textAlign: 'left',
|
||||
position: 'relative',
|
||||
},
|
||||
body: {
|
||||
background: "var(--ant-background-color)",
|
||||
padding: "var(--ant-padding-lg)",
|
||||
background: 'var(--ant-background-color)',
|
||||
padding: 'var(--ant-padding-lg)',
|
||||
...bodyStyle,
|
||||
},
|
||||
}}
|
||||
@@ -111,7 +112,7 @@ const ConfigurableDrawerForm = forwardRef<
|
||||
onClose={() => setOpen(false)}
|
||||
width={width}
|
||||
footer={
|
||||
<Space style={{ width: "100%", justifyContent: "end" }}>
|
||||
<Space style={{ width: '100%', justifyContent: 'end' }}>
|
||||
{footer ? (
|
||||
footer
|
||||
) : (
|
||||
@@ -142,7 +143,7 @@ const ConfigurableDrawerForm = forwardRef<
|
||||
)}
|
||||
</Drawer>
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
export default ConfigurableDrawerForm;
|
||||
|
||||
67
src/components/ModalCom/ConfirmModal.tsx
Normal file
67
src/components/ModalCom/ConfirmModal.tsx
Normal file
@@ -0,0 +1,67 @@
|
||||
import { Button, Modal, Space } from 'antd';
|
||||
import React, { createContext } from 'react';
|
||||
|
||||
const ReachableContext = createContext<string | null>(null);
|
||||
const UnreachableContext = createContext<string | null>(null);
|
||||
|
||||
const config = {
|
||||
title: 'Use Hook!',
|
||||
content: (
|
||||
<>
|
||||
<ReachableContext.Consumer>
|
||||
{(name) => `Reachable: ${name}!`}
|
||||
</ReachableContext.Consumer>
|
||||
<br />
|
||||
<UnreachableContext.Consumer>
|
||||
{(name) => `Unreachable: ${name}!`}
|
||||
</UnreachableContext.Consumer>
|
||||
</>
|
||||
),
|
||||
};
|
||||
|
||||
const ConfirmModal: React.FC = () => {
|
||||
const [modal, contextHolder] = Modal.useModal();
|
||||
|
||||
return (
|
||||
<ReachableContext.Provider value="Light">
|
||||
<Space>
|
||||
<Button
|
||||
onClick={async () => {
|
||||
const confirmed = await modal.confirm(config);
|
||||
console.log('Confirmed: ', confirmed);
|
||||
}}
|
||||
>
|
||||
Confirm
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
modal.warning(config);
|
||||
}}
|
||||
>
|
||||
Warning
|
||||
</Button>
|
||||
<Button
|
||||
onClick={async () => {
|
||||
modal.info(config);
|
||||
}}
|
||||
>
|
||||
Info
|
||||
</Button>
|
||||
<Button
|
||||
onClick={async () => {
|
||||
modal.error(config);
|
||||
}}
|
||||
>
|
||||
Error
|
||||
</Button>
|
||||
</Space>
|
||||
{/* `contextHolder` should always be placed under the context you want to access */}
|
||||
{contextHolder}
|
||||
|
||||
{/* Can not access this context since `contextHolder` is not in it */}
|
||||
<UnreachableContext.Provider value="Bamboo" />
|
||||
</ReachableContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export default ConfirmModal;
|
||||
@@ -64,7 +64,7 @@ const TagEditor: React.FC<TagEditorProps> = ({
|
||||
const canAddMore = !maxCount || tags.length < maxCount;
|
||||
|
||||
return (
|
||||
<Space wrap>
|
||||
<Space wrap style={{ width: '100%' }}>
|
||||
{tags.map((tag) => (
|
||||
<Tag
|
||||
key={tag}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { uploadImage } from "@/services/infra/media";
|
||||
import { Editor } from "@tinymce/tinymce-react";
|
||||
import { message } from "antd";
|
||||
import React, { useCallback, useState } from "react";
|
||||
import type { Editor as TinyMCEEditor } from "tinymce";
|
||||
import { Editor } from '@tinymce/tinymce-react';
|
||||
import { message } from 'antd';
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import type { Editor as TinyMCEEditor } from 'tinymce';
|
||||
import { uploadImage } from '@/services/infra/media';
|
||||
export interface RichEditorProps {
|
||||
value?: string;
|
||||
onChange?: (content: string) => void;
|
||||
@@ -22,7 +22,7 @@ export interface RichEditorProps {
|
||||
|
||||
console.log(VITE_BASE_URL);
|
||||
const RichEditor: React.FC<RichEditorProps> = ({
|
||||
value = "",
|
||||
value = '',
|
||||
onChange,
|
||||
// height = 400,
|
||||
// placeholder = "请输入内容...",
|
||||
@@ -31,7 +31,7 @@ const RichEditor: React.FC<RichEditorProps> = ({
|
||||
// maxWords,
|
||||
uploadConfig = {
|
||||
maxSize: 5,
|
||||
acceptTypes: ["image/jpeg", "image/png", "image/gif", "image/webp"],
|
||||
acceptTypes: ['image/jpeg', 'image/png', 'image/gif', 'image/webp'],
|
||||
},
|
||||
}) => {
|
||||
const [uploading, setUploading] = useState<boolean>(false);
|
||||
@@ -39,13 +39,13 @@ const RichEditor: React.FC<RichEditorProps> = ({
|
||||
async (file: File): Promise<string> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const formData = new FormData();
|
||||
formData.append("file", file);
|
||||
formData.append('file', file);
|
||||
try {
|
||||
uploadImage(formData).then((res) => {
|
||||
if (res) {
|
||||
resolve(res);
|
||||
} else {
|
||||
reject(new Error("上传失败:未返回有效的URL"));
|
||||
reject(new Error('上传失败:未返回有效的URL'));
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
@@ -53,7 +53,7 @@ const RichEditor: React.FC<RichEditorProps> = ({
|
||||
}
|
||||
});
|
||||
},
|
||||
[uploadConfig]
|
||||
[uploadConfig],
|
||||
);
|
||||
const handleImageUpload = useCallback(
|
||||
(blobInfo: any, _: (percent: number) => void): Promise<string> => {
|
||||
@@ -65,23 +65,23 @@ const RichEditor: React.FC<RichEditorProps> = ({
|
||||
resolve(url);
|
||||
});
|
||||
|
||||
message.success("图片上传成功");
|
||||
message.success('图片上传成功');
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
message.error(typeof error === "string" ? error : "上传失败");
|
||||
message.error(typeof error === 'string' ? error : '上传失败');
|
||||
} finally {
|
||||
setUploading(false);
|
||||
}
|
||||
});
|
||||
},
|
||||
[uploadFile]
|
||||
[uploadFile],
|
||||
);
|
||||
|
||||
const handleCustomUpload = useCallback(
|
||||
(editor: TinyMCEEditor) => {
|
||||
const input = document.createElement("input");
|
||||
input.type = "file";
|
||||
input.accept = uploadConfig.acceptTypes?.join(",") || "image/*";
|
||||
const input = document.createElement('input');
|
||||
input.type = 'file';
|
||||
input.accept = uploadConfig.acceptTypes?.join(',') || 'image/*';
|
||||
input.multiple = true;
|
||||
|
||||
const handleFileChange = async (event: Event) => {
|
||||
@@ -104,7 +104,7 @@ const RichEditor: React.FC<RichEditorProps> = ({
|
||||
file.size / 1024 / 1024 < (uploadConfig.maxSize || 5);
|
||||
if (!isValidSize) {
|
||||
message.error(
|
||||
`文件 ${file.name} 大小超过 ${uploadConfig.maxSize || 5}MB`
|
||||
`文件 ${file.name} 大小超过 ${uploadConfig.maxSize || 5}MB`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
@@ -123,10 +123,10 @@ const RichEditor: React.FC<RichEditorProps> = ({
|
||||
}
|
||||
};
|
||||
|
||||
input.addEventListener("change", handleFileChange);
|
||||
input.addEventListener('change', handleFileChange);
|
||||
input.click();
|
||||
},
|
||||
[uploadConfig, uploadFile]
|
||||
[uploadConfig, uploadFile],
|
||||
);
|
||||
|
||||
const handleEditorChange = (content: string) => {
|
||||
@@ -143,18 +143,18 @@ const RichEditor: React.FC<RichEditorProps> = ({
|
||||
init={{
|
||||
plugins: [
|
||||
// Core editing features
|
||||
"anchor",
|
||||
"autolink",
|
||||
"charmap",
|
||||
"codesample",
|
||||
"emoticons",
|
||||
"link",
|
||||
"lists",
|
||||
"media",
|
||||
"searchreplace",
|
||||
"table",
|
||||
"visualblocks",
|
||||
"wordcount",
|
||||
'anchor',
|
||||
'autolink',
|
||||
'charmap',
|
||||
'codesample',
|
||||
'emoticons',
|
||||
'link',
|
||||
'lists',
|
||||
'media',
|
||||
'searchreplace',
|
||||
'table',
|
||||
'visualblocks',
|
||||
'wordcount',
|
||||
// Your account includes a free trial of TinyMCE premium features
|
||||
// Try the most popular premium features until Oct 8, 2025:
|
||||
// "checklist",
|
||||
@@ -187,44 +187,42 @@ const RichEditor: React.FC<RichEditorProps> = ({
|
||||
|
||||
menubar: false,
|
||||
toolbar:
|
||||
"undo redo | blocks | bold italic forecolor " +
|
||||
"alignleft aligncenter | " +
|
||||
"alignright alignjustify | bullist numlist outdent indent customupload | " +
|
||||
"removeformat ",
|
||||
tinycomments_mode: "embedded",
|
||||
tinycomments_author: "Author name",
|
||||
toolbar_mode: "wrap" as const, // 改为 wrap 模式,全部展开
|
||||
'undo redo | blocks | bold italic forecolor ' +
|
||||
'alignleft aligncenter | ' +
|
||||
'alignright alignjustify | bullist numlist outdent indent customupload | ' +
|
||||
'removeformat ',
|
||||
tinycomments_mode: 'embedded',
|
||||
tinycomments_author: 'Author name',
|
||||
toolbar_mode: 'wrap' as const, // 改为 wrap 模式,全部展开
|
||||
// toolbar_mode: "sliding",
|
||||
mergetags_list: [
|
||||
{ value: "First.Name", title: "First Name" },
|
||||
{ value: "Email", title: "Email" },
|
||||
{ value: 'First.Name', title: 'First Name' },
|
||||
{ value: 'Email', title: 'Email' },
|
||||
],
|
||||
ai_request: (
|
||||
_: any,
|
||||
respondWith: { string: (arg0: () => Promise<never>) => any }
|
||||
respondWith: { string: (arg0: () => Promise<never>) => any },
|
||||
) =>
|
||||
respondWith.string(() =>
|
||||
Promise.reject("See docs to implement AI Assistant")
|
||||
Promise.reject('See docs to implement AI Assistant'),
|
||||
),
|
||||
language: "zh_CN",
|
||||
|
||||
language: 'zh_CN',
|
||||
// 其他配置
|
||||
table_class_list: [
|
||||
{ title: "无样式", value: "" },
|
||||
{ title: "简单表格", value: "simple-table" },
|
||||
{ title: "条纹表格", value: "striped-table" },
|
||||
{ title: "边框表格", value: "bordered-table" },
|
||||
{ title: '无样式', value: '' },
|
||||
{ title: '简单表格', value: 'simple-table' },
|
||||
{ title: '条纹表格', value: 'striped-table' },
|
||||
{ title: '边框表格', value: 'bordered-table' },
|
||||
],
|
||||
convert_urls: false,
|
||||
remove_script_host: false,
|
||||
uploadcare_public_key: "0ad3671d77f59c5756dd",
|
||||
|
||||
uploadcare_public_key: '0ad3671d77f59c5756dd',
|
||||
setup: (editor: TinyMCEEditor) => {
|
||||
// 注册自定义上传按钮
|
||||
editor.ui.registry.addButton("customupload", {
|
||||
text: uploading ? "上传中..." : "上传",
|
||||
icon: "upload",
|
||||
tooltip: "上传图片(支持多选)",
|
||||
editor.ui.registry.addButton('customupload', {
|
||||
text: uploading ? '上传中...' : '上传',
|
||||
icon: 'upload',
|
||||
tooltip: '上传图片(支持多选)',
|
||||
enabled: !disabled && !uploading,
|
||||
onAction: () => {
|
||||
handleCustomUpload(editor);
|
||||
@@ -235,7 +233,9 @@ const RichEditor: React.FC<RichEditorProps> = ({
|
||||
images_upload_handler: handleImageUpload,
|
||||
// 性能配置
|
||||
browser_spellcheck: true,
|
||||
contextmenu: "link image table",
|
||||
contextmenu: 'link image table',
|
||||
promotion: false,
|
||||
branding: false, // 去除品牌标识
|
||||
}}
|
||||
|
||||
// onBlur={() =>onChange()}
|
||||
|
||||
@@ -61,7 +61,6 @@ const AudioUploader: React.FC<AudioUploaderProps> = ({
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
// 实际的后端接口上传
|
||||
const uploadToServer = async (file: File) => {
|
||||
const formData = new FormData();
|
||||
|
||||
147
src/components/Upload/UploadImages/index.tsx
Normal file
147
src/components/Upload/UploadImages/index.tsx
Normal file
@@ -0,0 +1,147 @@
|
||||
import { PlusOutlined } from '@ant-design/icons';
|
||||
import type { GetProp, UploadFile, UploadProps } from 'antd';
|
||||
import { Image, message, Spin, Upload } from 'antd';
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { uploadImage } from '@/services/infra/media';
|
||||
|
||||
type FileType = Parameters<GetProp<UploadProps, 'beforeUpload'>>[0];
|
||||
|
||||
const getBase64 = (file: FileType): Promise<string> =>
|
||||
new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.readAsDataURL(file);
|
||||
reader.onload = () => resolve(reader.result as string);
|
||||
reader.onerror = (error) => reject(error);
|
||||
});
|
||||
|
||||
// accept: .doc,.docx,.xml,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document image/*,.pdf
|
||||
const UploadImages: React.FC<{
|
||||
value?: string;
|
||||
onChange?: (value: string | string[]) => void;
|
||||
multiple?: boolean;
|
||||
accept?: string;
|
||||
maxCount?: number;
|
||||
}> = (props) => {
|
||||
const {
|
||||
value,
|
||||
multiple = false,
|
||||
maxCount = 1,
|
||||
accept = 'image/png,image/jpeg',
|
||||
onChange,
|
||||
} = props;
|
||||
const [previewOpen, setPreviewOpen] = useState(false);
|
||||
const [previewImage, setPreviewImage] = useState('');
|
||||
const [fileList, setFileList] = useState<UploadFile[]>([]);
|
||||
const [uploading, setUploading] = useState(false);
|
||||
useEffect(() => {
|
||||
if (value) {
|
||||
setFileList([{ uid: '-1', url: value, status: 'done', name: value }]);
|
||||
} else {
|
||||
setFileList([]);
|
||||
}
|
||||
}, [value]);
|
||||
const beforeUpload = (file: FileType) => {
|
||||
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
|
||||
if (!isJpgOrPng) {
|
||||
message.error('仅支持.jpg .png 格式!');
|
||||
}
|
||||
// const isLt2M = file.size / 1024 / 1024 < 2;
|
||||
// if (!isLt2M) {
|
||||
// message.error('Image must smaller than 2MB!');
|
||||
// }
|
||||
return isJpgOrPng;
|
||||
};
|
||||
const handlePreview = async (file: UploadFile) => {
|
||||
if (!file.url && !file.preview) {
|
||||
file.preview = await getBase64(file.originFileObj as FileType);
|
||||
}
|
||||
|
||||
setPreviewImage(file.url || (file.preview as string));
|
||||
setPreviewOpen(true);
|
||||
};
|
||||
|
||||
const handleRemove = (file: UploadFile): boolean => {
|
||||
const newFileList = fileList.filter((item) => item.uid !== file.uid);
|
||||
const newUrl = newFileList.map((item) => item.url) as string[];
|
||||
onChange?.(newUrl[0]);
|
||||
return true;
|
||||
};
|
||||
|
||||
const uploadButton = (
|
||||
<button style={{ border: 0, background: 'none' }} type="button">
|
||||
<PlusOutlined />
|
||||
<div style={{ marginTop: 8 }}>Upload</div>
|
||||
</button>
|
||||
);
|
||||
const uploadFile = useCallback(async (file: File): Promise<string> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
try {
|
||||
uploadImage(formData).then((res) => {
|
||||
if (res) {
|
||||
resolve(res);
|
||||
} else {
|
||||
reject(new Error('上传失败:未返回有效的URL'));
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
const handleLoadImage: UploadProps['customRequest'] = async (option) => {
|
||||
const { file, onSuccess, onError, onProgress } = option;
|
||||
|
||||
try {
|
||||
setUploading(true);
|
||||
// 模拟进度更新
|
||||
onProgress?.({ percent: 10 });
|
||||
// 调用后端接口
|
||||
const url = await uploadFile(file as File);
|
||||
onProgress?.({ percent: 100 });
|
||||
if (url) {
|
||||
onChange?.(url);
|
||||
onSuccess?.({ url });
|
||||
message.success('上传成功');
|
||||
} else {
|
||||
throw new Error('上传失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Upload error:', error);
|
||||
onError?.(error as Error);
|
||||
message.error(`上传失败: ${(error as Error).message}`);
|
||||
} finally {
|
||||
setUploading(false);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<Spin spinning={uploading}>
|
||||
<Upload
|
||||
listType="picture-card"
|
||||
fileList={fileList}
|
||||
onPreview={handlePreview}
|
||||
onRemove={handleRemove}
|
||||
beforeUpload={beforeUpload}
|
||||
customRequest={handleLoadImage}
|
||||
multiple={multiple}
|
||||
accept={accept}
|
||||
>
|
||||
{fileList.length >= maxCount ? null : uploadButton}
|
||||
</Upload>
|
||||
{previewImage && (
|
||||
<Image
|
||||
wrapperStyle={{ display: 'none' }}
|
||||
preview={{
|
||||
visible: previewOpen,
|
||||
onVisibleChange: (visible) => setPreviewOpen(visible),
|
||||
afterOpenChange: (visible) => !visible && setPreviewImage(''),
|
||||
}}
|
||||
src={previewImage}
|
||||
/>
|
||||
)}
|
||||
</Spin>
|
||||
);
|
||||
};
|
||||
|
||||
export default UploadImages;
|
||||
192
src/components/Upload/UploadVideo/index.tsx
Normal file
192
src/components/Upload/UploadVideo/index.tsx
Normal file
@@ -0,0 +1,192 @@
|
||||
import { PlusOutlined } from '@ant-design/icons';
|
||||
import type { GetProp, UploadFile, UploadProps } from 'antd';
|
||||
import { Modal, message, Spin, Upload } from 'antd';
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import VideoThumbnail from 'react-video-thumbnail';
|
||||
import { uploadImage } from '@/services/infra/media';
|
||||
|
||||
type FileType = Parameters<GetProp<UploadProps, 'beforeUpload'>>[0];
|
||||
interface CustomUploadFile extends UploadFile {
|
||||
thumbUrl?: string;
|
||||
preview?: string;
|
||||
}
|
||||
const getBase64 = (file: FileType): Promise<string> =>
|
||||
new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.readAsDataURL(file);
|
||||
reader.onload = () => resolve(reader.result as string);
|
||||
reader.onerror = (error) => reject(error);
|
||||
});
|
||||
|
||||
// accept: .doc,.docx,.xml,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document image/*,.pdf
|
||||
const UploadVideo: React.FC<{
|
||||
value?: string;
|
||||
onChange?: (value: string | string[]) => void;
|
||||
multiple?: boolean;
|
||||
accept?: string;
|
||||
maxCount?: number;
|
||||
}> = (props) => {
|
||||
const {
|
||||
value,
|
||||
multiple = false,
|
||||
maxCount = 1,
|
||||
accept = 'video/*',
|
||||
onChange,
|
||||
} = props;
|
||||
const [previewOpen, setPreviewOpen] = useState(false);
|
||||
const [previewVideo, setPreviewVideo] = useState('');
|
||||
const [fileList, setFileList] = useState<CustomUploadFile[]>([]);
|
||||
const [uploading, setUploading] = useState(false);
|
||||
useEffect(() => {
|
||||
if (value) {
|
||||
setFileList([
|
||||
{ uid: '-1', url: value, thumbUrl: value, status: 'done', name: value },
|
||||
]);
|
||||
} else {
|
||||
setFileList([]);
|
||||
}
|
||||
}, [value]);
|
||||
const beforeUpload = (file: FileType) => {
|
||||
const isJpgOrPng = file.type === 'video/mp4' || file.type === 'video/mov';
|
||||
if (!isJpgOrPng) {
|
||||
message.error('仅支持.mp4 .mov 格式!');
|
||||
}
|
||||
// const isLt2M = file.size / 1024 / 1024 < 2;
|
||||
// if (!isLt2M) {
|
||||
// message.error('Image must smaller than 2MB!');
|
||||
// }
|
||||
return isJpgOrPng;
|
||||
};
|
||||
|
||||
// // 生成缩略图组件
|
||||
// const renderThumbnail = (videoUrl: string) => {
|
||||
// return (
|
||||
// <div style={{ width: "100%", height: "100%" }}>
|
||||
// <VideoThumbnail
|
||||
// videoUrl={videoUrl}
|
||||
// width={120}
|
||||
// height={90}
|
||||
// snapshotAt={1}
|
||||
// />
|
||||
// </div>
|
||||
// );
|
||||
// };
|
||||
const handlePreview = async (file: CustomUploadFile) => {
|
||||
if (!file.url && !file.preview && file.originFileObj) {
|
||||
file.preview = await getBase64(file.originFileObj);
|
||||
}
|
||||
setPreviewVideo(file.url || file.preview || '');
|
||||
setPreviewOpen(true);
|
||||
};
|
||||
// const customItemRender: UploadProps["itemRender"] = (
|
||||
// _,
|
||||
// file: CustomUploadFile
|
||||
// ) => {
|
||||
// return (
|
||||
// <div className="ant-upload-list-item-container">
|
||||
// <div className="ant-upload-list-item-card">
|
||||
// <div className="video-thumbnail" onClick={() => handlePreview(file)}>
|
||||
// {file.thumbUrl ? (
|
||||
// renderThumbnail("https://petshy.tashowz.com" + file.thumbUrl)
|
||||
// ) : (
|
||||
// <div className="video-icon">
|
||||
// <PlayCircleOutlined
|
||||
// style={{ fontSize: 48, color: "#1890ff" }}
|
||||
// />
|
||||
// </div>
|
||||
// )}
|
||||
// </div>
|
||||
// <div className="ant-upload-list-item-name">{file.name}</div>
|
||||
// </div>
|
||||
// </div>
|
||||
// );
|
||||
// };
|
||||
const handleRemove = (file: UploadFile): boolean => {
|
||||
const newFileList = fileList.filter((item) => item.uid !== file.uid);
|
||||
const newUrl = newFileList.map((item) => item.url) as string[];
|
||||
onChange?.(newUrl[0]);
|
||||
return true;
|
||||
};
|
||||
|
||||
const uploadButton = (
|
||||
<button style={{ border: 0, background: 'none' }} type="button">
|
||||
<PlusOutlined />
|
||||
<div style={{ marginTop: 8 }}>上传</div>
|
||||
</button>
|
||||
);
|
||||
const uploadFile = useCallback(async (file: File): Promise<string> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
try {
|
||||
uploadImage(formData).then((res) => {
|
||||
if (res) {
|
||||
resolve(res);
|
||||
} else {
|
||||
reject(new Error('上传失败:未返回有效的URL'));
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
const handleLoadImage: UploadProps['customRequest'] = async (option) => {
|
||||
const { file, onSuccess, onError, onProgress } = option;
|
||||
|
||||
try {
|
||||
setUploading(true);
|
||||
// 模拟进度更新
|
||||
onProgress?.({ percent: 10 });
|
||||
// 调用后端接口
|
||||
const url = await uploadFile(file as File);
|
||||
onProgress?.({ percent: 100 });
|
||||
if (url) {
|
||||
onChange?.(url);
|
||||
onSuccess?.({ url });
|
||||
message.success('上传成功');
|
||||
} else {
|
||||
throw new Error('上传失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Upload error:', error);
|
||||
onError?.(error as Error);
|
||||
message.error(`上传失败: ${(error as Error).message}`);
|
||||
} finally {
|
||||
setUploading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Spin spinning={uploading}>
|
||||
<Upload
|
||||
listType="picture-card"
|
||||
fileList={fileList}
|
||||
onPreview={handlePreview}
|
||||
// itemRender={customItemRender}
|
||||
onRemove={handleRemove}
|
||||
beforeUpload={beforeUpload}
|
||||
customRequest={handleLoadImage}
|
||||
multiple={multiple}
|
||||
accept={accept}
|
||||
>
|
||||
{fileList.length >= maxCount ? null : uploadButton}
|
||||
</Upload>
|
||||
<Modal
|
||||
open={previewOpen}
|
||||
title="视频预览"
|
||||
footer={null}
|
||||
onCancel={() => setPreviewOpen(false)}
|
||||
width={800}
|
||||
>
|
||||
<video controls style={{ width: '100%', height: '500px' }} autoPlay>
|
||||
<source src={previewVideo} type="video/mp4" />
|
||||
<track kind="captions" src="" srcLang="zh" label="Chinese" />
|
||||
您的浏览器不支持视频预览功能
|
||||
</video>
|
||||
</Modal>
|
||||
</Spin>
|
||||
);
|
||||
};
|
||||
|
||||
export default UploadVideo;
|
||||
2
src/constants/antd/image.tsx
Normal file
2
src/constants/antd/image.tsx
Normal file
@@ -0,0 +1,2 @@
|
||||
export const fallback =
|
||||
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMIAAADDCAYAAADQvc6UAAABRWlDQ1BJQ0MgUHJvZmlsZQAAKJFjYGASSSwoyGFhYGDIzSspCnJ3UoiIjFJgf8LAwSDCIMogwMCcmFxc4BgQ4ANUwgCjUcG3awyMIPqyLsis7PPOq3QdDFcvjV3jOD1boQVTPQrgSkktTgbSf4A4LbmgqISBgTEFyFYuLykAsTuAbJEioKOA7DkgdjqEvQHEToKwj4DVhAQ5A9k3gGyB5IxEoBmML4BsnSQk8XQkNtReEOBxcfXxUQg1Mjc0dyHgXNJBSWpFCYh2zi+oLMpMzyhRcASGUqqCZ16yno6CkYGRAQMDKMwhqj/fAIcloxgHQqxAjIHBEugw5sUIsSQpBobtQPdLciLEVJYzMPBHMDBsayhILEqEO4DxG0txmrERhM29nYGBddr//5/DGRjYNRkY/l7////39v///y4Dmn+LgeHANwDrkl1AuO+pmgAAADhlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAAqACAAQAAAABAAAAwqADAAQAAAABAAAAwwAAAAD9b/HnAAAHlklEQVR4Ae3dP3PTWBSGcbGzM6GCKqlIBRV0dHRJFarQ0eUT8LH4BnRU0NHR0UEFVdIlFRV7TzRksomPY8uykTk/zewQfKw/9znv4yvJynLv4uLiV2dBoDiBf4qP3/ARuCRABEFAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghgg0Aj8i0JO4OzsrPv69Wv+hi2qPHr0qNvf39+iI97soRIh4f3z58/u7du3SXX7Xt7Z2enevHmzfQe+oSN2apSAPj09TSrb+XKI/f379+08+A0cNRE2ANkupk+ACNPvkSPcAAEibACyXUyfABGm3yNHuAECRNgAZLuYPgEirKlHu7u7XdyytGwHAd8jjNyng4OD7vnz51dbPT8/7z58+NB9+/bt6jU/TI+AGWHEnrx48eJ/EsSmHzx40L18+fLyzxF3ZVMjEyDCiEDjMYZZS5wiPXnyZFbJaxMhQIQRGzHvWR7XCyOCXsOmiDAi1HmPMMQjDpbpEiDCiL358eNHurW/5SnWdIBbXiDCiA38/Pnzrce2YyZ4//59F3ePLNMl4PbpiL2J0L979+7yDtHDhw8vtzzvdGnEXdvUigSIsCLAWavHp/+qM0BcXMd/q25n1vF57TYBp0a3mUzilePj4+7k5KSLb6gt6ydAhPUzXnoPR0dHl79WGTNCfBnn1uvSCJdegQhLI1vvCk+fPu2ePXt2tZOYEV6/fn31dz+shwAR1sP1cqvLntbEN9MxA9xcYjsxS1jWR4AIa2Ibzx0tc44fYX/16lV6NDFLXH+YL32jwiACRBiEbf5KcXoTIsQSpzXx4N28Ja4BQoK7rgXiydbHjx/P25TaQAJEGAguWy0+2Q8PD6/Ki4R8EVl+bzBOnZY95fq9rj9zAkTI2SxdidBHqG9+skdw43borCXO/ZcJdraPWdv22uIEiLA4q7nvvCug8WTqzQveOH26fodo7g6uFe/a17W3+nFBAkRYENRdb1vkkz1CH9cPsVy/jrhr27PqMYvENYNlHAIesRiBYwRy0V+8iXP8+/fvX11Mr7L7ECueb/r48eMqm7FuI2BGWDEG8cm+7G3NEOfmdcTQw4h9/55lhm7DekRYKQPZF2ArbXTAyu4kDYB2YxUzwg0gi/41ztHnfQG26HbGel/crVrm7tNY+/1btkOEAZ2M05r4FB7r9GbAIdxaZYrHdOsgJ/wCEQY0J74TmOKnbxxT9n3FgGGWWsVdowHtjt9Nnvf7yQM2aZU/TIAIAxrw6dOnAWtZZcoEnBpNuTuObWMEiLAx1HY0ZQJEmHJ3HNvGCBBhY6jtaMoEiJB0Z29vL6ls58vxPcO8/zfrdo5qvKO+d3Fx8Wu8zf1dW4p/cPzLly/dtv9Ts/EbcvGAHhHyfBIhZ6NSiIBTo0LNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiEC/wGgKKC4YMA4TAAAAABJRU5ErkJggg==';
|
||||
@@ -3,6 +3,9 @@ export const formStatusType: { [key: string]: string } = {
|
||||
update: '编辑',
|
||||
test: '测试',
|
||||
detail: '详情',
|
||||
sku: 'sku管理',
|
||||
'extend-rule': '服务规则管理',
|
||||
'extend-service': '扩展服务管理',
|
||||
};
|
||||
|
||||
export const tenantStatus = [
|
||||
|
||||
5
src/pages/prod/category/category-selecr.tsx
Normal file
5
src/pages/prod/category/category-selecr.tsx
Normal file
@@ -0,0 +1,5 @@
|
||||
const CateGorySelect = () => {
|
||||
return <div></div>;
|
||||
};
|
||||
|
||||
export default CateGorySelect;
|
||||
@@ -2,51 +2,54 @@ import type {
|
||||
ProColumns,
|
||||
ProCoreActionType,
|
||||
ProFormColumnsType,
|
||||
} from "@ant-design/pro-components";
|
||||
import dayjs from "dayjs";
|
||||
import TagEditor from "@/components/TagEditor";
|
||||
import TinyMCEEditor from "@/components/Tinymce";
|
||||
} from '@ant-design/pro-components';
|
||||
import { Modal, message, Switch } from 'antd';
|
||||
import dayjs from 'dayjs';
|
||||
import TagEditor from '@/components/TagEditor';
|
||||
import TinyMCEEditor from '@/components/Tinymce';
|
||||
import UploadImages from '@/components/Upload/UploadImages';
|
||||
import { dateFormatS } from '@/constants';
|
||||
import {
|
||||
getCategoryList,
|
||||
putCategoryUpdate,
|
||||
} from "@/services/prodApi/category";
|
||||
import { Input, message, Modal, Switch } from "antd";
|
||||
export const baseTenantColumns: ProColumns<API.CategoryDO>[] = [
|
||||
type Category,
|
||||
getProdCategoryPage,
|
||||
updateProdCategory,
|
||||
} from '@/services/prod/category-manager';
|
||||
export const baseTenantColumns: ProColumns<Category>[] = [
|
||||
{
|
||||
title: "类目名称",
|
||||
dataIndex: "categoryName",
|
||||
title: '类目名称',
|
||||
dataIndex: 'categoryName',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: "类目ID",
|
||||
dataIndex: "categoryId",
|
||||
title: '类目ID',
|
||||
dataIndex: 'categoryId',
|
||||
},
|
||||
{
|
||||
title: "类目层级",
|
||||
dataIndex: "grade",
|
||||
title: '类目层级',
|
||||
dataIndex: 'grade',
|
||||
hideInSearch: true, // 在搜索表单中隐藏
|
||||
},
|
||||
{
|
||||
title: "父级类目",
|
||||
dataIndex: "parentName",
|
||||
title: '父级类目',
|
||||
dataIndex: 'parentName',
|
||||
|
||||
hideInSearch: true, // 在搜索表单中隐藏
|
||||
},
|
||||
{
|
||||
title: "排序权重",
|
||||
dataIndex: "sort",
|
||||
title: '排序权重',
|
||||
dataIndex: 'sort',
|
||||
hideInSearch: true, // 在搜索表单中隐藏
|
||||
},
|
||||
{
|
||||
title: "状态",
|
||||
dataIndex: "status",
|
||||
valueType: "switch",
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
valueType: 'switch',
|
||||
hideInSearch: true,
|
||||
render: (
|
||||
_,
|
||||
record: API.CategoryDO,
|
||||
record: Category,
|
||||
_index: number,
|
||||
action: ProCoreActionType | undefined
|
||||
action: ProCoreActionType | undefined,
|
||||
) => (
|
||||
<Switch
|
||||
checked={record.status === 1}
|
||||
@@ -54,17 +57,17 @@ export const baseTenantColumns: ProColumns<API.CategoryDO>[] = [
|
||||
unCheckedChildren="禁用"
|
||||
onChange={(checked) => {
|
||||
Modal.confirm({
|
||||
title: "确认操作",
|
||||
content: `确认要"${checked ? "启用" : "禁用"}${
|
||||
title: '确认操作',
|
||||
content: `确认要"${checked ? '启用' : '禁用'}${
|
||||
record.categoryName
|
||||
}"类目吗?`,
|
||||
onOk: async () => {
|
||||
console.log(checked);
|
||||
await putCategoryUpdate({
|
||||
await updateProdCategory({
|
||||
status: checked ? 1 : 0,
|
||||
categoryId: record.categoryId,
|
||||
});
|
||||
message.success("修改成功");
|
||||
message.success('修改成功');
|
||||
action?.reload();
|
||||
},
|
||||
});
|
||||
@@ -73,145 +76,158 @@ export const baseTenantColumns: ProColumns<API.CategoryDO>[] = [
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "创建时间",
|
||||
dataIndex: "createTime",
|
||||
valueType: "dateRange",
|
||||
title: '创建时间',
|
||||
dataIndex: 'createTime',
|
||||
valueType: 'dateRange',
|
||||
hideInSearch: true, // 在搜索表单中隐藏
|
||||
render: (_, record: API.CategoryDO) =>
|
||||
dayjs(record.createTime).format("YYYY-MM-DD HH:mm:ss"),
|
||||
render: (_, record: Category) =>
|
||||
dayjs(record.createTime).format('YYYY-MM-DD HH:mm:ss'),
|
||||
},
|
||||
];
|
||||
|
||||
export const formColumns = (data: {
|
||||
type: string;
|
||||
grade: number;
|
||||
}): ProFormColumnsType[] => [
|
||||
{
|
||||
title: "类目",
|
||||
dataIndex: "grade",
|
||||
valueType: "radio",
|
||||
fieldProps: {
|
||||
options: [
|
||||
{ label: "一级类目", value: 1 },
|
||||
{ label: "二级类目", value: 2 },
|
||||
{ label: "三级类目", value: 3 },
|
||||
],
|
||||
disabled: data.type === "update",
|
||||
export const formColumns = (data: { type: string }): ProFormColumnsType[] => {
|
||||
console.log(data, 'data');
|
||||
return [
|
||||
{
|
||||
title: '类目',
|
||||
dataIndex: 'grade',
|
||||
valueType: 'radio',
|
||||
fieldProps: {
|
||||
options: [
|
||||
{ label: '一级类目', value: 1 },
|
||||
{ label: '二级类目', value: 2 },
|
||||
{ label: '三级类目', value: 3 },
|
||||
],
|
||||
disabled: data.type === 'update',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "类目名称",
|
||||
dataIndex: "categoryName",
|
||||
formItemProps: {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: "请输入用户名",
|
||||
},
|
||||
],
|
||||
{
|
||||
title: '类目名称',
|
||||
dataIndex: 'categoryName',
|
||||
formItemProps: {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入用户名',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "排序权重",
|
||||
dataIndex: "sort",
|
||||
valueType: "digit",
|
||||
},
|
||||
{
|
||||
title: "类目描述",
|
||||
dataIndex: "description",
|
||||
valueType: "textarea",
|
||||
renderFormItem: () => {
|
||||
return <TinyMCEEditor />;
|
||||
{
|
||||
title: '排序权重',
|
||||
dataIndex: 'sort',
|
||||
valueType: 'digit',
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "关联父级",
|
||||
dataIndex: "parentId",
|
||||
valueType: "select",
|
||||
hideInForm: data.grade - 1 <= 0,
|
||||
fieldProps: {
|
||||
fieldNames: { label: "categoryName", value: "categoryId" },
|
||||
{
|
||||
title: '类目描述',
|
||||
dataIndex: 'description',
|
||||
valueType: 'textarea',
|
||||
renderFormItem: () => {
|
||||
return <TinyMCEEditor />;
|
||||
},
|
||||
},
|
||||
request: async () => {
|
||||
const grade = data.grade ? data.grade - 1 : undefined;
|
||||
const res = await getCategoryList({ grade });
|
||||
return res;
|
||||
{
|
||||
title: '关联父级',
|
||||
dataIndex: 'parentId',
|
||||
valueType: 'select',
|
||||
fieldProps: {
|
||||
fieldNames: { label: 'categoryName', value: 'categoryId' },
|
||||
},
|
||||
dependencies: ['grade'],
|
||||
request: async (params) => {
|
||||
const res = await getProdCategoryPage({
|
||||
grade: Number(params.grade) - 1,
|
||||
});
|
||||
return res;
|
||||
},
|
||||
renderFormItem: (schema, config, form) => {
|
||||
const grade = form.getFieldValue('grade');
|
||||
if (Number(grade) === 1) {
|
||||
return null;
|
||||
}
|
||||
return config.defaultRender(schema);
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "类目icon",
|
||||
dataIndex: "icon",
|
||||
},
|
||||
{
|
||||
title: "类目标签",
|
||||
dataIndex: "tag",
|
||||
renderFormItem: () => {
|
||||
return (
|
||||
<TagEditor
|
||||
placeholder="输入标签名称"
|
||||
maxCount={10}
|
||||
tagProps={{
|
||||
color: "blue",
|
||||
}}
|
||||
/>
|
||||
);
|
||||
{
|
||||
title: '类目icon',
|
||||
dataIndex: 'icon',
|
||||
renderFormItem: () => {
|
||||
return <UploadImages multiple={true} />;
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "类目状态",
|
||||
dataIndex: "status",
|
||||
hideInForm: data.type === "create",
|
||||
fieldProps: {
|
||||
disabled: data.type === "update",
|
||||
{
|
||||
title: '类目标签',
|
||||
dataIndex: 'tag',
|
||||
renderFormItem: () => {
|
||||
return (
|
||||
<TagEditor
|
||||
placeholder="输入标签名称"
|
||||
maxCount={10}
|
||||
tagProps={{
|
||||
color: 'blue',
|
||||
}}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
renderFormItem: (_schema, _config, form) => {
|
||||
const status = form.getFieldValue("type");
|
||||
return <Input value={status ? "开启" : "禁用"} disabled />;
|
||||
{
|
||||
title: '类目状态',
|
||||
dataIndex: 'status',
|
||||
hideInForm: data.type === 'create',
|
||||
renderFormItem: (_schema, _config, form) => {
|
||||
const status = form.getFieldValue('status');
|
||||
return <span>{status ? '启用' : '禁用'}</span>;
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "类目ID",
|
||||
dataIndex: "categoryId",
|
||||
hideInForm: data.type === "create",
|
||||
fieldProps: {
|
||||
disabled: data.type === "update",
|
||||
{
|
||||
title: '类目ID',
|
||||
dataIndex: 'categoryId',
|
||||
hideInForm: data.type === 'create',
|
||||
renderFormItem: (_schema, _config, form) => {
|
||||
const categoryId = form.getFieldValue('categoryId');
|
||||
return <span>{categoryId}</span>;
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "创建时间",
|
||||
dataIndex: "createTime",
|
||||
valueType: "dateTime",
|
||||
hideInForm: data.type === "create",
|
||||
fieldProps: {
|
||||
disabled: data.type === "update",
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'createTime',
|
||||
valueType: 'dateTime',
|
||||
hideInForm: data.type === 'create',
|
||||
renderFormItem: (_schema, _config, form) => {
|
||||
const createTime = form.getFieldValue('createTime');
|
||||
return <span>{dayjs(createTime).format(dateFormatS)}</span>;
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "创建人",
|
||||
dataIndex: "creator",
|
||||
hideInForm: data.type === "create",
|
||||
fieldProps: {
|
||||
disabled: data.type === "update",
|
||||
{
|
||||
title: '创建人',
|
||||
dataIndex: 'creator',
|
||||
hideInForm: data.type === 'create',
|
||||
renderFormItem: (_schema, _config, form) => {
|
||||
const creator = form.getFieldValue('creator');
|
||||
return <span>{creator}</span>;
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "更新时间",
|
||||
dataIndex: "updateTime",
|
||||
valueType: "dateTime",
|
||||
hideInForm: data.type === "create",
|
||||
fieldProps: {
|
||||
disabled: data.type === "update",
|
||||
{
|
||||
title: '更新时间',
|
||||
dataIndex: 'updateTime',
|
||||
valueType: 'dateTime',
|
||||
hideInForm: data.type === 'create',
|
||||
renderFormItem: (_schema, _config, form) => {
|
||||
const dateTime = form.getFieldValue('dateTime');
|
||||
return <span>{dayjs(dateTime).format(dateFormatS)}</span>;
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "更新人",
|
||||
dataIndex: "updator",
|
||||
hideInForm: data.type === "create",
|
||||
fieldProps: {
|
||||
disabled: data.type === "update",
|
||||
{
|
||||
title: '更新人',
|
||||
dataIndex: 'updator',
|
||||
hideInForm: data.type === 'create',
|
||||
renderFormItem: (_schema, _config, form) => {
|
||||
const updator = form.getFieldValue('updator');
|
||||
return <span>{updator}</span>;
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
];
|
||||
};
|
||||
|
||||
// {
|
||||
// title: "模板内容",
|
||||
|
||||
@@ -1,24 +1,26 @@
|
||||
import { PlusOutlined } from "@ant-design/icons";
|
||||
import type { ActionType, ProColumns } from "@ant-design/pro-components";
|
||||
import type { TabsProps } from "antd";
|
||||
import { Tabs } from "antd";
|
||||
import { useCallback, useRef, useState } from "react";
|
||||
import { PlusOutlined } from '@ant-design/icons';
|
||||
import type { ActionType, ProColumns } from '@ant-design/pro-components';
|
||||
import type { TabsProps } from 'antd';
|
||||
import { Tabs } from 'antd';
|
||||
import { useCallback, useRef, useState } from 'react';
|
||||
import ConfigurableDrawerForm, {
|
||||
type ConfigurableDrawerFormRef,
|
||||
} from "@/components/DrawerForm";
|
||||
import EnhancedProTable from "@/components/EnhancedProTable";
|
||||
import type { ToolbarAction } from "@/components/EnhancedProTable/types";
|
||||
import { formStatusType } from "@/constants";
|
||||
} from '@/components/DrawerForm';
|
||||
import EnhancedProTable from '@/components/EnhancedProTable';
|
||||
import type { ToolbarAction } from '@/components/EnhancedProTable/types';
|
||||
import { formStatusType } from '@/constants';
|
||||
import {
|
||||
getCategoryList,
|
||||
postCategoryCreate,
|
||||
putCategoryUpdate,
|
||||
} from "@/services/prodApi/category";
|
||||
import { baseTenantColumns, formColumns } from "./config";
|
||||
type Category,
|
||||
type CategoryReq,
|
||||
createProdCategory,
|
||||
getProdCategoryPage,
|
||||
updateProdCategory,
|
||||
} from '@/services/prod/category-manager';
|
||||
import { baseTenantColumns, formColumns } from './config';
|
||||
|
||||
const ProdCategory = () => {
|
||||
const tableRef = useRef<ActionType>(null);
|
||||
const [type, setType] = useState<"create" | "update" | "test">("create");
|
||||
const [type, setType] = useState<'create' | 'update' | 'test'>('create');
|
||||
const [grade, setGrade] = useState<number>();
|
||||
const configurableDrawerRef = useRef<ConfigurableDrawerFormRef>(null);
|
||||
const [id, setId] = useState<number>(0);
|
||||
@@ -26,11 +28,11 @@ const ProdCategory = () => {
|
||||
(key: string) => {
|
||||
setGrade(Number(key));
|
||||
},
|
||||
[grade]
|
||||
[grade],
|
||||
);
|
||||
|
||||
const onFetch = async (params: API.getProductCategoryCategoryListParams) => {
|
||||
const data = await getCategoryList({
|
||||
const onFetch = async (params: CategoryReq) => {
|
||||
const data = await getProdCategoryPage({
|
||||
...params,
|
||||
grade: grade ? Number(grade) : undefined,
|
||||
});
|
||||
@@ -41,48 +43,48 @@ const ProdCategory = () => {
|
||||
};
|
||||
|
||||
const handleAdd = () => {
|
||||
setType("create");
|
||||
configurableDrawerRef.current?.open({ grade: grade ? grade : 1 });
|
||||
setType('create');
|
||||
configurableDrawerRef.current?.open({ grade: 1 });
|
||||
};
|
||||
|
||||
const toolbarActions: ToolbarAction[] = [
|
||||
{
|
||||
key: "add",
|
||||
label: "新建",
|
||||
type: "primary",
|
||||
key: 'add',
|
||||
label: '新建',
|
||||
type: 'primary',
|
||||
icon: <PlusOutlined />,
|
||||
onClick: handleAdd,
|
||||
},
|
||||
];
|
||||
const handleEdit = async (row: API.CategoryDO) => {
|
||||
setType("update");
|
||||
const handleEdit = async (row: Category) => {
|
||||
setType('update');
|
||||
row.categoryId && setId(row.categoryId);
|
||||
configurableDrawerRef.current?.open(row);
|
||||
};
|
||||
const handleSubmit = useCallback(
|
||||
async (values: API.CategoryDO) => {
|
||||
if (type === "create") {
|
||||
await postCategoryCreate(values);
|
||||
async (values: Category) => {
|
||||
if (type === 'create') {
|
||||
await createProdCategory(values);
|
||||
} else {
|
||||
await putCategoryUpdate({
|
||||
await updateProdCategory({
|
||||
...values,
|
||||
categoryId: id,
|
||||
});
|
||||
}
|
||||
tableRef.current?.reload();
|
||||
tableRef.current?.reload(true);
|
||||
return true;
|
||||
},
|
||||
|
||||
[id, type]
|
||||
[id, type],
|
||||
);
|
||||
|
||||
const actionColumns: ProColumns<API.CategoryDO> = {
|
||||
title: "操作",
|
||||
dataIndex: "option",
|
||||
valueType: "option",
|
||||
fixed: "right",
|
||||
const actionColumns: ProColumns<Category> = {
|
||||
title: '操作',
|
||||
dataIndex: 'option',
|
||||
valueType: 'option',
|
||||
fixed: 'right',
|
||||
width: 120,
|
||||
render: (_text: React.ReactNode, record: API.CategoryDO, _: number) => [
|
||||
render: (_text: React.ReactNode, record: Category, _: number) => [
|
||||
<a key="edit" onClick={() => handleEdit(record)}>
|
||||
编辑
|
||||
</a>,
|
||||
@@ -94,7 +96,7 @@ const ProdCategory = () => {
|
||||
const renderChildren = () => {
|
||||
return (
|
||||
<>
|
||||
<EnhancedProTable<API.CategoryDO>
|
||||
<EnhancedProTable<Category>
|
||||
ref={tableRef}
|
||||
columns={columns}
|
||||
rowKey="categoryId"
|
||||
@@ -107,8 +109,8 @@ const ProdCategory = () => {
|
||||
<ConfigurableDrawerForm
|
||||
ref={configurableDrawerRef}
|
||||
title={formStatusType[type]}
|
||||
// width="50vw"
|
||||
columns={formColumns({ grade: Number(grade), type })}
|
||||
width={'60vw'}
|
||||
columns={formColumns({ type })}
|
||||
onSubmit={handleSubmit}
|
||||
footer={undefined}
|
||||
bodyStyle={{}}
|
||||
@@ -117,25 +119,25 @@ const ProdCategory = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const items: TabsProps["items"] = [
|
||||
const items: TabsProps['items'] = [
|
||||
{
|
||||
key: "",
|
||||
label: "全部分类",
|
||||
key: '',
|
||||
label: '全部分类',
|
||||
children: renderChildren(),
|
||||
},
|
||||
{
|
||||
key: "3",
|
||||
label: "三级分类",
|
||||
key: '3',
|
||||
label: '三级分类',
|
||||
children: renderChildren(),
|
||||
},
|
||||
{
|
||||
key: "2",
|
||||
label: "二级分类",
|
||||
key: '2',
|
||||
label: '二级分类',
|
||||
children: renderChildren(),
|
||||
},
|
||||
{
|
||||
key: "1",
|
||||
label: "一级分类",
|
||||
key: '1',
|
||||
label: '一级分类',
|
||||
children: renderChildren(),
|
||||
},
|
||||
];
|
||||
@@ -143,6 +145,7 @@ const ProdCategory = () => {
|
||||
<Tabs
|
||||
defaultActiveKey={grade as unknown as string}
|
||||
items={items}
|
||||
destroyOnHidden
|
||||
onChange={onChange}
|
||||
/>
|
||||
);
|
||||
|
||||
0
src/pages/prod/list/components/extend-rule.tsx
Normal file
0
src/pages/prod/list/components/extend-rule.tsx
Normal file
151
src/pages/prod/list/components/prod-info.tsx
Normal file
151
src/pages/prod/list/components/prod-info.tsx
Normal file
@@ -0,0 +1,151 @@
|
||||
import {
|
||||
ProForm,
|
||||
ProFormGroup,
|
||||
ProFormSelect,
|
||||
ProFormText,
|
||||
ProFormTextArea,
|
||||
} from '@ant-design/pro-components';
|
||||
import { Divider } from 'antd';
|
||||
import React from 'react';
|
||||
import TagEditor from '@/components/TagEditor';
|
||||
import TinymceEditor from '@/components/Tinymce';
|
||||
import UploadImages from '@/components/Upload/UploadImages';
|
||||
import UploadVideo from '@/components/Upload/UploadVideo';
|
||||
import type { Prod } from '@/services/prod/prod-manager';
|
||||
|
||||
interface ProdInfoProps<T> {
|
||||
onRefresh?: (type?: string) => void;
|
||||
data?: T;
|
||||
}
|
||||
|
||||
const ProdInfo = <T extends Record<string, any>>(props: ProdInfoProps<T>) => {
|
||||
console.log(props, 'ProdInfo');
|
||||
return (
|
||||
<>
|
||||
<ProFormGroup title="一、基础信息">
|
||||
<ProFormText
|
||||
name="prodName"
|
||||
label="商品名字"
|
||||
rules={[{ required: true }]}
|
||||
width="xl"
|
||||
/>
|
||||
<ProFormText name="abbreviation" label="商品简称" width="xl" />
|
||||
<ProFormText name="brief" label="商品概述" width="xl" />
|
||||
<ProFormText name="prodNumber" label="商品编码" width="xl" />
|
||||
<ProFormText name="brand" label="品牌" width="xl" />
|
||||
<ProFormText name="shopId" label="商品所有权" width="xl" />
|
||||
<ProFormText name="categoryName" label="关联类目" width="xl" />
|
||||
<ProForm.Item
|
||||
name="tag"
|
||||
label="商品标签"
|
||||
tooltip="设置卖点标签,单标签限xx字符,最多x个标签"
|
||||
layout="horizontal"
|
||||
width="xl"
|
||||
required={false}
|
||||
// getValueFromEvent={(e) => e.fileList}
|
||||
>
|
||||
<TagEditor
|
||||
placeholder="输入标签名称"
|
||||
maxCount={10}
|
||||
tagProps={{
|
||||
color: 'blue',
|
||||
}}
|
||||
/>
|
||||
</ProForm.Item>
|
||||
</ProFormGroup>
|
||||
<ProFormGroup title="二、内容展示">
|
||||
<ProForm.Item
|
||||
style={{ width: '100%' }}
|
||||
name="pic"
|
||||
label="主图"
|
||||
width="xl"
|
||||
extra="仅支持.jpg .png 格式,建议图片比例1:1,限1张"
|
||||
// rules={[{ required: true }]}
|
||||
// getValueFromEvent={(e) => e.fileList}
|
||||
>
|
||||
<UploadImages />
|
||||
</ProForm.Item>
|
||||
<ProForm.Item
|
||||
style={{ width: '100%' }}
|
||||
name="imgs"
|
||||
label="轮播图"
|
||||
layout="horizontal"
|
||||
width="xl"
|
||||
extra="仅支持.jpg .png 格式,建议图片比例1:1,限7张"
|
||||
// getValueFromEvent={(e) => e.fileList}
|
||||
>
|
||||
<UploadImages />
|
||||
</ProForm.Item>
|
||||
<ProForm.Item
|
||||
style={{ width: '100%' }}
|
||||
name="whiteImg"
|
||||
label="白底图"
|
||||
width="xl"
|
||||
extra="仅支持.jpg .png 格式,建议图片比例1:1,限1张"
|
||||
// getValueFromEvent={(e) => e.fileList}
|
||||
>
|
||||
<UploadImages />
|
||||
</ProForm.Item>
|
||||
<ProForm.Item
|
||||
name="video"
|
||||
label="主视频"
|
||||
width="xl"
|
||||
extra="仅支持.MP4 .MOV 格式,建议比例1:1、16:9,限1个"
|
||||
// getValueFromEvent={(e) => e.fileList}
|
||||
>
|
||||
<UploadVideo />
|
||||
</ProForm.Item>
|
||||
<ProForm.Item
|
||||
name="content"
|
||||
label="图文介绍"
|
||||
rules={[{ required: true }]}
|
||||
width="xl"
|
||||
// getValueFromEvent={(e) => e.fileList}
|
||||
>
|
||||
<TinymceEditor />
|
||||
</ProForm.Item>
|
||||
</ProFormGroup>
|
||||
<ProFormGroup title="三、营销与传播">
|
||||
<ProFormText
|
||||
name="seoShortName"
|
||||
label="短标题"
|
||||
colProps={{
|
||||
span: 20,
|
||||
}}
|
||||
/>
|
||||
<ProFormText name="seoSearch" label="SEO标题" width={'xl'} />
|
||||
<ProFormTextArea name="keyword" label="商品关键词" width={'xl'} />
|
||||
<Divider />
|
||||
|
||||
<ProForm.Item
|
||||
style={{ width: '100%' }}
|
||||
name="shareImage"
|
||||
label="分享图"
|
||||
width="xl"
|
||||
extra="仅支持.jpg .png 格式,限1张"
|
||||
>
|
||||
<UploadImages />
|
||||
</ProForm.Item>
|
||||
<ProFormTextArea
|
||||
name="shareContent"
|
||||
label="分享话术"
|
||||
placeholder={'请输入分享话术'}
|
||||
width={'xl'}
|
||||
/>
|
||||
</ProFormGroup>
|
||||
<ProFormGroup>
|
||||
<ProFormSelect name="status" label="商品状态" readonly />
|
||||
<ProFormText name="prodId" label="商品ID" readonly />
|
||||
<ProFormText name="createTime" label="创建时间" readonly />
|
||||
<ProFormText name="creator" label="创建人" readonly />
|
||||
<ProFormText name="updateTime" label="更新时间" readonly />
|
||||
<ProFormText name="updater" label="更新人" readonly />
|
||||
<ProFormText name="version" label="版本号" readonly />
|
||||
</ProFormGroup>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(ProdInfo) as <_T extends Record<string, any>>(
|
||||
props: ProdInfoProps<Prod>,
|
||||
) => React.ReactElement;
|
||||
69
src/pages/prod/list/components/service-rule/index.tsx
Normal file
69
src/pages/prod/list/components/service-rule/index.tsx
Normal file
@@ -0,0 +1,69 @@
|
||||
import { ProForm, ProFormText } from '@ant-design/pro-components';
|
||||
|
||||
const ServiceRule: React.FC = () => {
|
||||
return (
|
||||
<ProForm<{
|
||||
name: string;
|
||||
company: string;
|
||||
}>
|
||||
grid
|
||||
onFinish={async (values) => {
|
||||
// await waitTime(2000);
|
||||
console.log(values);
|
||||
// message.success('提交成功');
|
||||
}}
|
||||
initialValues={{
|
||||
name: '蚂蚁设计有限公司',
|
||||
useMode: 'chapter',
|
||||
}}
|
||||
>
|
||||
<ProForm.Group>
|
||||
<ProFormText
|
||||
width="md"
|
||||
name="name"
|
||||
label="签约客户名称"
|
||||
tooltip="最长为 24 位"
|
||||
placeholder="请输入名称"
|
||||
/>
|
||||
<ProFormText
|
||||
width="md"
|
||||
name="company"
|
||||
label="我方公司名称"
|
||||
placeholder="请输入名称"
|
||||
/>
|
||||
</ProForm.Group>
|
||||
<ProFormText width="sm" name="id" label="主合同编号" />
|
||||
<ProForm.Item
|
||||
label="数组数据"
|
||||
name="dataSource"
|
||||
// initialValue={defaultData}
|
||||
trigger="onValuesChange"
|
||||
>
|
||||
{/* <EditableProTable<DataSourceType>
|
||||
rowKey="id"
|
||||
toolBarRender={false}
|
||||
columns={columns}
|
||||
recordCreatorProps={{
|
||||
newRecordType: 'dataSource',
|
||||
position: 'top',
|
||||
record: () => ({
|
||||
id: Date.now(),
|
||||
addonBefore: 'ccccccc',
|
||||
decs: 'testdesc',
|
||||
}),
|
||||
}}
|
||||
editable={{
|
||||
type: 'multiple',
|
||||
editableKeys,
|
||||
onChange: setEditableRowKeys,
|
||||
actionRender: (row, _, dom) => {
|
||||
return [dom.delete];
|
||||
},
|
||||
}} */}
|
||||
{/* /> */}
|
||||
</ProForm.Item>
|
||||
</ProForm>
|
||||
);
|
||||
};
|
||||
|
||||
export default ServiceRule;
|
||||
31
src/pages/prod/list/components/sku/index.tsx
Normal file
31
src/pages/prod/list/components/sku/index.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
import { ProForm } from '@ant-design/pro-components';
|
||||
import React from 'react';
|
||||
import SkuConfig from './sku-confiig';
|
||||
import SkuList from './sku-list';
|
||||
|
||||
const Sku: React.FC = () => {
|
||||
return (
|
||||
<>
|
||||
<ProForm.Item
|
||||
style={{ width: '100%' }}
|
||||
name="prodPropSaveReqVO"
|
||||
layout="horizontal"
|
||||
width="xl"
|
||||
// getValueFromEvent={(e) => e.fileList}
|
||||
>
|
||||
<SkuConfig />
|
||||
</ProForm.Item>
|
||||
<ProForm.Item
|
||||
style={{ width: '100%' }}
|
||||
name="skuList"
|
||||
layout="horizontal"
|
||||
width="xl"
|
||||
// getValueFromEvent={(e) => e.fileList}
|
||||
>
|
||||
<SkuList />
|
||||
</ProForm.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(Sku);
|
||||
23
src/pages/prod/list/components/sku/sku-confiig.tsx
Normal file
23
src/pages/prod/list/components/sku/sku-confiig.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
import { Typography } from 'antd';
|
||||
import React from 'react';
|
||||
import DraggableTagList from '@/components/Draggable/DraggableTagList';
|
||||
|
||||
const { Title, Text } = Typography;
|
||||
const SkuConfig: React.FC<{
|
||||
value?: API.ProdPropSaveReqVO;
|
||||
onChange?: (value: API.ProdPropSaveReqVO) => void;
|
||||
}> = () => {
|
||||
// const { value, onChange } = props;
|
||||
return (
|
||||
<>
|
||||
<Title level={4}>规格设置</Title>
|
||||
<Text type="secondary">
|
||||
你想区分商品的哪些属性?第一次使用?<a>点此查看详情</a>
|
||||
学习。商品创建成功后,规格属性不可增减,如需变更规格逻辑定义,请创建新的商品。
|
||||
</Text>
|
||||
<DraggableTagList />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(SkuConfig);
|
||||
22
src/pages/prod/list/components/sku/sku-list.tsx
Normal file
22
src/pages/prod/list/components/sku/sku-list.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
import { Typography } from 'antd';
|
||||
import React from 'react';
|
||||
import type { SkuConfig } from '@/services/prod/prod-manager';
|
||||
|
||||
const { Title, Text } = Typography;
|
||||
const SkuList: React.FC<{
|
||||
value?: SkuConfig;
|
||||
onChange?: (value: SkuConfig) => void;
|
||||
}> = (props) => {
|
||||
const { value } = props;
|
||||
console.log('value', value);
|
||||
return (
|
||||
<>
|
||||
<Title level={4}>SKU 列表</Title>
|
||||
<Text type="secondary">
|
||||
请填写SKU价格与可售数量,高级设置可自定义更多内容。
|
||||
</Text>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(SkuList);
|
||||
90
src/pages/prod/list/config.tsx
Normal file
90
src/pages/prod/list/config.tsx
Normal file
@@ -0,0 +1,90 @@
|
||||
import type { ProColumns } from '@ant-design/pro-components';
|
||||
import { Badge, Button, Image, Space, Typography } from 'antd';
|
||||
import dayjs from 'dayjs';
|
||||
import type { Prod } from '@/services/prod/prod-manager';
|
||||
|
||||
const { Text } = Typography;
|
||||
export const baseTenantColumns: ProColumns<Prod>[] = [
|
||||
{
|
||||
title: '商品',
|
||||
dataIndex: 'prodName',
|
||||
render: (_, record) => (
|
||||
<Space>
|
||||
<Image width={64} height={64} src={record.pic} />
|
||||
<div>
|
||||
<div>
|
||||
<Text>{record.categoryName}</Text>
|
||||
</div>
|
||||
<div>
|
||||
<Text type="secondary">ID:{record.categoryName}</Text>
|
||||
</div>
|
||||
<div>
|
||||
<Text type="secondary">类目:{record.categoryName}</Text>
|
||||
</div>
|
||||
</div>
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '服务信息',
|
||||
dataIndex: 'categoryId',
|
||||
render: () => (
|
||||
<Space direction="vertical">
|
||||
<div>
|
||||
<Text type="secondary">服务区域:</Text>
|
||||
<Text></Text>
|
||||
</div>
|
||||
<div>
|
||||
<Text type="secondary">服务区域:</Text>
|
||||
<Text></Text>
|
||||
</div>
|
||||
<div>
|
||||
<Text type="secondary">紧急服务:</Text>
|
||||
<Text></Text>
|
||||
</div>
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
valueType: 'switch',
|
||||
width: 300,
|
||||
hideInSearch: true,
|
||||
render: () => (
|
||||
<Space direction="vertical">
|
||||
<Space>
|
||||
<Badge status="success" text="出售中" />
|
||||
<Badge status="default" text="已置灰" />
|
||||
<Badge status="warning" text="待审核" />
|
||||
<Badge status="default" text="仓库中" />
|
||||
</Space>
|
||||
<Button size="small" type="dashed">
|
||||
状态控制
|
||||
</Button>
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '时间信息',
|
||||
dataIndex: 'createTime',
|
||||
valueType: 'dateRange',
|
||||
hideInSearch: true, // 在搜索表单中隐藏
|
||||
render: (_, record) => (
|
||||
<Space direction="vertical">
|
||||
<div>
|
||||
<Image></Image> 某某某某有限公司
|
||||
</div>
|
||||
<div>
|
||||
<Text type="secondary">创建时间:</Text>
|
||||
{dayjs(record.createTime).format('YYYY-MM-DD HH:mm:ss')}
|
||||
</div>
|
||||
<div>
|
||||
<Text type="secondary">更新时间:</Text>
|
||||
{dayjs(record.updateTime).format('YYYY-MM-DD HH:mm:ss')}
|
||||
</div>
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
];
|
||||
84
src/pages/prod/list/detail.tsx
Normal file
84
src/pages/prod/list/detail.tsx
Normal file
@@ -0,0 +1,84 @@
|
||||
import type { FormInstance } from '@ant-design/pro-components';
|
||||
import { ProCard, ProForm, StepsForm } from '@ant-design/pro-components';
|
||||
import { message } from 'antd';
|
||||
import { useEffect } from 'react';
|
||||
import ProdInfo from '@/pages/prod/list/components/prod-info';
|
||||
import Sku from '@/pages/prod/list/components/sku';
|
||||
import type { Prod, ProdDetail, SkuConfig } from '@/services/prod/prod-manager';
|
||||
|
||||
const waitTime = (time: number = 100) => {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve(true);
|
||||
}, time);
|
||||
});
|
||||
};
|
||||
|
||||
const ProdDetailPage: React.FC<{
|
||||
data?: Prod;
|
||||
formRef?: React.RefObject<FormInstance<any>>;
|
||||
}> = (props) => {
|
||||
const { data, formRef } = props;
|
||||
console.log(data, 'ProdDetailPage');
|
||||
useEffect(() => {
|
||||
if (data) {
|
||||
formRef?.current?.setFieldsValue(data);
|
||||
}
|
||||
}, [data]);
|
||||
return (
|
||||
<ProCard>
|
||||
{data?.prodId ? (
|
||||
<ProForm
|
||||
formRef={formRef}
|
||||
layout="horizontal"
|
||||
grid={true}
|
||||
submitter={false}
|
||||
>
|
||||
<ProdInfo />
|
||||
</ProForm>
|
||||
) : (
|
||||
<StepsForm<ProdDetail>
|
||||
current={0}
|
||||
formRef={formRef}
|
||||
submitter={false}
|
||||
onFinish={async () => {
|
||||
await waitTime(1000);
|
||||
message.success('提交成功');
|
||||
}}
|
||||
formProps={{
|
||||
validateMessages: {
|
||||
required: '此项为必填项',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<StepsForm.StepForm<ProdDetail>
|
||||
grid={true}
|
||||
layout="horizontal"
|
||||
name="info"
|
||||
title="填写商品信息"
|
||||
onFinish={async () => {
|
||||
try {
|
||||
await formRef?.current?.validateFields();
|
||||
console.log(formRef?.current?.getFieldsValue());
|
||||
} catch (error: any) {
|
||||
console.log(error);
|
||||
message.error(error.msg);
|
||||
}
|
||||
return true;
|
||||
}}
|
||||
>
|
||||
<ProdInfo data={data} />
|
||||
</StepsForm.StepForm>
|
||||
<StepsForm.StepForm<SkuConfig> name="sku" title="设置商品规格">
|
||||
<Sku />
|
||||
</StepsForm.StepForm>
|
||||
<StepsForm.StepForm<ProdDetail> name="prod" title="发布商品">
|
||||
提交
|
||||
</StepsForm.StepForm>
|
||||
</StepsForm>
|
||||
)}
|
||||
</ProCard>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProdDetailPage;
|
||||
@@ -1,5 +1,250 @@
|
||||
import { EllipsisOutlined, PlusOutlined } from '@ant-design/icons';
|
||||
import type { ActionType, ProColumns } from '@ant-design/pro-components';
|
||||
import type { MenuProps, TabsProps } from 'antd';
|
||||
import { Button, Dropdown, Space, Tabs } from 'antd';
|
||||
import { useCallback, useRef, useState } from 'react';
|
||||
import ConfigurableDrawerForm, {
|
||||
type ConfigurableDrawerFormRef,
|
||||
} from '@/components/DrawerForm';
|
||||
import EnhancedProTable from '@/components/EnhancedProTable';
|
||||
import type { ToolbarAction } from '@/components/EnhancedProTable/types';
|
||||
import { formStatusType } from '@/constants';
|
||||
import ProdDetail from '@/pages/prod/list/detail';
|
||||
import {
|
||||
createProd,
|
||||
getProdDetail,
|
||||
getProdPage,
|
||||
type Prod,
|
||||
type ProdReq,
|
||||
updateProd,
|
||||
} from '@/services/prod/prod-manager';
|
||||
import { baseTenantColumns } from './config';
|
||||
|
||||
const ProdList = () => {
|
||||
return <div>ProdList</div>;
|
||||
const tableRef = useRef<ActionType>(null);
|
||||
const [type, setType] = useState<'create' | 'update' | 'test'>('create');
|
||||
const [status, setStatus] = useState<number>();
|
||||
const detailRef = useRef<ConfigurableDrawerFormRef>(null);
|
||||
// const editRef = useRef<ConfigurableDrawerFormRef>(null);
|
||||
const [id, setId] = useState<number>(0);
|
||||
const onChange = useCallback(
|
||||
(key: string) => {
|
||||
setStatus(Number(key));
|
||||
},
|
||||
[status],
|
||||
);
|
||||
|
||||
const onFetch = async (params: ProdReq) => {
|
||||
const data = await getProdPage({
|
||||
...params,
|
||||
status: status ? status : undefined,
|
||||
});
|
||||
return {
|
||||
data: data.list,
|
||||
success: true,
|
||||
};
|
||||
};
|
||||
|
||||
const handleAdd = () => {
|
||||
setType('create');
|
||||
detailRef.current?.open({});
|
||||
};
|
||||
|
||||
const toolbarActions: ToolbarAction[] = [
|
||||
{
|
||||
key: 'add',
|
||||
label: '新建',
|
||||
type: 'primary',
|
||||
icon: <PlusOutlined />,
|
||||
onClick: handleAdd,
|
||||
},
|
||||
];
|
||||
const handleEdit = async (row: Prod) => {
|
||||
setType('update');
|
||||
const res = await getProdDetail({ id: row.prodId as number });
|
||||
setId(row.prodId as number);
|
||||
detailRef.current?.open(res);
|
||||
};
|
||||
// 商品更新
|
||||
// const _handleEditSubmit = async (values: Prod) => {
|
||||
// await updateProd(values);
|
||||
// tableRef.current?.reload();
|
||||
// message.success("编辑成功");
|
||||
// return true;
|
||||
// };
|
||||
const handleSubmit = useCallback(
|
||||
async (values: Prod) => {
|
||||
if (type === 'create') {
|
||||
await createProd(values);
|
||||
} else {
|
||||
await updateProd({
|
||||
...values,
|
||||
categoryId: id,
|
||||
});
|
||||
}
|
||||
tableRef.current?.reload();
|
||||
return true;
|
||||
},
|
||||
|
||||
[id, type],
|
||||
);
|
||||
|
||||
// const renderDetailFooter = () => {
|
||||
// if (type === "update") {
|
||||
// return (
|
||||
// <Space>
|
||||
// <Button onClick={() => detailRef.current?.close()}>取消</Button>
|
||||
// <Button type="primary" onClick={handleEditSubmit}>
|
||||
// 确定
|
||||
// </Button>
|
||||
// </Space>
|
||||
// );
|
||||
// } else {
|
||||
// return (
|
||||
// <Button type="primary" onClick={() => detailRef.current?.close()}>
|
||||
// 确定
|
||||
// </Button>
|
||||
// );
|
||||
// }
|
||||
// };
|
||||
const itemsMenu = (row: Prod): MenuProps['items'] => [
|
||||
{
|
||||
key: 'edit',
|
||||
label: (
|
||||
<Button type="link" onClick={() => handleEdit(row)}>
|
||||
商品编辑
|
||||
</Button>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'sku',
|
||||
label: <Button type="link">SKU管理</Button>,
|
||||
},
|
||||
{
|
||||
key: 'rules-service',
|
||||
label: <Button type="link">服务规则编辑</Button>,
|
||||
},
|
||||
{
|
||||
key: 'extend-service',
|
||||
label: <Button type="link">扩展服务管理</Button>,
|
||||
},
|
||||
{
|
||||
key: 'status',
|
||||
label: <Button type="link">状态控制</Button>,
|
||||
},
|
||||
{
|
||||
key: 'delete',
|
||||
label: (
|
||||
<Button color="danger" variant="link">
|
||||
删除商品
|
||||
</Button>
|
||||
),
|
||||
},
|
||||
];
|
||||
const actionColumns: ProColumns<Prod> = {
|
||||
title: '操作',
|
||||
dataIndex: 'option',
|
||||
valueType: 'option',
|
||||
fixed: 'right',
|
||||
align: 'center',
|
||||
|
||||
width: 200,
|
||||
render: (_text: React.ReactNode, record: Prod, _: number) => [
|
||||
<Space style={{ width: '100%' }} wrap size={0} key={record.prodId}>
|
||||
<Space.Compact direction="vertical" block key="1">
|
||||
<Button type="link" onClick={() => handleEdit(record)}>
|
||||
商品编辑
|
||||
</Button>
|
||||
<Button type="link">SKU管理</Button>
|
||||
</Space.Compact>
|
||||
<Space.Compact direction="vertical" block key="2">
|
||||
<Button type="link">服务规则</Button>
|
||||
<Button type="link">扩展服务</Button>
|
||||
</Space.Compact>
|
||||
<Space.Compact direction="vertical" block key="3">
|
||||
<Dropdown menu={{ items: itemsMenu(record) }} placement="bottomLeft">
|
||||
<Button type="link">
|
||||
<EllipsisOutlined />
|
||||
</Button>
|
||||
</Dropdown>
|
||||
</Space.Compact>
|
||||
</Space>,
|
||||
],
|
||||
};
|
||||
|
||||
const columns = [...baseTenantColumns, actionColumns];
|
||||
const renderChildren = () => {
|
||||
return (
|
||||
<>
|
||||
<EnhancedProTable<Prod>
|
||||
ref={tableRef}
|
||||
columns={columns}
|
||||
request={onFetch}
|
||||
toolbarActions={toolbarActions}
|
||||
headerTitle="短信渠道"
|
||||
showIndex={false}
|
||||
rowKey="prodId"
|
||||
showSelection={false}
|
||||
/>
|
||||
|
||||
<ConfigurableDrawerForm
|
||||
ref={detailRef}
|
||||
onSubmit={handleSubmit}
|
||||
// footer={renderDetailFooter()}
|
||||
title={formStatusType[type]}
|
||||
width={'80vw'}
|
||||
bodyStyle={{
|
||||
background: '#f5f5f5',
|
||||
paddingTop: 8,
|
||||
}}
|
||||
>
|
||||
<ProdDetail />
|
||||
</ConfigurableDrawerForm>
|
||||
{/* <ConfigurableDrawerForm
|
||||
ref={editRef}
|
||||
onSubmit={handleEditSubmit}
|
||||
footer={renderDetailFooter()}
|
||||
width={"80vw"}
|
||||
bodyStyle={{
|
||||
background: "#f5f5f5",
|
||||
paddingTop: 8,
|
||||
}}
|
||||
>
|
||||
<ProdDetail />
|
||||
</ConfigurableDrawerForm> */}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const items: TabsProps['items'] = [
|
||||
{
|
||||
key: '',
|
||||
label: '全部商品',
|
||||
children: renderChildren(),
|
||||
},
|
||||
{
|
||||
key: '1',
|
||||
label: '出售中的商品',
|
||||
children: renderChildren(),
|
||||
},
|
||||
{
|
||||
key: '0',
|
||||
label: '仓库中的商品',
|
||||
children: renderChildren(),
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
label: '待审核的商品',
|
||||
children: renderChildren(),
|
||||
},
|
||||
];
|
||||
return (
|
||||
<Tabs
|
||||
defaultActiveKey={status as unknown as string}
|
||||
items={items}
|
||||
onChange={onChange}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProdList;
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
// src/pages/system/menu/index.tsx
|
||||
|
||||
import { PlusOutlined, ReloadOutlined } from '@ant-design/icons';
|
||||
import {
|
||||
ExclamationCircleOutlined,
|
||||
PlusOutlined,
|
||||
ReloadOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import type { ActionType, ProColumns } from '@ant-design/pro-components';
|
||||
import { useModel } from '@umijs/max';
|
||||
import { Modal, Popconfirm } from 'antd';
|
||||
@@ -11,8 +15,6 @@ import ConfigurableDrawerForm, {
|
||||
import EnhancedProTable from '@/components/EnhancedProTable';
|
||||
import type { ToolbarAction } from '@/components/EnhancedProTable/types';
|
||||
import { formStatusType } from '@/constants';
|
||||
import { useMessage } from '@/hooks/antd/useMessage';
|
||||
import { CACHE_KEY, useCache } from '@/hooks/web/useCache';
|
||||
import {
|
||||
createMenu,
|
||||
deleteMenu,
|
||||
@@ -27,11 +29,10 @@ import { baseMenuColumns, formColumns } from './config';
|
||||
const SystemMenu = () => {
|
||||
const configurableDrawerRef = useRef<ConfigurableDrawerFormRef>(null);
|
||||
const tableRef = useRef<ActionType>(null);
|
||||
const { wsCache } = useCache();
|
||||
const message = useMessage(); // 消息弹窗
|
||||
const [modal, contextHolder] = Modal.useModal();
|
||||
const [type, setType] = useState<'create' | 'update'>('create');
|
||||
const [id, setId] = useState<number>(0);
|
||||
const { initialState, setInitialState } = useModel('@@initialState');
|
||||
const { initialState } = useModel('@@initialState');
|
||||
const handleEdit = (record: MenuVO) => {
|
||||
setType('update');
|
||||
setId(record.id);
|
||||
@@ -56,13 +57,18 @@ const SystemMenu = () => {
|
||||
|
||||
const handleReload = async () => {
|
||||
try {
|
||||
await message.confirm('即将更新缓存刷新浏览器!', '刷新菜单缓存');
|
||||
// 清空,从而触发刷新
|
||||
// wsCache.delete(CACHE_KEY.USER);
|
||||
// wsCache.delete(CACHE_KEY.ROLE_ROUTERS);
|
||||
await initialState?.fetchUserInfo?.();
|
||||
// 刷新浏览器
|
||||
location.reload();
|
||||
await modal.confirm({
|
||||
title: '刷新菜单缓存',
|
||||
icon: <ExclamationCircleOutlined />,
|
||||
content: '即将更新缓存刷新浏览器!',
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
onOk: async () => {
|
||||
await initialState?.fetchUserInfo?.();
|
||||
// 刷新浏览器
|
||||
location.reload();
|
||||
},
|
||||
});
|
||||
} catch {}
|
||||
};
|
||||
|
||||
@@ -126,6 +132,7 @@ const SystemMenu = () => {
|
||||
const columns = [...baseMenuColumns, actionColumns];
|
||||
return (
|
||||
<>
|
||||
{contextHolder}
|
||||
<EnhancedProTable<MenuVO>
|
||||
ref={tableRef}
|
||||
columns={columns}
|
||||
|
||||
@@ -1,43 +1,52 @@
|
||||
import type { ProColumns } from '@ant-design/pro-components';
|
||||
import { Button, Space, Tag, Typography } from 'antd';
|
||||
import dayjs from 'dayjs';
|
||||
import { dateFormat, dateFormatS } from '@/constants';
|
||||
import { Image, Space, Tag, Typography } from 'antd';
|
||||
import type { TradeOrderPageRespVO } from '@/services/trade/order';
|
||||
|
||||
const { Text, Paragraph } = Typography;
|
||||
export const baseOrderColumns: ProColumns<TradeOrderPageRespVO>[] = [
|
||||
{
|
||||
title: '商品',
|
||||
dataIndex: 'spuName',
|
||||
dataIndex: 'items',
|
||||
hideInSearch: true,
|
||||
width: '100%',
|
||||
ellipsis: true,
|
||||
render: (_, record) => (
|
||||
<Paragraph>
|
||||
<Paragraph ellipsis style={{ marginBottom: 0 }}>
|
||||
{record.spuName}
|
||||
</Paragraph>
|
||||
<div>{record.skuName}</div>
|
||||
<Space>
|
||||
<div>
|
||||
<Text type="secondary">数量:</Text>
|
||||
<Text>{record.count}</Text>
|
||||
render: (_, record) => {
|
||||
if (!record.items) {
|
||||
return _;
|
||||
}
|
||||
return record.items.map((item) => (
|
||||
<div
|
||||
style={{ width: '100%', display: 'flex', gap: '8px' }}
|
||||
key={item.id}
|
||||
>
|
||||
<Image src={item.picUrl} width={64} height={64} />
|
||||
<div style={{ flex: '1', overflow: 'hidden' }}>
|
||||
<Paragraph ellipsis style={{ width: '100%', marginBottom: 0 }}>
|
||||
{item.spuName}测试商品名称测试商品名称测试商品名称测试商品名称
|
||||
</Paragraph>
|
||||
<div>{item.skuName}</div>
|
||||
<Space>
|
||||
<div>
|
||||
<Text type="secondary">数量:</Text>
|
||||
<Text>{item.count || 0}</Text>
|
||||
</div>
|
||||
<div>
|
||||
<Text type="secondary">单价:</Text>
|
||||
<Text>
|
||||
{item.price || 0}/{item.unit || '-'}
|
||||
</Text>
|
||||
</div>
|
||||
<div>
|
||||
<Text type="secondary">到手价:</Text>
|
||||
<Text>
|
||||
{item.handedPrice || 0}/{item.unit || '-'}
|
||||
</Text>
|
||||
</div>
|
||||
</Space>
|
||||
</div>
|
||||
<div>
|
||||
<Text type="secondary">单价:</Text>
|
||||
<Text>
|
||||
{record.price}/{record.unit}
|
||||
</Text>
|
||||
</div>
|
||||
<div>
|
||||
<Text type="secondary">到手价:</Text>
|
||||
<Text>
|
||||
{record.handedPrice}/{record.unit}
|
||||
</Text>
|
||||
</div>
|
||||
</Space>
|
||||
</Paragraph>
|
||||
),
|
||||
</div>
|
||||
));
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
@@ -50,7 +59,7 @@ export const baseOrderColumns: ProColumns<TradeOrderPageRespVO>[] = [
|
||||
<Space direction="vertical" style={{ width: '100%' }}>
|
||||
<Paragraph ellipsis style={{ marginBottom: 0 }}>
|
||||
<Text type="secondary">预约时间:</Text>
|
||||
<Text>{dayjs(record.subTime).format(dateFormatS)}</Text>
|
||||
<Text>{record?.subTime || '-'}</Text>
|
||||
<Tag style={{ marginLeft: 10 }}>预约</Tag>
|
||||
<Tag color="error" style={{ marginLeft: 10 }}>
|
||||
加急
|
||||
@@ -58,14 +67,11 @@ export const baseOrderColumns: ProColumns<TradeOrderPageRespVO>[] = [
|
||||
</Paragraph>
|
||||
<Paragraph ellipsis style={{ marginBottom: 0 }}>
|
||||
<Text type="secondary">服务地址:</Text>
|
||||
<Text>
|
||||
{record.serveAddress}
|
||||
服务地址:服务地址:服务地址:服务地址:服务地址:服务地址:
|
||||
</Text>
|
||||
<Text>{record.serveAddress || '-'}</Text>
|
||||
</Paragraph>
|
||||
<div>
|
||||
<Text type="secondary">用户备注:</Text>
|
||||
<Text>{record.userRemark}</Text>
|
||||
<Text>{record.userRemark || '-'}</Text>
|
||||
</div>
|
||||
</Space>
|
||||
),
|
||||
@@ -74,20 +80,20 @@ export const baseOrderColumns: ProColumns<TradeOrderPageRespVO>[] = [
|
||||
title: '财务',
|
||||
dataIndex: 'price',
|
||||
hideInSearch: true,
|
||||
width: '100',
|
||||
width: '100%',
|
||||
render: (_, record) => (
|
||||
<Space direction="vertical">
|
||||
<div>
|
||||
<Text type="secondary">实付金额:</Text>
|
||||
<Text>{record.payPrice}</Text>
|
||||
<Text>{record?.payPrice || '-'}</Text>
|
||||
</div>
|
||||
<div>
|
||||
<Text type="secondary">支付方式:</Text>
|
||||
<Text>{record.payType}</Text>
|
||||
<Text>{record.payType || '-'}</Text>
|
||||
</div>
|
||||
<div>
|
||||
<Text type="secondary">财务状态:</Text>
|
||||
<Text>{record.financeStatus}</Text>
|
||||
<Text>{record.financeStatus || '-'}</Text>
|
||||
</div>
|
||||
</Space>
|
||||
),
|
||||
|
||||
@@ -1,23 +1,36 @@
|
||||
import { ProCard } from '@ant-design/pro-components';
|
||||
import { Avatar, Button, Card, Empty, Space, Steps, Typography } from 'antd';
|
||||
import {
|
||||
Avatar,
|
||||
Button,
|
||||
Card,
|
||||
Divider,
|
||||
Empty,
|
||||
Space,
|
||||
Steps,
|
||||
Typography,
|
||||
} from 'antd';
|
||||
import dayjs from 'dayjs';
|
||||
import RcResizeObserver from 'rc-resize-observer';
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { OrderStatus, OrderStatusLabels } from '@/constants/trade';
|
||||
import type { TradeOrderBaseInfo } from '@/services/trade/order';
|
||||
import type {
|
||||
TradeOrderDetailRespVO,
|
||||
TradeOrderStatusRespVo,
|
||||
} from '@/services/trade/order/detail';
|
||||
import type { ItemConfig } from '../../order-info';
|
||||
import { type BtnType, renderBaseInfoOrder } from './config';
|
||||
import styles from './index.module.less';
|
||||
|
||||
const { Title, Text } = Typography;
|
||||
const BasicInfo: React.FC<{ data?: TradeOrderBaseInfo; id: number }> = (
|
||||
props,
|
||||
) => {
|
||||
const { data } = props;
|
||||
const { Text } = Typography;
|
||||
const BasicInfo: React.FC<ItemConfig<TradeOrderDetailRespVO>> = (props) => {
|
||||
const { data, loading } = props;
|
||||
const [orderStatus, setOrderStatus] = useState<number>(0);
|
||||
const [statusList, setStatusList] = useState<TradeOrderStatusRespVo[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (data) {
|
||||
setOrderStatus(Number(data.orderStatus));
|
||||
setStatusList(data?.statusList || []);
|
||||
}
|
||||
}, [data]);
|
||||
|
||||
@@ -27,22 +40,24 @@ const BasicInfo: React.FC<{ data?: TradeOrderBaseInfo; id: number }> = (
|
||||
<Space size={16}>
|
||||
<div>
|
||||
<Text type="secondary">订单编号:</Text>
|
||||
<Text copyable>{data?.orderNo}</Text>
|
||||
<Text copyable>{data?.orderNum}</Text>
|
||||
</div>
|
||||
<div>
|
||||
<Text type="secondary">订单类目:</Text>
|
||||
<Text>{data?.orderCategoryId}</Text>
|
||||
<Text>{data?.orderCategoryName}</Text>
|
||||
<Text>ID:</Text>
|
||||
<Text copyable>{data?.id}</Text>
|
||||
<Divider type="vertical" />
|
||||
<Text copyable>{data?.orderCategoryId}</Text>
|
||||
</div>
|
||||
<div>
|
||||
<Text type="secondary">订单来源:</Text>
|
||||
<Text>{data?.orderCategoryName}</Text>
|
||||
<Text>{data?.orderTerminal}</Text>
|
||||
</div>
|
||||
<div>
|
||||
<Space>
|
||||
<Avatar size={20} src={data?.userAvatar} />
|
||||
<Text>{data?.userInfo}</Text>
|
||||
</div>
|
||||
<Text>{data?.userName || data?.userNickName}</Text>
|
||||
<Text>{data?.userMobile}</Text>
|
||||
</Space>
|
||||
</Space>
|
||||
);
|
||||
}, [data]);
|
||||
@@ -65,128 +80,184 @@ const BasicInfo: React.FC<{ data?: TradeOrderBaseInfo; id: number }> = (
|
||||
|
||||
return (
|
||||
<div className={styles['order-info']}>
|
||||
<Card title="基本信息">
|
||||
{data ? (
|
||||
<Card title="基本信息" loading={loading}>
|
||||
<Space direction="vertical" size={16} style={{ width: '100%' }}>
|
||||
{data ? (
|
||||
<ProCard
|
||||
size="small"
|
||||
title={renderTitle()}
|
||||
bordered
|
||||
headerBordered
|
||||
gutter={8}
|
||||
className="order-info-card"
|
||||
>
|
||||
<ProCard colSpan="300px">
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: 10,
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
{renderOrderStatus}
|
||||
</div>
|
||||
</ProCard>
|
||||
<ProCard layout="center">
|
||||
<RcResizeObserver
|
||||
key="resize-observer"
|
||||
onResize={(offset) => {
|
||||
setResponsive(offset.width < 460);
|
||||
}}
|
||||
>
|
||||
<Steps
|
||||
size="small"
|
||||
progressDot
|
||||
style={{ width: '100%' }}
|
||||
current={statusList.length}
|
||||
direction={responsive ? 'vertical' : 'horizontal'}
|
||||
items={[
|
||||
{
|
||||
title: `创建订单`,
|
||||
description: (
|
||||
<Space direction="vertical" size={0}>
|
||||
{dayjs(data.createTime).format('YYYY-MM-DD')}
|
||||
{dayjs(data.createTime).format('HH:mm:ss')}
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: `${
|
||||
OrderStatusLabels[OrderStatus.PendingPayment].label
|
||||
} ${
|
||||
orderStatus > OrderStatus.PendingPayment
|
||||
? '(已付款)'
|
||||
: ''
|
||||
}`,
|
||||
description: (
|
||||
<Space direction="vertical" size={0}>
|
||||
{dayjs(data.createTime).format('YYYY-MM-DD')}
|
||||
{dayjs(data.createTime).format('HH:mm:ss')}
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: `${
|
||||
OrderStatusLabels[OrderStatus.PendingConfirmation]
|
||||
.label
|
||||
} ${
|
||||
orderStatus > OrderStatus.PendingConfirmation
|
||||
? '(已确定)'
|
||||
: ''
|
||||
}`,
|
||||
description: (
|
||||
<Space direction="vertical" size={0}>
|
||||
{/* {dayjs(data.finishTime).format("YYYY-MM-DD")}
|
||||
{dayjs(data.finishTime).format("HH:mm:ss")} */}
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: `${
|
||||
OrderStatusLabels[OrderStatus.PendingService].label
|
||||
} ${
|
||||
orderStatus > OrderStatus.PendingService
|
||||
? '(已开始)'
|
||||
: ''
|
||||
}`,
|
||||
description: (
|
||||
<Space direction="vertical" size={0}>
|
||||
{/* {dayjs(data.finishTime).format("YYYY-MM-DD")}
|
||||
{dayjs(data.finishTime).format("HH:mm:ss")} */}
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: `${
|
||||
OrderStatusLabels[OrderStatus.PendingAcceptance].label
|
||||
} ${
|
||||
orderStatus > OrderStatus.PendingAcceptance
|
||||
? '(已验收)'
|
||||
: ''
|
||||
}`,
|
||||
description: (
|
||||
<Space direction="vertical" size={0}>
|
||||
{/* {dayjs(data.finishTime).format("YYYY-MM-DD")}
|
||||
{dayjs(data.finishTime).format("HH:mm:ss")} */}
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '完成',
|
||||
description: (
|
||||
<Space direction="vertical" size={0}>
|
||||
{dayjs(data.finishTime).format('YYYY-MM-DD')}
|
||||
{dayjs(data.finishTime).format('HH:mm:ss')}
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</RcResizeObserver>
|
||||
</ProCard>
|
||||
</ProCard>
|
||||
) : (
|
||||
<Empty />
|
||||
)}
|
||||
<ProCard
|
||||
size="small"
|
||||
title={renderTitle()}
|
||||
bordered
|
||||
headerBordered
|
||||
title="订单付款信息"
|
||||
gutter={8}
|
||||
className="order-info-card"
|
||||
extra={<Button size="small">财务状态:{data?.financeStatus}</Button>}
|
||||
>
|
||||
<ProCard colSpan="300px">
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: 10,
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
{renderOrderStatus}
|
||||
</div>
|
||||
<ProCard>
|
||||
<Space direction="vertical">
|
||||
<div>
|
||||
<Text type="secondary">订单总价:</Text>
|
||||
<Text>{data?.price}</Text>
|
||||
</div>
|
||||
<div>
|
||||
<Text type="secondary">优惠总额:</Text>
|
||||
<Text>{data?.discountPrice}</Text>
|
||||
</div>
|
||||
<div>
|
||||
<Text type="secondary">实付金额:</Text>
|
||||
<Text>{data?.payPrice}</Text>
|
||||
</div>
|
||||
<div>
|
||||
<Text type="secondary">累计退款金额:</Text>
|
||||
<Text>{data?.refundPrice}</Text>
|
||||
</div>
|
||||
<div>
|
||||
<Text type="secondary">最终实收金额:</Text>
|
||||
<Text>{data?.livePrice}</Text>
|
||||
</div>
|
||||
</Space>
|
||||
</ProCard>
|
||||
<ProCard layout="center">
|
||||
<RcResizeObserver
|
||||
key="resize-observer"
|
||||
onResize={(offset) => {
|
||||
setResponsive(offset.width < 460);
|
||||
}}
|
||||
>
|
||||
<Steps
|
||||
size="small"
|
||||
progressDot
|
||||
style={{ width: '100%' }}
|
||||
current={orderStatus / 10}
|
||||
direction={responsive ? 'vertical' : 'horizontal'}
|
||||
items={[
|
||||
{
|
||||
title: `创建订单`,
|
||||
description: (
|
||||
<Space direction="vertical" size={0}>
|
||||
{dayjs(data.createTime).format('YYYY-MM-DD')}
|
||||
{dayjs(data.createTime).format('HH:mm:ss')}
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: `${
|
||||
OrderStatusLabels[OrderStatus.PendingPayment].label
|
||||
} ${
|
||||
orderStatus > OrderStatus.PendingPayment
|
||||
? '(已付款)'
|
||||
: ''
|
||||
}`,
|
||||
description: (
|
||||
<Space direction="vertical" size={0}>
|
||||
{dayjs(data.createTime).format('YYYY-MM-DD')}
|
||||
{dayjs(data.createTime).format('HH:mm:ss')}
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: `${
|
||||
OrderStatusLabels[OrderStatus.PendingConfirmation].label
|
||||
} ${
|
||||
orderStatus > OrderStatus.PendingConfirmation
|
||||
? '(已确定)'
|
||||
: ''
|
||||
}`,
|
||||
description: (
|
||||
<Space direction="vertical" size={0}>
|
||||
{/* {dayjs(data.finishTime).format("YYYY-MM-DD")}
|
||||
{dayjs(data.finishTime).format("HH:mm:ss")} */}
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: `${
|
||||
OrderStatusLabels[OrderStatus.PendingService].label
|
||||
} ${
|
||||
orderStatus > OrderStatus.PendingService
|
||||
? '(已开始)'
|
||||
: ''
|
||||
}`,
|
||||
description: (
|
||||
<Space direction="vertical" size={0}>
|
||||
{/* {dayjs(data.finishTime).format("YYYY-MM-DD")}
|
||||
{dayjs(data.finishTime).format("HH:mm:ss")} */}
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: `${
|
||||
OrderStatusLabels[OrderStatus.PendingAcceptance].label
|
||||
} ${
|
||||
orderStatus > OrderStatus.PendingAcceptance
|
||||
? '(已验收)'
|
||||
: ''
|
||||
}`,
|
||||
description: (
|
||||
<Space direction="vertical" size={0}>
|
||||
{/* {dayjs(data.finishTime).format("YYYY-MM-DD")}
|
||||
{dayjs(data.finishTime).format("HH:mm:ss")} */}
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '完成',
|
||||
description: (
|
||||
<Space direction="vertical" size={0}>
|
||||
{dayjs(data.finishTime).format('YYYY-MM-DD')}
|
||||
{dayjs(data.finishTime).format('HH:mm:ss')}
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</RcResizeObserver>
|
||||
<ProCard>
|
||||
<Space direction="vertical">
|
||||
<div>
|
||||
<Text type="secondary">支付方式:</Text>
|
||||
<Text>{data?.payType}</Text>
|
||||
</div>
|
||||
<div>
|
||||
<Text type="secondary">支付渠道:</Text>
|
||||
<Text>{data?.payChannelCode}</Text>
|
||||
</div>
|
||||
<div>
|
||||
<Text type="secondary">支付时间:</Text>
|
||||
<Text>{data?.payTime}</Text>
|
||||
</div>
|
||||
<div>
|
||||
<Text type="secondary">交易流水:</Text>
|
||||
<Text>{data?.payOrderId}</Text>
|
||||
</div>
|
||||
</Space>
|
||||
</ProCard>
|
||||
</ProCard>
|
||||
) : (
|
||||
<Empty />
|
||||
)}
|
||||
</Space>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -9,30 +9,10 @@ import {
|
||||
OrderStatusLabels,
|
||||
} from '@/constants/trade';
|
||||
import type { DeptVO } from '@/services/system/dept';
|
||||
import type { TradeOrderBaseInfo } from '@/services/trade/order';
|
||||
import type { TradeOrderDetailRespVO } from '@/services/trade/order';
|
||||
|
||||
const { Title, Text, Paragraph } = Typography;
|
||||
|
||||
export const baseOrderColumns: ProColumns<DeptVO>[] = [
|
||||
{
|
||||
title: '商品',
|
||||
dataIndex: 'name',
|
||||
width: '33.33%',
|
||||
render: (_, record) => (
|
||||
<Tag color={record.status === 1 ? 'green' : 'red'}>{record.name}</Tag>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '服务',
|
||||
dataIndex: 'leaderUserId',
|
||||
hideInSearch: true,
|
||||
},
|
||||
{
|
||||
title: '财务',
|
||||
dataIndex: 'sort',
|
||||
hideInSearch: true,
|
||||
},
|
||||
];
|
||||
const sharedOnCell = (_: DeptVO, index?: number) => {
|
||||
if (index === 3) {
|
||||
return { colSpan: 0 };
|
||||
@@ -77,17 +57,17 @@ export const surchargeInfoColumns: ProColumns<DeptVO>[] = [
|
||||
export type BtnType = 'sales' | 'confirm';
|
||||
|
||||
export const renderBaseInfoOrder = (
|
||||
data: TradeOrderBaseInfo,
|
||||
data: TradeOrderDetailRespVO,
|
||||
handleClick: (type: BtnType) => void,
|
||||
): React.ReactNode => {
|
||||
const orderStatusObj =
|
||||
OrderStatusLabels[data.orderStatus as unknown as OrderStatus];
|
||||
const orderStatusObj = data.orderStatus
|
||||
? OrderStatusLabels[data.orderStatus as unknown as OrderStatus]
|
||||
: { color: 'default', label: '未知' };
|
||||
|
||||
console.log(orderStatusObj, data);
|
||||
return (
|
||||
<>
|
||||
<Title
|
||||
type={(orderStatusObj.color as BaseType) || ''}
|
||||
type={(orderStatusObj?.color as BaseType) || ''}
|
||||
level={4}
|
||||
style={{ margin: 0 }}
|
||||
>
|
||||
@@ -101,7 +81,7 @@ export const renderBaseInfoOrder = (
|
||||
Number(data.orderStatus) === OrderStatus.Refunded && (
|
||||
<Paragraph>
|
||||
<Text type="secondary">退款时间:</Text>
|
||||
<Text>退款时间</Text>
|
||||
<Text>{data.refundTime}</Text>
|
||||
</Paragraph>
|
||||
)}
|
||||
{data.orderStatus &&
|
||||
|
||||
20
src/pages/trade/order/detail/component/info/extend-cost.tsx
Normal file
20
src/pages/trade/order/detail/component/info/extend-cost.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
import { Card } from 'antd';
|
||||
import React from 'react';
|
||||
import type { TradeExtendCostInfo } from '@/services/trade/order/detail';
|
||||
import type { ItemConfig } from '../../order-info';
|
||||
import styles from './index.module.less';
|
||||
import ExtendCost from './uis/pets/extend-cost';
|
||||
|
||||
const EntendCostInfo: React.FC<ItemConfig<TradeExtendCostInfo[]>> = (props) => {
|
||||
const { data = [], orderCategoryId } = props;
|
||||
|
||||
return (
|
||||
<div className={styles['order-info']}>
|
||||
<Card title="服务信息">
|
||||
{orderCategoryId === 1 && <ExtendCost data={data} />}
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(EntendCostInfo);
|
||||
@@ -0,0 +1,18 @@
|
||||
import React from 'react';
|
||||
import type { TradeExtendServeInfo } from '@/services/trade/order/detail';
|
||||
import type { ItemConfig } from '../../order-info';
|
||||
import styles from './index.module.less';
|
||||
import ExtendServicePets from './uis/pets/extend-service';
|
||||
|
||||
const ExtendService: React.FC<ItemConfig<TradeExtendServeInfo[][]>> = (
|
||||
props,
|
||||
) => {
|
||||
const { data = [], orderCategoryId } = props;
|
||||
return (
|
||||
<div className={styles['order-info']}>
|
||||
{orderCategoryId === 1 && <ExtendServicePets data={data} />}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(ExtendService);
|
||||
@@ -2,6 +2,7 @@
|
||||
:global {
|
||||
.ant-pro-card-header {
|
||||
background: rgba(0, 0, 0, 0.02);
|
||||
min-height: 41px;
|
||||
}
|
||||
.ant-pro-card-col {
|
||||
flex: 1 auto;
|
||||
@@ -21,10 +22,13 @@
|
||||
.ant-pro-card-body {
|
||||
padding: 0px;
|
||||
}
|
||||
.ant-steps-item-icon {
|
||||
height: 8px !important;
|
||||
line-height: 8px !important;
|
||||
.ant-steps-dot {
|
||||
.ant-steps-item-icon {
|
||||
height: 8px !important;
|
||||
line-height: 8px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-steps-item-active {
|
||||
.ant-steps-icon-dot {
|
||||
height: 10px !important;
|
||||
|
||||
@@ -1,24 +1,25 @@
|
||||
import { ProCard } from '@ant-design/pro-components';
|
||||
import { Button, Card, Image, Space, Tag, Typography } from 'antd';
|
||||
import React, { useCallback } from 'react';
|
||||
import type { TradeProductInfo } from '@/services/trade/order';
|
||||
|
||||
import { fallback } from '@/constants/antd/image';
|
||||
import type { Item } from '@/services/trade/order/detail';
|
||||
import type { ItemConfig } from '../../order-info';
|
||||
import styles from './index.module.less';
|
||||
|
||||
const { Text, Paragraph } = Typography;
|
||||
const ProdInfo: React.FC<{ data?: TradeProductInfo; id: number }> = (props) => {
|
||||
const { data = {}, id } = props;
|
||||
const renderTitle = useCallback(() => {
|
||||
const ProdInfo: React.FC<ItemConfig<Item[]>> = (props) => {
|
||||
const { data = [] } = props;
|
||||
const renderTitle = useCallback((item: Item) => {
|
||||
return (
|
||||
<Space style={{ height: '100%' }} size={16}>
|
||||
<Paragraph className="order-paragraph">百业到家</Paragraph>
|
||||
<Paragraph className="order-paragraph">{item.shopName}</Paragraph>
|
||||
<Paragraph className="order-paragraph">
|
||||
<Text type="secondary"> 商品 ID:</Text>
|
||||
<Text copyable>8877777</Text>
|
||||
<Text copyable>{item.spuId}</Text>
|
||||
</Paragraph>
|
||||
<Paragraph className="order-paragraph">
|
||||
<Text type="secondary">SKU ID:</Text>
|
||||
<Text copyable>8877777</Text>
|
||||
<Text copyable>{item.skuId}</Text>
|
||||
</Paragraph>
|
||||
</Space>
|
||||
);
|
||||
@@ -26,109 +27,119 @@ const ProdInfo: React.FC<{ data?: TradeProductInfo; id: number }> = (props) => {
|
||||
return (
|
||||
<div className={styles['order-info']}>
|
||||
<Card title="商品信息">
|
||||
<ProCard
|
||||
size="small"
|
||||
title={renderTitle()}
|
||||
bordered
|
||||
headerBordered
|
||||
gutter={8}
|
||||
extra={<Button size="small">交易快照</Button>}
|
||||
>
|
||||
{data?.map((item) => (
|
||||
<ProCard
|
||||
layout="default"
|
||||
colSpan={'50%'}
|
||||
style={{ borderRight: '1px solid rgba(5,5,5,0.06)' }}
|
||||
key={item.id}
|
||||
size="small"
|
||||
title={renderTitle(item)}
|
||||
bordered
|
||||
headerBordered
|
||||
gutter={8}
|
||||
extra={<Button size="small">交易快照</Button>}
|
||||
>
|
||||
<Space>
|
||||
<Image
|
||||
width={64}
|
||||
src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"
|
||||
/>
|
||||
<div>
|
||||
<Text>商品名称</Text>
|
||||
<Paragraph className="order-paragraph">
|
||||
<Text>规格:</Text>
|
||||
<Text type="secondary"> 标准,单独火化,基础清洁</Text>
|
||||
</Paragraph>
|
||||
<Space wrap size={0} direction="horizontal">
|
||||
<Paragraph
|
||||
className="order-paragraph"
|
||||
style={{ marginRight: 16 }}
|
||||
>
|
||||
<Text type="secondary">数量:</Text>
|
||||
<Text> 1</Text>
|
||||
</Paragraph>
|
||||
<Paragraph
|
||||
className="order-paragraph"
|
||||
style={{ marginRight: 16 }}
|
||||
>
|
||||
<Text type="secondary">单价:</Text>
|
||||
<Text> ¥100 件</Text>
|
||||
</Paragraph>
|
||||
<Paragraph
|
||||
className="order-paragraph"
|
||||
style={{ marginRight: 16 }}
|
||||
>
|
||||
<Text type="secondary">到手价:</Text>
|
||||
<Text> ¥80 件</Text>
|
||||
</Paragraph>
|
||||
<ProCard
|
||||
layout="default"
|
||||
colSpan={'50%'}
|
||||
style={{ borderRight: '1px solid rgba(5,5,5,0.06)' }}
|
||||
>
|
||||
<Space>
|
||||
<Image width={64} src={item.shopLogo} fallback={fallback} />
|
||||
<div>
|
||||
<Text>{item.shopName}</Text>
|
||||
<Paragraph className="order-paragraph">
|
||||
<Text type="secondary">成本价:</Text>
|
||||
<Text> ¥50 件/-</Text>
|
||||
<Text>规格:</Text>
|
||||
<Text type="secondary"> {item.skuName}</Text>
|
||||
</Paragraph>
|
||||
</Space>
|
||||
</div>
|
||||
</Space>
|
||||
<Paragraph style={{ marginTop: 16 }}>
|
||||
<Tag>标签</Tag>
|
||||
<Tag>标签</Tag>
|
||||
<Tag>标签</Tag>
|
||||
<Tag>标签</Tag>
|
||||
<Tag>标签</Tag>
|
||||
</Paragraph>
|
||||
<Paragraph className="order-paragraph">
|
||||
<Text type="secondary">商品描述:</Text>
|
||||
<Paragraph className="order-paragraph">
|
||||
商品描述商品描述商品描述商品描述商品描述商品描述商品描述商品描述商品描述商品描述商品描述商品描述商品描述商品描述商品描述商品描述商品描述商品描述商品描述商品描述商品描述商品描述商品描述商品描述商品描述商品描述商品描述商品描述商品描述商品描述商品描述商品描述商品描述商品描述商品描述商品描述商品描述商品描述商品描述商品描述商品描述商品描述商品描述商品
|
||||
<Space wrap size={0} direction="horizontal">
|
||||
<Paragraph
|
||||
className="order-paragraph"
|
||||
style={{ marginRight: 16 }}
|
||||
>
|
||||
<Text type="secondary">数量:</Text>
|
||||
<Text> {item.count}</Text>
|
||||
</Paragraph>
|
||||
<Paragraph
|
||||
className="order-paragraph"
|
||||
style={{ marginRight: 16 }}
|
||||
>
|
||||
<Text type="secondary">单价:</Text>
|
||||
<Text>
|
||||
¥{item.price}
|
||||
{item.unit}
|
||||
</Text>
|
||||
</Paragraph>
|
||||
<Paragraph
|
||||
className="order-paragraph"
|
||||
style={{ marginRight: 16 }}
|
||||
>
|
||||
<Text type="secondary">到手价:</Text>
|
||||
<Text>
|
||||
{' '}
|
||||
¥{item.handedPrice} {item.unit}
|
||||
</Text>
|
||||
</Paragraph>
|
||||
<Paragraph className="order-paragraph">
|
||||
<Text type="secondary">成本价:</Text>
|
||||
<Text>
|
||||
{' '}
|
||||
¥{item.expensePrice} {item.unit}/-
|
||||
</Text>
|
||||
</Paragraph>
|
||||
</Space>
|
||||
</div>
|
||||
</Space>
|
||||
<Paragraph style={{ marginTop: 16 }}>
|
||||
{item.properties}
|
||||
<Tag>标签</Tag>
|
||||
<Tag>标签</Tag>
|
||||
<Tag>标签</Tag>
|
||||
<Tag>标签</Tag>
|
||||
<Tag>标签</Tag>
|
||||
</Paragraph>
|
||||
</Paragraph>
|
||||
<Paragraph className="order-paragraph">
|
||||
<Text type="secondary">商品描述:</Text>
|
||||
<Paragraph className="order-paragraph">
|
||||
{item.serveContent}
|
||||
</Paragraph>
|
||||
</Paragraph>
|
||||
</ProCard>
|
||||
<ProCard
|
||||
style={{
|
||||
borderRight: '1px solid rgba(5,5,5,0.06)',
|
||||
height: '100%',
|
||||
}}
|
||||
>
|
||||
<Space direction="vertical">
|
||||
<Text>付款信息</Text>
|
||||
<Paragraph className="order-paragraph">
|
||||
<Text type="secondary">商品总价:</Text>
|
||||
<Text>¥500</Text>
|
||||
</Paragraph>
|
||||
<Paragraph className="order-paragraph">
|
||||
<Text type="secondary">商品总价:</Text>
|
||||
<Text>¥500</Text>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Text type="secondary">商品总价:</Text>
|
||||
<Text>¥500</Text>
|
||||
</Paragraph>
|
||||
</Space>
|
||||
</ProCard>
|
||||
<ProCard>
|
||||
<Space direction="vertical">
|
||||
<Text>退款信息</Text>
|
||||
<Paragraph className="order-paragraph">
|
||||
<Text type="secondary">累计退款金额:</Text>
|
||||
<Text>¥{item.refundPrice}</Text>
|
||||
</Paragraph>
|
||||
<Paragraph className="order-paragraph">
|
||||
<Text type="secondary">累计退款数量:</Text>
|
||||
<Text>{item.refundCount}</Text>
|
||||
</Paragraph>
|
||||
</Space>
|
||||
</ProCard>
|
||||
</ProCard>
|
||||
<ProCard
|
||||
style={{
|
||||
borderRight: '1px solid rgba(5,5,5,0.06)',
|
||||
height: '100%',
|
||||
}}
|
||||
>
|
||||
<Space direction="vertical">
|
||||
<Text>付款信息</Text>
|
||||
<Paragraph className="order-paragraph">
|
||||
<Text type="secondary">商品总价:</Text>
|
||||
<Text>¥500</Text>
|
||||
</Paragraph>
|
||||
<Paragraph className="order-paragraph">
|
||||
<Text type="secondary">商品总价:</Text>
|
||||
<Text>¥500</Text>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Text type="secondary">商品总价:</Text>
|
||||
<Text>¥500</Text>
|
||||
</Paragraph>
|
||||
</Space>
|
||||
</ProCard>
|
||||
<ProCard>
|
||||
<Space direction="vertical">
|
||||
<Text>退款信息</Text>
|
||||
<Paragraph className="order-paragraph">
|
||||
<Text type="secondary">累计退款金额:</Text>
|
||||
<Text>¥500</Text>
|
||||
</Paragraph>
|
||||
<Paragraph className="order-paragraph">
|
||||
<Text type="secondary">累计退款数量:</Text>
|
||||
<Text>1</Text>
|
||||
</Paragraph>
|
||||
</Space>
|
||||
</ProCard>
|
||||
</ProCard>
|
||||
))}
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
import { ProCard } from '@ant-design/pro-components';
|
||||
import { Card, Space } from 'antd';
|
||||
import React from 'react';
|
||||
import EnhancedProTable from '@/components/EnhancedProTable';
|
||||
import {
|
||||
type DeptReqVO,
|
||||
type DeptVO,
|
||||
getDeptPage,
|
||||
} from '@/services/system/dept';
|
||||
import type { TradeExtendCostInfo } from '@/services/trade/order';
|
||||
import { baseOrderColumns } from '../../../config';
|
||||
import styles from './index.module.less';
|
||||
|
||||
const SelectInfo: React.FC<{ data?: TradeExtendCostInfo; id: number }> = (
|
||||
props,
|
||||
) => {
|
||||
const { data = {}, id } = props;
|
||||
const onFetch = async (
|
||||
params: DeptReqVO & {
|
||||
pageSize?: number;
|
||||
current?: number;
|
||||
},
|
||||
) => {
|
||||
const data = await getDeptPage({
|
||||
...params,
|
||||
pageNo: params.current,
|
||||
pageSize: params.pageSize,
|
||||
});
|
||||
return {
|
||||
data: data,
|
||||
success: true,
|
||||
total: data.total,
|
||||
};
|
||||
};
|
||||
return (
|
||||
<div className={styles['order-info']}>
|
||||
<Card title="可选服务">
|
||||
<Space direction="vertical" style={{ width: '100%' }} size={16}>
|
||||
<ProCard split="vertical" bordered>
|
||||
<ProCard size="small" title="服务" headerBordered>
|
||||
1111
|
||||
</ProCard>
|
||||
<ProCard size="small" title="付款信息" headerBordered>
|
||||
1111
|
||||
</ProCard>
|
||||
<ProCard size="small" title="退款信息" headerBordered>
|
||||
1111
|
||||
</ProCard>
|
||||
</ProCard>
|
||||
|
||||
<EnhancedProTable<DeptVO>
|
||||
columns={baseOrderColumns}
|
||||
request={onFetch}
|
||||
showIndex={false}
|
||||
size="small"
|
||||
search={false}
|
||||
showActions={false}
|
||||
showSelection={false}
|
||||
bordered
|
||||
pagination={false}
|
||||
/>
|
||||
|
||||
<ProCard split="vertical" bordered>
|
||||
<ProCard size="small" title="纪念品" headerBordered>
|
||||
1111
|
||||
</ProCard>
|
||||
<ProCard size="small" title="付款信息" headerBordered>
|
||||
1111
|
||||
</ProCard>
|
||||
<ProCard size="small" title="退款摘要" headerBordered>
|
||||
1111
|
||||
</ProCard>
|
||||
</ProCard>
|
||||
</Space>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(SelectInfo);
|
||||
@@ -1,102 +1,11 @@
|
||||
import { ProCard } from '@ant-design/pro-components';
|
||||
import { Button, Card, Image, Space, Typography } from 'antd';
|
||||
import React from 'react';
|
||||
import type { TradeServeInfo } from '@/services/trade/order';
|
||||
import styles from './index.module.less';
|
||||
import type { TradeServeInfo } from '@/services/trade/order/detail';
|
||||
import type { ItemConfig } from '../../order-info';
|
||||
import ServicePetUI from './uis/pets/service';
|
||||
|
||||
const { Text, Paragraph } = Typography;
|
||||
const ServiceInfo: React.FC<{ data?: TradeServeInfo; id: number }> = (
|
||||
props,
|
||||
) => {
|
||||
const { data = {}, id } = props;
|
||||
return (
|
||||
<div className={styles['order-info']}>
|
||||
<Card title="服务信息">
|
||||
<ProCard split="vertical">
|
||||
<ProCard
|
||||
title="遗体信息"
|
||||
extra={<Button size="small">修改记录</Button>}
|
||||
size="small"
|
||||
colSpan="30%"
|
||||
headerBordered
|
||||
>
|
||||
<Paragraph>
|
||||
<Text type="secondary">姓名:</Text>
|
||||
<Text>钱多多</Text>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Text type="secondary">宠物品种:</Text>
|
||||
<Text>钱多多</Text>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Text type="secondary">体型/体重:</Text>
|
||||
<Text>钱多多</Text>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Text type="secondary">离世时间:</Text>
|
||||
<Text>钱多多</Text>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Text type="secondary">离世原因:</Text>
|
||||
<Text>钱多多</Text>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Text type="secondary">遗体照片:</Text>
|
||||
<Space wrap>
|
||||
<Image
|
||||
width={48}
|
||||
src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"
|
||||
/>
|
||||
<Image
|
||||
width={48}
|
||||
src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"
|
||||
/>
|
||||
<Image
|
||||
width={48}
|
||||
src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"
|
||||
/>
|
||||
<Image
|
||||
width={48}
|
||||
src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"
|
||||
/>
|
||||
<Image
|
||||
width={48}
|
||||
src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"
|
||||
/>
|
||||
</Space>
|
||||
</Paragraph>
|
||||
</ProCard>
|
||||
<ProCard
|
||||
size="small"
|
||||
title="预约信息"
|
||||
headerBordered
|
||||
extra={<Button size="small">修改记录</Button>}
|
||||
>
|
||||
<Paragraph>
|
||||
<Text type="secondary">离世时间:</Text>
|
||||
<Text>钱多多</Text>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Text type="secondary">更改规则:</Text>
|
||||
<Text>钱多多</Text>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Text type="secondary">预约时间:</Text>
|
||||
<Text>钱多多</Text>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Text type="secondary">用户备注:</Text>
|
||||
<Text>钱多多</Text>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Text type="secondary">客服备注:</Text>
|
||||
<Text>钱多多</Text>
|
||||
</Paragraph>
|
||||
</ProCard>
|
||||
</ProCard>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
const ServiceInfo: React.FC<ItemConfig<TradeServeInfo>> = (props) => {
|
||||
const { data = {}, orderCategoryId } = props;
|
||||
return <>{orderCategoryId === 1 && <ServicePetUI data={data} />}</>; //宠物服务ui
|
||||
};
|
||||
|
||||
export default React.memo(ServiceInfo);
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
import { Card } from 'antd';
|
||||
import React from 'react';
|
||||
import EnhancedProTable from '@/components/EnhancedProTable';
|
||||
import {
|
||||
type DeptReqVO,
|
||||
type DeptVO,
|
||||
getDeptPage,
|
||||
} from '@/services/system/dept';
|
||||
import type { TradeExtendServeInfo } from '@/services/trade/order';
|
||||
import { surchargeInfoColumns } from './config';
|
||||
import styles from './index.module.less';
|
||||
|
||||
const SurchargeInfo: React.FC<{ data?: TradeExtendServeInfo; id: number }> = (
|
||||
props,
|
||||
) => {
|
||||
const { data, id } = props;
|
||||
const onFetch = async (
|
||||
params: DeptReqVO & {
|
||||
pageSize?: number;
|
||||
current?: number;
|
||||
},
|
||||
) => {
|
||||
const data = await getDeptPage({
|
||||
...params,
|
||||
pageNo: params.current,
|
||||
pageSize: params.pageSize,
|
||||
});
|
||||
return {
|
||||
data: data,
|
||||
success: true,
|
||||
total: data.total,
|
||||
};
|
||||
};
|
||||
return (
|
||||
<div className={styles['order-info']}>
|
||||
<Card title="服务信息">
|
||||
<EnhancedProTable<DeptVO>
|
||||
columns={surchargeInfoColumns}
|
||||
request={onFetch}
|
||||
showIndex={false}
|
||||
size="small"
|
||||
search={false}
|
||||
showActions={false}
|
||||
showSelection={false}
|
||||
bordered
|
||||
pagination={false}
|
||||
/>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(SurchargeInfo);
|
||||
233
src/pages/trade/order/detail/component/info/uis/pets/config.tsx
Normal file
233
src/pages/trade/order/detail/component/info/uis/pets/config.tsx
Normal file
@@ -0,0 +1,233 @@
|
||||
import type { ProColumns } from '@ant-design/pro-components';
|
||||
import { Image, Space, Typography } from 'antd';
|
||||
import { fallback } from '@/constants/antd/image';
|
||||
import type {
|
||||
TradeExtendCostInfo,
|
||||
TradeExtendServeInfo,
|
||||
} from '@/services/trade/order/detail';
|
||||
|
||||
const { Text } = Typography;
|
||||
const sharedOnCell = (record: TradeExtendServeInfo) => {
|
||||
if (record.deliveryType) {
|
||||
return { colSpan: 0 };
|
||||
}
|
||||
|
||||
return {};
|
||||
};
|
||||
export const baseOrderColumns: ProColumns<TradeExtendServeInfo>[] = [
|
||||
{
|
||||
title: '服务',
|
||||
dataIndex: 'serve',
|
||||
width: '33.33%',
|
||||
onCell: (record) => {
|
||||
if (record.deliveryType) {
|
||||
return {
|
||||
colSpan: 3,
|
||||
};
|
||||
}
|
||||
return {};
|
||||
},
|
||||
render: (_, record) => {
|
||||
if (record.deliveryType) {
|
||||
return (
|
||||
<Space direction="vertical">
|
||||
<div>
|
||||
<Text type="secondary">配送方式:</Text>
|
||||
<Text>{record.deliveryType}</Text>
|
||||
</div>
|
||||
{record.receiveUser && (
|
||||
<div>
|
||||
<Text type="secondary">收货人:</Text>
|
||||
<Text>{record.receiveUser}</Text>
|
||||
</div>
|
||||
)}
|
||||
{record.sendUser && (
|
||||
<div>
|
||||
<Text type="secondary">提货人:</Text>
|
||||
<Text>{record.sendUser}</Text>
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<Text type="secondary">手机号码:</Text>
|
||||
<Text>{record?.userMobile}</Text>
|
||||
</div>
|
||||
<div>
|
||||
<Text type="secondary">地址信息:</Text>
|
||||
<Text>{record.address}</Text>
|
||||
</div>
|
||||
</Space>
|
||||
);
|
||||
} else if (record.tempType === 3) {
|
||||
return (
|
||||
<div>
|
||||
<Text type="secondary">{record.serveTitle}:</Text>
|
||||
<Text>{record.serveType}</Text>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Space size={8} direction="vertical">
|
||||
{record.serve?.map((serve, index) => (
|
||||
<Space size={8} key={`${index}-${Math.random()}`}>
|
||||
<Image
|
||||
src={serve.serveUrl}
|
||||
width={50}
|
||||
height={50}
|
||||
fallback={fallback}
|
||||
/>
|
||||
<div>
|
||||
<div>{serve.serveName}</div>
|
||||
<Text type="secondary">{serve.serveDesc}</Text>
|
||||
<div>
|
||||
<Text type="secondary">数量:</Text>
|
||||
<Text>{serve.count}</Text>
|
||||
<Text type="secondary">单价:</Text>
|
||||
<Text>{serve.price}</Text>
|
||||
<Text type="secondary">到手价:</Text>
|
||||
<Text>{serve.handPrice}</Text>
|
||||
</div>
|
||||
</div>
|
||||
</Space>
|
||||
))}
|
||||
</Space>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '付款信息',
|
||||
dataIndex: 'payPrice',
|
||||
hideInSearch: true,
|
||||
onCell: sharedOnCell,
|
||||
render: (_, record) => (
|
||||
<Space direction="vertical">
|
||||
<div>
|
||||
<Text type="secondary">商品总价:</Text>
|
||||
<Text>{record.totalPrice}</Text>
|
||||
</div>
|
||||
<div>
|
||||
<Text type="secondary">优惠金额:</Text>
|
||||
<Text>{record.discountPrice}</Text>
|
||||
</div>
|
||||
<div>
|
||||
<Text type="secondary">实付金额:</Text>
|
||||
<Text>{record.payPrice}</Text>
|
||||
</div>
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '退款信息',
|
||||
dataIndex: 'refundMoney',
|
||||
hideInSearch: true,
|
||||
onCell: sharedOnCell,
|
||||
render: (_, record) => (
|
||||
<Space direction="vertical">
|
||||
<div>
|
||||
<Text type="secondary">累计退款金额:</Text>
|
||||
<Text>{record.refundMoney}</Text>
|
||||
</div>
|
||||
<div>
|
||||
<Text type="secondary">累计退款数量:</Text>
|
||||
<Text>{record.refundCount}</Text>
|
||||
</div>
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
export const extendCost: ProColumns<TradeExtendCostInfo>[] = [
|
||||
{
|
||||
title: '服务附加费',
|
||||
dataIndex: 'serveExtFee',
|
||||
},
|
||||
{
|
||||
title: '费用详情',
|
||||
dataIndex: 'leaderUserId',
|
||||
render: (_, record) => (
|
||||
<Space direction="vertical">
|
||||
<div>
|
||||
<Text type="secondary">费用名称:</Text>
|
||||
<Text>{record.costName}</Text>
|
||||
</div>
|
||||
{record.serveArea && (
|
||||
<div>
|
||||
<Text type="secondary">可服务区域:</Text>
|
||||
<Text>{record.serveArea}</Text>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{record.targetArea && (
|
||||
<div>
|
||||
<Text type="secondary">目标区域:</Text>
|
||||
<Text>{record.targetArea}</Text>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{record.weight && (
|
||||
<div>
|
||||
<Text type="secondary">体型/体重:</Text>
|
||||
<Text>{record.weight}</Text>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{record.respTime && (
|
||||
<div>
|
||||
<Text type="secondary">响应时间:</Text>
|
||||
<Text>{record.respTime}</Text>
|
||||
</div>
|
||||
)}
|
||||
{record.respMode && (
|
||||
<div>
|
||||
<Text type="secondary">响应模式:</Text>
|
||||
<Text>{record.respMode || '-'}</Text>
|
||||
</div>
|
||||
)}
|
||||
{record.chargeTime && (
|
||||
<div>
|
||||
<Text type="secondary">收费时段:</Text>
|
||||
<Text>{record.chargeTime}</Text>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div>
|
||||
<Text type="secondary">收费方式:</Text>
|
||||
<Text>{record.chargeType || '-'}</Text>
|
||||
</div>
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '付款信息',
|
||||
dataIndex: 'payInfo',
|
||||
render: (_, record) => (
|
||||
<Space direction="vertical">
|
||||
<div>
|
||||
<Text type="secondary">服务总价:</Text>
|
||||
<Text>¥{record.payInfo?.totalPrice || 0}</Text>
|
||||
</div>
|
||||
<div>
|
||||
<Text type="secondary">优惠金额:</Text>
|
||||
<Text>¥{record.payInfo?.discountPrice || 0}</Text>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Text type="secondary">实付金额:</Text>
|
||||
<Text>¥{record.payInfo?.payPrice || 0}</Text>
|
||||
</div>
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '退款信息',
|
||||
dataIndex: 'refundPrice',
|
||||
render: (_, record) => (
|
||||
<Space direction="vertical">
|
||||
<div>
|
||||
<Text type="secondary">累计退款金额:</Text>
|
||||
<Text>¥{record.refundPrice || 0}</Text>
|
||||
</div>
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,24 @@
|
||||
import React from 'react';
|
||||
import EnhancedProTable from '@/components/EnhancedProTable';
|
||||
import type { TradeExtendCostInfo } from '@/services/trade/order/detail';
|
||||
import type { ItemConfig } from '../../../../order-info';
|
||||
import { extendCost } from './config';
|
||||
|
||||
const ExtendCost: React.FC<ItemConfig<TradeExtendCostInfo[]>> = (props) => {
|
||||
const { data } = props;
|
||||
return (
|
||||
<EnhancedProTable<TradeExtendCostInfo>
|
||||
columns={extendCost}
|
||||
dataSource={data}
|
||||
showIndex={false}
|
||||
size="small"
|
||||
search={false}
|
||||
showActions={false}
|
||||
showSelection={false}
|
||||
bordered
|
||||
pagination={false}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(ExtendCost);
|
||||
@@ -0,0 +1,34 @@
|
||||
import { Card } from 'antd';
|
||||
import React from 'react';
|
||||
import EnhancedProTable from '@/components/EnhancedProTable';
|
||||
import type { TradeExtendServeInfo } from '@/services/trade/order/detail';
|
||||
import type { ItemConfig } from '../../../../order-info';
|
||||
import { baseOrderColumns } from './config';
|
||||
|
||||
const ExtendServicePet: React.FC<ItemConfig<TradeExtendServeInfo[][]>> = (
|
||||
props,
|
||||
) => {
|
||||
const { data = [] } = props;
|
||||
return (
|
||||
<Card title="可选服务">
|
||||
<div style={{ display: 'flex', gap: '16px', flexDirection: 'column' }}>
|
||||
{data.map((item, index) => (
|
||||
<EnhancedProTable<TradeExtendServeInfo>
|
||||
key={`${index}-${Math.random()}`}
|
||||
columns={baseOrderColumns}
|
||||
dataSource={item}
|
||||
showIndex={false}
|
||||
size="small"
|
||||
search={false}
|
||||
showActions={false}
|
||||
showSelection={false}
|
||||
bordered
|
||||
pagination={false}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(ExtendServicePet);
|
||||
106
src/pages/trade/order/detail/component/info/uis/pets/service.tsx
Normal file
106
src/pages/trade/order/detail/component/info/uis/pets/service.tsx
Normal file
@@ -0,0 +1,106 @@
|
||||
import { ClockCircleOutlined, EnvironmentOutlined } from '@ant-design/icons';
|
||||
import { ProCard } from '@ant-design/pro-components';
|
||||
import { Button, Card, Image, Space, Timeline, Typography } from 'antd';
|
||||
import React from 'react';
|
||||
import { fallback } from '@/constants/antd/image';
|
||||
import type { TradeServeInfo } from '@/services/trade/order/detail';
|
||||
import type { ItemConfig } from '../../../../order-info';
|
||||
import styles from '../../index.module.less';
|
||||
|
||||
const { Text, Paragraph } = Typography;
|
||||
const ServicePetUI: React.FC<ItemConfig<TradeServeInfo>> = (props) => {
|
||||
const { data = {} } = props;
|
||||
const { boneInfo, subInfo } = data;
|
||||
return (
|
||||
<div className={styles['order-info']}>
|
||||
<Card title="服务信息">
|
||||
<ProCard split="vertical" bordered>
|
||||
<ProCard title="遗体信息" size="small" colSpan="30%" headerBordered>
|
||||
<Paragraph>
|
||||
<Text type="secondary">姓名:</Text>
|
||||
<Text>{boneInfo?.petName}</Text>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Text type="secondary">宠物品种:</Text>
|
||||
<Text>{boneInfo?.petType}</Text>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Text type="secondary">体型/体重:</Text>
|
||||
<Text>{boneInfo?.weight}</Text>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Text type="secondary">离世时间:</Text>
|
||||
<Text>{boneInfo?.diedTime}</Text>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Text type="secondary">离世原因:</Text>
|
||||
<Text>{boneInfo?.diedReason}</Text>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Text type="secondary">遗体照片:</Text>
|
||||
<Space wrap>
|
||||
{data.boneInfo?.boneUrl?.map((item: string, index: number) => (
|
||||
<Image
|
||||
width={48}
|
||||
src={item}
|
||||
key={`${index}-${Math.random()}`}
|
||||
fallback={fallback}
|
||||
/>
|
||||
))}
|
||||
</Space>
|
||||
</Paragraph>
|
||||
</ProCard>
|
||||
<ProCard
|
||||
size="small"
|
||||
title="预约信息"
|
||||
headerBordered
|
||||
extra={<Button size="small">修改记录</Button>}
|
||||
>
|
||||
<Space size={100}>
|
||||
<div>
|
||||
<Paragraph>
|
||||
<Text type="secondary">预约类型:</Text>
|
||||
<Text>{subInfo?.subType}</Text>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Text type="secondary">更改规则:</Text>
|
||||
<Text>{subInfo?.changeRule}</Text>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Text type="secondary">预约时间:</Text>
|
||||
<Text>{subInfo?.subOrder}</Text>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Text type="secondary">用户备注:</Text>
|
||||
<Text>{subInfo?.userRemark}</Text>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Text type="secondary">客服备注:</Text>
|
||||
<Text>{subInfo?.merchantRemark}</Text>
|
||||
</Paragraph>
|
||||
</div>
|
||||
<Timeline
|
||||
items={[
|
||||
{
|
||||
dot: (
|
||||
<ClockCircleOutlined className="timeline-clock-icon" />
|
||||
),
|
||||
color: 'green',
|
||||
children: subInfo?.pickUpAddress,
|
||||
},
|
||||
{
|
||||
dot: <EnvironmentOutlined />,
|
||||
children: subInfo?.pickUpAddress,
|
||||
color: 'red',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</Space>
|
||||
</ProCard>
|
||||
</ProCard>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(ServicePetUI);
|
||||
@@ -3,34 +3,60 @@ import React, { useCallback, useEffect, useState } from 'react';
|
||||
import {
|
||||
getTradeOrderDetail,
|
||||
type TradeOrderDetailRespVO,
|
||||
type TradeOrderPageRespVO,
|
||||
} from '@/services/trade/order';
|
||||
import BasicInfo from './component/info/basic-info'; //基本信息(通版)
|
||||
import ExtendCostInfo from './component/info/extend-cost'; //服务附加费(殡葬专属字段)
|
||||
import ExtendService from './component/info/extend-service'; //可选服务(殡葬专属字段)
|
||||
import ProdInfo from './component/info/prod-info'; //商品信息(通版)
|
||||
import SelectInfo from './component/info/select-info'; //可选服务(殡葬专属字段)
|
||||
import ServiceInfo from './component/info/service-info';
|
||||
import SurchargeInfo from './component/info/surcharge-info'; //服务附加费(殡葬专属字段)
|
||||
|
||||
const OrderDetail: React.FC<{ data?: TradeOrderDetailRespVO }> = (props) => {
|
||||
export interface ItemConfig<T> {
|
||||
data?: T;
|
||||
loading?: boolean;
|
||||
orderCategoryId?: number;
|
||||
}
|
||||
const OrderDetail: React.FC<{ data?: TradeOrderPageRespVO }> = (props) => {
|
||||
const { data } = props;
|
||||
const [detais, setDetails] = useState<TradeOrderDetailRespVO>();
|
||||
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const fetch = useCallback(async () => {
|
||||
if (data?.id) {
|
||||
const res = await getTradeOrderDetail(data.id);
|
||||
setDetails(res);
|
||||
try {
|
||||
setLoading(true);
|
||||
if (data?.id) {
|
||||
const res = await getTradeOrderDetail(data.id);
|
||||
setDetails(res);
|
||||
}
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [data]);
|
||||
}, [data?.id]);
|
||||
useEffect(() => {
|
||||
fetch();
|
||||
}, [data]);
|
||||
}, [data?.id]);
|
||||
|
||||
return (
|
||||
<Space direction="vertical" size={24} style={{ width: '100%' }}>
|
||||
<BasicInfo data={detais?.tradeOrderInfoBase} id={data?.id} />
|
||||
<ProdInfo data={detais?.tradeProductInfo} id={data?.id} />
|
||||
<ServiceInfo data={detais?.tradeServeInfo} id={data?.id} />
|
||||
<SelectInfo data={detais?.tradeExtendCostInfo} id={data?.id} />
|
||||
<SurchargeInfo data={detais?.tradeExtendServeInfo} id={data?.id} />
|
||||
<BasicInfo data={detais} loading={loading} />
|
||||
<ProdInfo data={detais?.items} />
|
||||
{detais?.tradeServeInfo && (
|
||||
<ServiceInfo
|
||||
data={detais.tradeServeInfo}
|
||||
orderCategoryId={detais?.orderCategoryId}
|
||||
/>
|
||||
)}
|
||||
{detais?.tradeExtendServeInfo && (
|
||||
<ExtendService
|
||||
data={detais.tradeExtendServeInfo}
|
||||
orderCategoryId={detais?.orderCategoryId}
|
||||
/>
|
||||
)}
|
||||
{detais?.tradeExtendCostInfo && (
|
||||
<ExtendCostInfo
|
||||
data={detais?.tradeExtendCostInfo}
|
||||
orderCategoryId={detais?.orderCategoryId}
|
||||
/>
|
||||
)}
|
||||
</Space>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -23,8 +23,6 @@ import { baseOrderColumns } from './config';
|
||||
|
||||
const { Search } = Input;
|
||||
|
||||
const { Text } = Typography;
|
||||
|
||||
import { DownOutlined, UpOutlined, UserOutlined } from '@ant-design/icons';
|
||||
import PopconfirmForm, {
|
||||
type PopconfirmFormRef,
|
||||
@@ -50,8 +48,8 @@ const OrderListItem: React.FC<{ orderStatus: number }> = (props) => {
|
||||
const popconfirmFormRef = useRef<PopconfirmFormRef>(null);
|
||||
const onFetch = async (
|
||||
params: TradeReq & {
|
||||
pageSize?: number;
|
||||
current?: number;
|
||||
pageSize: number;
|
||||
current: number;
|
||||
},
|
||||
) => {
|
||||
const data = await getTradeOrderPage({
|
||||
@@ -68,10 +66,13 @@ const OrderListItem: React.FC<{ orderStatus: number }> = (props) => {
|
||||
};
|
||||
};
|
||||
|
||||
const handleDetail = useCallback((record: TradeOrderPageRespVO) => {
|
||||
setModalData(record);
|
||||
configurableDrawerRef.current?.open();
|
||||
}, []);
|
||||
const handleDetail = useCallback(
|
||||
(record: TradeOrderPageRespVO) => {
|
||||
setModalData(record);
|
||||
configurableDrawerRef.current?.open(record);
|
||||
},
|
||||
[modalData],
|
||||
);
|
||||
|
||||
const handleOrder = useCallback((id?: number) => {
|
||||
console.log(id, '取消订单');
|
||||
@@ -107,10 +108,10 @@ const OrderListItem: React.FC<{ orderStatus: number }> = (props) => {
|
||||
<a key="cancel" onClick={() => handleOrder(record.id)}>
|
||||
取消订单
|
||||
</a>
|
||||
<a key="cancel" onClick={() => handleOrder(record.id)}>
|
||||
<a key="order" onClick={() => handleOrder(record.id)}>
|
||||
开始服务
|
||||
</a>
|
||||
<a key="cancel" onClick={() => handleOrder(record.id)}>
|
||||
<a key="sale" onClick={() => handleOrder(record.id)}>
|
||||
新建售后
|
||||
</a>
|
||||
<a key="detail" onClick={() => handleDetail(record)}>
|
||||
@@ -186,9 +187,9 @@ const OrderListItem: React.FC<{ orderStatus: number }> = (props) => {
|
||||
<span>{record.orderNum}</span>
|
||||
<span> {record.payType}</span>
|
||||
<Space>
|
||||
<Avatar icon={<UserOutlined />} />
|
||||
<Avatar icon={<UserOutlined />} src={record.shopLogo} />
|
||||
{/* <Image src={record.picUrl} width={64} /> */}
|
||||
百业到家旗舰店
|
||||
{record.shopName || '-'}
|
||||
</Space>
|
||||
<Space>
|
||||
{record.userAvatar ? (
|
||||
@@ -211,7 +212,6 @@ const OrderListItem: React.FC<{ orderStatus: number }> = (props) => {
|
||||
header: {
|
||||
cell: (props: any) => {
|
||||
const { children, ...restProps } = props;
|
||||
console.log(restProps, children);
|
||||
return <th {...restProps}>{children}</th>;
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import type { RequestOptions } from "@@/plugin-request/request";
|
||||
import type { RequestConfig } from "@umijs/max";
|
||||
import { request } from "@umijs/max";
|
||||
import { message } from "antd";
|
||||
import { getAccessToken, getRefreshToken, setToken } from "./utils/auth";
|
||||
import type { RequestOptions } from '@@/plugin-request/request';
|
||||
import type { RequestConfig } from '@umijs/max';
|
||||
import { request } from '@umijs/max';
|
||||
import { message } from 'antd';
|
||||
import { getAccessToken, getRefreshToken, setToken } from './utils/auth';
|
||||
|
||||
// const tenantEnable = process.env.VITE_APP_TENANT_ENABLE;
|
||||
// const { result_code, base_url, request_timeout } = config;
|
||||
@@ -49,8 +49,8 @@ interface ResponseStructure {
|
||||
*/
|
||||
|
||||
const refreshToken = async () => {
|
||||
return await request("/system/auth/refresh-token", {
|
||||
method: "POST",
|
||||
return await request('/system/auth/refresh-token', {
|
||||
method: 'POST',
|
||||
params: { refreshToken: getRefreshToken() },
|
||||
});
|
||||
};
|
||||
@@ -93,7 +93,7 @@ export const errorConfig: RequestConfig = {
|
||||
const { success, data, code, msg } = res as unknown as ResponseStructure;
|
||||
if (!success) {
|
||||
const error: any = new Error(msg);
|
||||
error.name = "BizError";
|
||||
error.name = 'BizError';
|
||||
error.info = { code, msg, data };
|
||||
throw error; // 抛出自制的错误
|
||||
}
|
||||
@@ -102,9 +102,9 @@ export const errorConfig: RequestConfig = {
|
||||
errorHandler: async (error: any, opts: any) => {
|
||||
if (opts?.skipErrorHandler) throw error;
|
||||
// 我们的 errorThrower 抛出的错误。
|
||||
console.log("errorHandler", error);
|
||||
console.log('errorHandler', error);
|
||||
const errorInfo: ResponseStructure | undefined = error.info;
|
||||
if (error.name === "BizError") {
|
||||
if (error.name === 'BizError') {
|
||||
if (errorInfo) {
|
||||
const { msg } = errorInfo;
|
||||
message.error(msg);
|
||||
@@ -114,7 +114,7 @@ export const errorConfig: RequestConfig = {
|
||||
// 请求成功发出且服务器也响应了状态码,但状态代码超出了 2xx 的范围
|
||||
message.error(`Response status:${error.response.status}`);
|
||||
} else if (error.request) {
|
||||
message.error("None response! Please retry.");
|
||||
message.error('None response! Please retry.');
|
||||
} else {
|
||||
message.error(`发送请求时出了点问题:${error.msg}`);
|
||||
}
|
||||
@@ -125,7 +125,7 @@ export const errorConfig: RequestConfig = {
|
||||
requestInterceptors: [
|
||||
(config: RequestOptions) => {
|
||||
// 拦截请求配置,进行个性化处理。
|
||||
console.log("requestInterceptors", config);
|
||||
console.log('requestInterceptors', config);
|
||||
return { ...config };
|
||||
},
|
||||
],
|
||||
@@ -133,25 +133,25 @@ export const errorConfig: RequestConfig = {
|
||||
// 响应拦截器
|
||||
responseInterceptors: [
|
||||
async (response) => {
|
||||
let { data } = response as unknown as ResponseStructure;
|
||||
const { data } = response as unknown as ResponseStructure;
|
||||
const config = response.config;
|
||||
const { code } = data;
|
||||
if (!data) {
|
||||
// 返回“[HTTP]请求没有返回值”;
|
||||
throw new Error();
|
||||
}
|
||||
// if (!data) {
|
||||
// // 返回“[HTTP]请求没有返回值”;
|
||||
// throw new Error();
|
||||
// }
|
||||
// 未设置状态码则默认成功状态
|
||||
// 二进制数据则直接返回,例如说 Excel 导出
|
||||
if (
|
||||
response.request.responseType === "blob" ||
|
||||
response.request.responseType === "arraybuffer"
|
||||
) {
|
||||
// 注意:如果导出的响应为 json,说明可能失败了,不直接返回进行下载
|
||||
// if (response.data.type !== "application/json") {
|
||||
// return response.data;
|
||||
// }
|
||||
data = await new Response(data).json();
|
||||
}
|
||||
// if (
|
||||
// response.request.responseType === "blob" ||
|
||||
// response.request.responseType === "arraybuffer"
|
||||
// ) {
|
||||
// // 注意:如果导出的响应为 json,说明可能失败了,不直接返回进行下载
|
||||
// // if (response.data.type !== "application/json") {
|
||||
// // return response.data;
|
||||
// // }
|
||||
// data = await new Response(data).json();
|
||||
// }
|
||||
// // 获取错误信息
|
||||
// const msg = data.msg || errorCode[code] || errorCode["default"];
|
||||
// if (ignoreMsgs.indexOf(msg) !== -1) {
|
||||
@@ -159,7 +159,7 @@ export const errorConfig: RequestConfig = {
|
||||
// return Promise.reject(msg);
|
||||
// }
|
||||
if (!config.url) {
|
||||
throw new Error("请求URL不能为空");
|
||||
throw new Error('请求URL不能为空');
|
||||
}
|
||||
// 发送请求时出了点问题
|
||||
if (code === 401) {
|
||||
@@ -172,28 +172,21 @@ export const errorConfig: RequestConfig = {
|
||||
// 2. 进行刷新访问令牌
|
||||
try {
|
||||
const refreshTokenRes = await refreshToken();
|
||||
console.log("刷新成功", refreshTokenRes);
|
||||
// 2.1 刷新成功,则回放队列的请求 + 当前请求
|
||||
setToken(refreshTokenRes);
|
||||
// 发出 token 刷新事件
|
||||
// 刷新当前路由
|
||||
// window.location.reload();
|
||||
// requestEventBus.emit('token-refreshed');
|
||||
location.reload();
|
||||
} catch (_) {
|
||||
// 为什么需要 catch 异常呢?刷新失败时,请求因为 Promise.reject 触发异常。
|
||||
// 提示是否要登出。即不回放当前请求!不然会形成递归
|
||||
return handleAuthorized();
|
||||
} finally {
|
||||
isRefreshToken = false;
|
||||
}
|
||||
return request(config.url, config);
|
||||
} else {
|
||||
console.log("刷新令牌失败");
|
||||
console.log('刷新令牌失败');
|
||||
//添加到队列,等待刷新获取到新的令牌
|
||||
return new Promise((resolve) => {
|
||||
requestList.push(() => {
|
||||
if (!config.url) {
|
||||
throw new Error("请求URL不能为空");
|
||||
throw new Error('请求URL不能为空');
|
||||
}
|
||||
if (config.headers)
|
||||
config.headers.Authorization = `Bearer ${getAccessToken()}`; // 让每个请求携带自定义token 请根据实际情况自行修改
|
||||
@@ -206,7 +199,7 @@ export const errorConfig: RequestConfig = {
|
||||
return Promise.reject(data);
|
||||
}
|
||||
if (data?.success === false) {
|
||||
message.error("请求失败!");
|
||||
message.error('请求失败!');
|
||||
return Promise.reject(data);
|
||||
}
|
||||
|
||||
|
||||
43
src/services/prod/category-manager/index.ts
Normal file
43
src/services/prod/category-manager/index.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { request } from "@umijs/max";
|
||||
|
||||
export interface Category extends PageParam {
|
||||
parentId?: number;
|
||||
categoryName?: string; //类目名称
|
||||
categoryId?: number; //类目ID
|
||||
grade?: number; //类目层级
|
||||
parentName?: string; //父级类目
|
||||
sort?: number; //排序权重
|
||||
status?: number; // 1为开启 0 为禁用;
|
||||
createTime?: Date;
|
||||
description?: string; //描述
|
||||
tag?: string[] | string;
|
||||
}
|
||||
|
||||
export interface CategoryReq extends PageParam {
|
||||
parentName?: string;
|
||||
categoryName?: string;
|
||||
status?: number;
|
||||
grade?: number; //父级类目
|
||||
}
|
||||
|
||||
// 查询分类列表
|
||||
export const getProdCategoryPage = async (params: CategoryReq) => {
|
||||
return request("/product/category/categoryList", {
|
||||
method: "GET",
|
||||
params,
|
||||
});
|
||||
};
|
||||
// 新增分类
|
||||
export const createProdCategory = async (data: Category) => {
|
||||
return request("/product/category/create", {
|
||||
method: "GET",
|
||||
data,
|
||||
});
|
||||
};
|
||||
//编辑分类
|
||||
export const updateProdCategory = async (data: Category) => {
|
||||
return request<IResponse<boolean>>("/product/category/create", {
|
||||
method: "PUT",
|
||||
data,
|
||||
});
|
||||
};
|
||||
@@ -1,3 +1,4 @@
|
||||
import { request } from "@umijs/max";
|
||||
export interface Prod extends PageParam {
|
||||
/**
|
||||
* 商品简称
|
||||
@@ -176,10 +177,10 @@ export interface SkuPropValues {
|
||||
id?: number;
|
||||
propValue: string;
|
||||
valueId: number;
|
||||
state: 0 | 1; // 0禁用1启用
|
||||
isExist: 0 | 1; //是否新增 0否1是
|
||||
state: number; // 0禁用1启用
|
||||
isExist: number; //是否新增 0否1是
|
||||
sort: number;
|
||||
isExpire: 0 | 1 /**是否失效0否1是**/;
|
||||
isExpire: number /**是否失效0否1是**/;
|
||||
}
|
||||
export interface SkuConfig {
|
||||
propName: string; //规格名字
|
||||
@@ -204,7 +205,209 @@ export interface ProdDetail {
|
||||
|
||||
export interface ProdReq extends PageParam {
|
||||
name?: string;
|
||||
status?: 0 | 1 | 2; //状态 1,正常状态(出售中), 0:下架(仓库中) 2:待审核
|
||||
status?: number; //状态 1,正常状态(出售中), 0:下架(仓库中) 2:待审核
|
||||
prodName?: string; // 商品名称
|
||||
createTime?: Date; //创建时间
|
||||
}
|
||||
|
||||
// 查询商品管理列表
|
||||
export const getProdPage = async (params: ProdReq) => {
|
||||
return request("/product/prod/page", {
|
||||
method: "GET",
|
||||
params,
|
||||
});
|
||||
};
|
||||
|
||||
// 查询商品回收站
|
||||
export const getProdRecycleBinPageList = async (params: ProdReq) => {
|
||||
return request("/product/prod/getProdRecycleBinPageList", {
|
||||
method: "GET",
|
||||
params,
|
||||
});
|
||||
};
|
||||
|
||||
// 恢复商品
|
||||
export const restoreProdList = async (params: { ids: number[] }) => {
|
||||
return request("/product/prod/restoreProdList", {
|
||||
method: "POST",
|
||||
params,
|
||||
});
|
||||
};
|
||||
|
||||
// 删除商品
|
||||
export const deleteProd = async (params: { id: number }) => {
|
||||
return request<PageResult<Prod[]>>("/product/prod/delete", {
|
||||
method: "DELETE",
|
||||
params,
|
||||
});
|
||||
};
|
||||
|
||||
// 批量删除商品
|
||||
export const deleteSkuList = async (params: { ids: number[] }) => {
|
||||
return request<PageResult<Prod[]>>("/product/prod/deleteSkuList", {
|
||||
method: "DELETE",
|
||||
params,
|
||||
});
|
||||
};
|
||||
|
||||
// 批量上下架商品
|
||||
export const updateSkuShelfList = async (params: {
|
||||
status: number;
|
||||
ids: number[];
|
||||
}) => {
|
||||
return request<PageResult<Prod[]>>("/product/prod/updateSkuShelfList", {
|
||||
method: "DELETE",
|
||||
params,
|
||||
});
|
||||
};
|
||||
|
||||
// 查询商品管理详情
|
||||
|
||||
export const getProdDetail = async (params: { id: number }) => {
|
||||
return request<PageResult<Prod[]>>("/product/prod/getProdInfo", {
|
||||
method: "GET",
|
||||
params,
|
||||
});
|
||||
};
|
||||
|
||||
// 创建商品
|
||||
export const createProd = async (data: Prod) => {
|
||||
return request<PageResult<Prod[]>>("/product/prod/create", {
|
||||
method: "POST",
|
||||
data,
|
||||
});
|
||||
};
|
||||
// 更新商品详情
|
||||
export const updateProd = async (data: Prod) => {
|
||||
return request<Promise<PageResult<Prod[]>>>("/product/prod/update", {
|
||||
method: "PUT",
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
||||
// 获取sku规格
|
||||
|
||||
export const getSKuPropList = async (params: Prod) => {
|
||||
return request("/product/sku/getSKuPropList", {
|
||||
method: "GET",
|
||||
params,
|
||||
});
|
||||
};
|
||||
|
||||
// 更新sku
|
||||
|
||||
export const updateProp = async (data: Prod) => {
|
||||
return request("/product/sku/updateProp", {
|
||||
method: "PUT",
|
||||
data,
|
||||
});
|
||||
};
|
||||
//更新单品SKU
|
||||
export const updateSKu = async (data: Prod) => {
|
||||
return request("/product/sku/update", {
|
||||
method: "PUT",
|
||||
data,
|
||||
});
|
||||
};
|
||||
//更新单品SKU上下架
|
||||
|
||||
export const updateSkuShelf = async (params: {
|
||||
id?: number;
|
||||
isShelf?: number;
|
||||
}) => {
|
||||
return request("/product/sku/updateSkuShelf", {
|
||||
method: "PUT",
|
||||
params,
|
||||
});
|
||||
};
|
||||
|
||||
//删除规格值
|
||||
|
||||
export const deletePropSku = async (params: { id?: number }) => {
|
||||
return request("/product/sku/deleteProp", {
|
||||
method: "PUT",
|
||||
params,
|
||||
});
|
||||
};
|
||||
//禁用规格值
|
||||
|
||||
export const disablePropSku = async (params: Prod) => {
|
||||
return request("/product/sku/disableProp", {
|
||||
method: "PUT",
|
||||
params,
|
||||
});
|
||||
};
|
||||
//获得SKU分页列表
|
||||
|
||||
export const getSkuPageList = async (params: Prod) => {
|
||||
return request("/product/sku/getSkuPageList", {
|
||||
method: "GET",
|
||||
params,
|
||||
});
|
||||
};
|
||||
//删除SKU
|
||||
export const deleteSku = async (id: number) => {
|
||||
return request("/product/sku/delete", {
|
||||
method: "DELETE",
|
||||
params: { id },
|
||||
});
|
||||
};
|
||||
//获得SKU回收站列表
|
||||
export const getSkuRecycleBinPageList = async (params: Prod) => {
|
||||
return request("/product/sku/getSkuRecycleBinPageList", {
|
||||
method: "GET",
|
||||
params,
|
||||
});
|
||||
};
|
||||
|
||||
//获得规格回收站
|
||||
|
||||
export const getPropRecycleBinList = async (params: Prod) => {
|
||||
return request("/product/sku/getPropRecycleBinList", {
|
||||
method: "GET",
|
||||
params,
|
||||
});
|
||||
};
|
||||
//恢复规格值
|
||||
|
||||
export const restorePropList = async (ids: number[]) => {
|
||||
return request("/product/sku/restorePropList", {
|
||||
method: "POST",
|
||||
params: { ids },
|
||||
});
|
||||
};
|
||||
//SKU回收站恢复
|
||||
export const restoreSkuList = async (ids: number[]) => {
|
||||
return request("/product/sku/restoreSkuList", {
|
||||
method: "POST",
|
||||
params: { ids },
|
||||
});
|
||||
};
|
||||
|
||||
// 规格属性修改
|
||||
export const updateProdProp = async (params: {
|
||||
id: number;
|
||||
propName: string;
|
||||
}) => {
|
||||
return request("/product/sku/updateProdProp", {
|
||||
method: "PUT",
|
||||
params,
|
||||
});
|
||||
};
|
||||
// 规格值修改
|
||||
export const updatePropValue = async (params: {
|
||||
id: number;
|
||||
propValue: string;
|
||||
}) => {
|
||||
return request("/product/sku/updatePropValue", {
|
||||
method: "PUT",
|
||||
params,
|
||||
});
|
||||
};
|
||||
// /tz/sku/update
|
||||
|
||||
// //修改服务配置
|
||||
// export const getSKuPropList = async (data: Prod) => {
|
||||
// return await request.post({ url: "/tz/sku/getSKuPropList", data: data });
|
||||
// };
|
||||
// /product/prod/uptateProdService
|
||||
|
||||
565
src/services/prod/prod-manager/rule.ts
Normal file
565
src/services/prod/prod-manager/rule.ts
Normal file
@@ -0,0 +1,565 @@
|
||||
import { request } from "@umijs/max";
|
||||
import type { Prod } from ".";
|
||||
|
||||
/**
|
||||
* ProdServiceVO
|
||||
*/
|
||||
export interface ProdServiceVO {
|
||||
/**
|
||||
* 是否特殊日期(节假日周末什么的)0关1开
|
||||
*/
|
||||
additionalFeeSwitch?: number;
|
||||
/**
|
||||
* 是否特殊时段0关1开
|
||||
*/
|
||||
additionalSwitch?: number;
|
||||
/**
|
||||
* 分类名称
|
||||
*/
|
||||
categoryName?: string;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
createTime?: string;
|
||||
/**
|
||||
* 新建人
|
||||
*/
|
||||
creator?: string;
|
||||
/**
|
||||
* 是否紧急响应服务0关1开
|
||||
*/
|
||||
emergencySwitch?: number;
|
||||
/**
|
||||
* 是否接单上线0关1开
|
||||
*/
|
||||
orderLimitSwitch?: number;
|
||||
/**
|
||||
* 特殊时段规则配置
|
||||
*/
|
||||
prodAdditionalFeeDatesList?: ProdAdditionalFeeDatesDO[];
|
||||
/**
|
||||
* 特殊日期规则配置
|
||||
*/
|
||||
prodAdditionalFeePeriodsList?: ProdAdditionalFeePeriodsDO[];
|
||||
/**
|
||||
* 急响应服务配置
|
||||
*/
|
||||
prodEmergencyInfoVO?: ProdEmergencyInfoVO;
|
||||
/**
|
||||
* 产品ID
|
||||
*/
|
||||
prodId?: number;
|
||||
/**
|
||||
* 预约配置
|
||||
*/
|
||||
prodReservationConfig?: ProdReservationInfoVO;
|
||||
/**
|
||||
* 服务区域配置
|
||||
*/
|
||||
prodServiceAreasInfo?: ProdServiceAreasInfoVO;
|
||||
/**
|
||||
* 接单上线配置
|
||||
*/
|
||||
productOrderLimitVO?: ProductOrderLimitDO;
|
||||
/**
|
||||
* 体重配置
|
||||
*/
|
||||
prodWeightConfig?: ProdWeightRangePricesSaveInfoVO;
|
||||
/**
|
||||
* 是否开启服务区域配置0关1开
|
||||
*/
|
||||
regionSwitch?: number;
|
||||
/**
|
||||
* 是否预约0关1开
|
||||
*/
|
||||
reservationSwitch?: number;
|
||||
/**
|
||||
* 修改人
|
||||
*/
|
||||
updater?: string;
|
||||
/**
|
||||
* 修改时间
|
||||
*/
|
||||
updateTime?: string;
|
||||
/**
|
||||
* 是否开启体重配置0关1开
|
||||
*/
|
||||
weightSwitch?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 特殊日期附加费用规则 DO
|
||||
*
|
||||
* ProdAdditionalFeeDatesDO
|
||||
*/
|
||||
export interface ProdAdditionalFeeDatesDO {
|
||||
/**
|
||||
* 收费方式
|
||||
*/
|
||||
chargeMode?: number;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
createTime?: string;
|
||||
/**
|
||||
* 创建者,目前使用 SysUser 的 id 编号
|
||||
*
|
||||
* 使用 String 类型的原因是,未来可能会存在非数值的情况,留好拓展性。
|
||||
*/
|
||||
creator?: string;
|
||||
/**
|
||||
* 自定义日期时间段(JSON格式存储)
|
||||
*/
|
||||
customTimeSlots?: string[];
|
||||
/**
|
||||
* 日期类型0:'自定义日期范围':1:'指定日期':2:'法定节假日',3:'固定休息日'
|
||||
*/
|
||||
dateType?: number;
|
||||
/**
|
||||
* 是否删除
|
||||
*/
|
||||
deleted?: number;
|
||||
/**
|
||||
* 特殊日期规则的唯一标识符
|
||||
*/
|
||||
id?: number;
|
||||
/**
|
||||
* 是否启用该规则
|
||||
*/
|
||||
isEnabled?: number;
|
||||
/**
|
||||
* 名称
|
||||
*/
|
||||
name?: string;
|
||||
/**
|
||||
* 价格或上浮百分比
|
||||
*/
|
||||
price?: number;
|
||||
/**
|
||||
* 商品id
|
||||
*/
|
||||
prodId?: number;
|
||||
/**
|
||||
* 类型:1:特殊日期 2:可预约时段黑名单日期 3:紧急相应服务黑名单日期
|
||||
*/
|
||||
type?: number;
|
||||
/**
|
||||
* 更新者,目前使用 SysUser 的 id 编号
|
||||
*
|
||||
* 使用 String 类型的原因是,未来可能会存在非数值的情况,留好拓展性。
|
||||
*/
|
||||
updater?: string;
|
||||
/**
|
||||
* 最后更新时间
|
||||
*/
|
||||
updateTime?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 特殊时段附加费用规则 DO
|
||||
*
|
||||
* ProdAdditionalFeePeriodsDO
|
||||
*/
|
||||
export interface ProdAdditionalFeePeriodsDO {
|
||||
/**
|
||||
* 收费方式0:'固定金额',1:'基准价上浮'
|
||||
*/
|
||||
chargeMode?: number;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
createTime?: string;
|
||||
/**
|
||||
* 创建者,目前使用 SysUser 的 id 编号
|
||||
*
|
||||
* 使用 String 类型的原因是,未来可能会存在非数值的情况,留好拓展性。
|
||||
*/
|
||||
creator?: string;
|
||||
/**
|
||||
* 是否删除
|
||||
*/
|
||||
deleted?: number;
|
||||
/**
|
||||
* 浮动百分比
|
||||
*/
|
||||
floatingPercentage?: number;
|
||||
/**
|
||||
* 特殊时段规则的唯一标识符
|
||||
*/
|
||||
id?: number;
|
||||
/**
|
||||
* 名称
|
||||
*/
|
||||
name?: string;
|
||||
/**
|
||||
* 价格或上浮百分比
|
||||
*/
|
||||
price?: number;
|
||||
/**
|
||||
* 商品ID
|
||||
*/
|
||||
prodId?: number;
|
||||
/**
|
||||
* 特殊时段设置(JSON格式存储)
|
||||
*/
|
||||
specialTimeSlots?: string[];
|
||||
/**
|
||||
* 更新者,目前使用 SysUser 的 id 编号
|
||||
*
|
||||
* 使用 String 类型的原因是,未来可能会存在非数值的情况,留好拓展性。
|
||||
*/
|
||||
updater?: string;
|
||||
/**
|
||||
* 最后更新时间
|
||||
*/
|
||||
updateTime?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 急响应服务配置
|
||||
*
|
||||
* ProdEmergencyInfoVO
|
||||
*/
|
||||
export interface ProdEmergencyInfoVO {
|
||||
/**
|
||||
* 紧急响应服务配置的唯一标识符
|
||||
*/
|
||||
id?: number;
|
||||
/**
|
||||
* 紧急响应黑名单日期设置
|
||||
*/
|
||||
prodEmergencyResponseBlackList?: ProdAdditionalFeeBlackVO[];
|
||||
/**
|
||||
* 紧急响应时间区间设置
|
||||
*/
|
||||
prodEmergencyResponseIntervalsList?: ProdEmergencyResponseIntervalsDO[];
|
||||
/**
|
||||
* 关联的商品ID
|
||||
*/
|
||||
prodId?: number;
|
||||
/**
|
||||
* 可响应时间段(JSON格式存储)
|
||||
*/
|
||||
responseTimeSlots?: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* com.tashow.cloud.productapi.api.product.vo.prodadditionalfeedates.ProdAdditionalFeeBlackVO
|
||||
*
|
||||
* ProdAdditionalFeeBlackVO
|
||||
*/
|
||||
export interface ProdAdditionalFeeBlackVO {
|
||||
/**
|
||||
* 黑名单日期设置
|
||||
*/
|
||||
customTimeSlots?: string[];
|
||||
/**
|
||||
* 日期类型0:'自定义日期范围':1:'指定日期':2:'法定节假日',3:'固定休息日'
|
||||
*/
|
||||
dateType?: number;
|
||||
/**
|
||||
* 特殊日期规则的唯一标识符
|
||||
*/
|
||||
id?: number;
|
||||
/**
|
||||
* 是否启用该规则是否启用该规则0关1开
|
||||
*/
|
||||
isEnabled?: number;
|
||||
/**
|
||||
* 类型:1:特殊日期 2:可预约时段黑名单日期 3:紧急相应服务黑名单日期
|
||||
*/
|
||||
type?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 紧急响应时间区间设置 DO
|
||||
*
|
||||
* ProdEmergencyResponseIntervalsDO
|
||||
*/
|
||||
export interface ProdEmergencyResponseIntervalsDO {
|
||||
/**
|
||||
* 收费模式0:固定收费 1:浮动收费
|
||||
*/
|
||||
chargeMode?: number;
|
||||
/**
|
||||
* 关联的紧急响应服务配置ID
|
||||
*/
|
||||
configId?: number;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
createTime?: string;
|
||||
/**
|
||||
* 创建者,目前使用 SysUser 的 id 编号
|
||||
*
|
||||
* 使用 String 类型的原因是,未来可能会存在非数值的情况,留好拓展性。
|
||||
*/
|
||||
creator?: string;
|
||||
/**
|
||||
* 是否删除
|
||||
*/
|
||||
deleted?: number;
|
||||
/**
|
||||
* 浮动百分比
|
||||
*/
|
||||
floatingPercentage?: number;
|
||||
/**
|
||||
* 响应时间区间的唯一标识符
|
||||
*/
|
||||
id?: number;
|
||||
/**
|
||||
* 响应模式名称
|
||||
*/
|
||||
modeName?: string;
|
||||
name?: string;
|
||||
/**
|
||||
* 价格或上浮百分比
|
||||
*/
|
||||
price?: number;
|
||||
/**
|
||||
* 商品ID
|
||||
*/
|
||||
prodId?: number;
|
||||
/**
|
||||
* 响应时间(小时)
|
||||
*/
|
||||
responseHours?: number;
|
||||
/**
|
||||
* 更新者,目前使用 SysUser 的 id 编号
|
||||
*
|
||||
* 使用 String 类型的原因是,未来可能会存在非数值的情况,留好拓展性。
|
||||
*/
|
||||
updater?: string;
|
||||
/**
|
||||
* 最后更新时间
|
||||
*/
|
||||
updateTime?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 预约配置
|
||||
*
|
||||
* ProdReservationInfoVO
|
||||
*/
|
||||
export interface ProdReservationInfoVO {
|
||||
/**
|
||||
* 需提前多少小时预约
|
||||
*/
|
||||
advanceHours?: number;
|
||||
/**
|
||||
* 是否允许更改预约时间 1可以 0不可以
|
||||
*/
|
||||
allowChange?: number;
|
||||
/**
|
||||
* 更改预约时间的时间规则(如服务开始前1小时可更改)
|
||||
*/
|
||||
changeTimeRule?: number;
|
||||
/**
|
||||
* 预约配置的唯一标识符
|
||||
*/
|
||||
id?: number;
|
||||
/**
|
||||
* 允许更改预约时间的最大次数
|
||||
*/
|
||||
maxChangeTimes?: number;
|
||||
/**
|
||||
* 关联的商品ID
|
||||
*/
|
||||
prodId?: number;
|
||||
/**
|
||||
* 预约黑名单日期设置
|
||||
*/
|
||||
prodReservationBlackList?: ProdAdditionalFeeBlackVO[];
|
||||
/**
|
||||
* 预约日期范围 7天 10天 15天 30天
|
||||
*/
|
||||
reservationDateRange?: number;
|
||||
/**
|
||||
* 预约时段设置
|
||||
*/
|
||||
reservationTimeSlots?: string[];
|
||||
/**
|
||||
* 预约时间区间设置
|
||||
*/
|
||||
timeBook?: TimeBookVO;
|
||||
/**
|
||||
* 时间段
|
||||
*/
|
||||
timeSlot?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 预约时间区间设置
|
||||
*
|
||||
* TimeBookVO
|
||||
*/
|
||||
export interface TimeBookVO {
|
||||
/**
|
||||
* 预约时段设置
|
||||
*/
|
||||
reservationTimeSlots?: string[];
|
||||
/**
|
||||
* 时间段
|
||||
*/
|
||||
timeSlot?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 服务区域配置
|
||||
*
|
||||
* ProdServiceAreasInfoVO
|
||||
*/
|
||||
export interface ProdServiceAreasInfoVO {
|
||||
/**
|
||||
* 服务区域地址名称
|
||||
*/
|
||||
areaNameList?: string[];
|
||||
/**
|
||||
* 超区费用(仅在rule_type为accept_with_fee时有效)
|
||||
*/
|
||||
fee?: number;
|
||||
/**
|
||||
* 超区规则的唯一标识符
|
||||
*/
|
||||
id?: number;
|
||||
/**
|
||||
* 关联的商品ID
|
||||
*/
|
||||
prodId?: number;
|
||||
/**
|
||||
* 超区规则类型(0:拒单、2:接单并收取超区费、3:接单并免超区费)
|
||||
*/
|
||||
ruleType?: number;
|
||||
[property: string]: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* 体重配置
|
||||
*
|
||||
* ProdWeightRangePricesSaveInfoVO
|
||||
*/
|
||||
export interface ProdWeightRangePricesSaveInfoVO {
|
||||
/**
|
||||
* 体重是否收费0否1是
|
||||
*/
|
||||
isWeightCharge?: number;
|
||||
/**
|
||||
* 体重配置
|
||||
*/
|
||||
prodWeightConfigList?: ProdWeightRangePricesDO[];
|
||||
}
|
||||
|
||||
/**
|
||||
* 体重区间价格 DO
|
||||
*
|
||||
* ProdWeightRangePricesDO
|
||||
*/
|
||||
export interface ProdWeightRangePricesDO {
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
createTime?: string;
|
||||
/**
|
||||
* 创建者,目前使用 SysUser 的 id 编号
|
||||
*
|
||||
* 使用 String 类型的原因是,未来可能会存在非数值的情况,留好拓展性。
|
||||
*/
|
||||
creator?: string;
|
||||
/**
|
||||
* 是否删除
|
||||
*/
|
||||
deleted?: number;
|
||||
/**
|
||||
* 体重区间价格的唯一标识符
|
||||
*/
|
||||
id?: number;
|
||||
/**
|
||||
* 是否启用该规则0否1是
|
||||
*/
|
||||
isEnabled?: number;
|
||||
/**
|
||||
* 价格
|
||||
*/
|
||||
price?: number;
|
||||
/**
|
||||
* 关联的体重配置ID
|
||||
*/
|
||||
prodId?: number;
|
||||
/**
|
||||
* 更新者,目前使用 SysUser 的 id 编号
|
||||
*
|
||||
* 使用 String 类型的原因是,未来可能会存在非数值的情况,留好拓展性。
|
||||
*/
|
||||
updater?: string;
|
||||
/**
|
||||
* 最后更新时间
|
||||
*/
|
||||
updateTime?: string;
|
||||
/**
|
||||
* 体重区间
|
||||
*/
|
||||
weightRange?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 接单上线配置
|
||||
*
|
||||
* ProductOrderLimitDO
|
||||
*/
|
||||
export interface ProductOrderLimitDO {
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
createTime?: string;
|
||||
/**
|
||||
* 创建者,目前使用 SysUser 的 id 编号
|
||||
*
|
||||
* 使用 String 类型的原因是,未来可能会存在非数值的情况,留好拓展性。
|
||||
*/
|
||||
creator?: string;
|
||||
/**
|
||||
* 是否删除
|
||||
*/
|
||||
deleted?: number;
|
||||
/**
|
||||
* 接单上限配置的唯一标识符
|
||||
*/
|
||||
id?: number;
|
||||
/**
|
||||
* 限制单位'0:按自然天',1:'按自然周',2:'按自然月'
|
||||
*/
|
||||
limitUnit?: number;
|
||||
/**
|
||||
* 上限阈值
|
||||
*/
|
||||
maxOrders?: number;
|
||||
/**
|
||||
* 关联的商品ID
|
||||
*/
|
||||
prodId?: number;
|
||||
/**
|
||||
* 更新者,目前使用 SysUser 的 id 编号
|
||||
*
|
||||
* 使用 String 类型的原因是,未来可能会存在非数值的情况,留好拓展性。
|
||||
*/
|
||||
updater?: string;
|
||||
/**
|
||||
* 最后更新时间
|
||||
*/
|
||||
updateTime?: string;
|
||||
}
|
||||
|
||||
export const getProdServiceRule = async (params: Prod) => {
|
||||
return request("/product/prod/getProdService", {
|
||||
method: "GET",
|
||||
params,
|
||||
});
|
||||
};
|
||||
|
||||
export const uptateProdServiceRule = async (data: ProdServiceVO) => {
|
||||
return request("/product/prod/uptateProdService", {
|
||||
method: "POST",
|
||||
data,
|
||||
});
|
||||
};
|
||||
@@ -1,48 +0,0 @@
|
||||
// @ts-ignore
|
||||
/// <reference path="./typings.d.ts" />
|
||||
import { request } from "@umijs/max";
|
||||
|
||||
/** 获取菜单页面的表 GET /product/category/categoryList */
|
||||
export async function getCategoryList(
|
||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||
params: API.getProductCategoryCategoryListParams,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request("/product/category/categoryList", {
|
||||
method: "GET",
|
||||
params: {
|
||||
...params,
|
||||
},
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 创建产品类目 创建产品类目 POST /product/category/create */
|
||||
export async function postCategoryCreate(
|
||||
body: API.CategorySaveReqVO,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.CommonResultLong>("/product/category/create", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 更新产品类目 更新产品类目 PUT /product/category/update */
|
||||
export async function putCategoryUpdate(
|
||||
body: API.CategorySaveReqVO,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.CommonResultBoolean>("/product/category/update", {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
// @ts-ignore
|
||||
/* eslint-disable */
|
||||
// API 更新时间:
|
||||
// API 唯一标识:
|
||||
import * as product from "./product";
|
||||
import * as category from "./category";
|
||||
export default {
|
||||
product,
|
||||
category,
|
||||
};
|
||||
@@ -1,586 +0,0 @@
|
||||
// @ts-ignore
|
||||
/// <reference path="./typings.d.ts" />
|
||||
import { request } from "@umijs/max";
|
||||
|
||||
/** 创建商品 创建商品 POST /prod/create */
|
||||
export async function postProdCreate(
|
||||
body: API.ProdSaveReqVO,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.CommonResultLong>("/prod/create", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 创建商品 创建商品 POST /product/prod/create */
|
||||
export async function postProductProdCreate(
|
||||
body: API.ProdSaveReqVO,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.CommonResultLong>("/product/prod/create", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 创建商品服务配置 创建商品服务配置 POST /product/prod/createProdService */
|
||||
export async function postProductProdCreateProdService(
|
||||
body: API.ProdServiceVO,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.CommonResultBoolean>("/product/prod/createProdService", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 删除商品 删除商品 DELETE /product/prod/delete */
|
||||
export async function deleteProductProdOpenApiDelete(
|
||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||
params: API.deleteProductProd_openAPI_deleteParams,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.CommonResultBoolean>("/product/prod/delete", {
|
||||
method: "DELETE",
|
||||
params: {
|
||||
...params,
|
||||
},
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 批量删除商品 批量删除商品 DELETE /product/prod/deleteSkuList */
|
||||
export async function deleteProductProdDeleteSkuList(
|
||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||
params: API.deleteProductProdDeleteSkuListParams,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.CommonResultBoolean>("/product/prod/deleteSkuList", {
|
||||
method: "DELETE",
|
||||
params: {
|
||||
...params,
|
||||
},
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 获得商品回收站分页列表 获得商品回收站分页列表 GET /product/prod/getProdRecycleBinPageList */
|
||||
export async function getProductProdGetProdRecycleBinPageList(
|
||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||
params: API.getProductProdGetProdRecycleBinPageListParams,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.CommonResultPageResultProdRestoreListVO>(
|
||||
"/product/prod/getProdRecycleBinPageList",
|
||||
{
|
||||
method: "GET",
|
||||
params: {
|
||||
...params,
|
||||
pageNo: params.pageNo ?? "1",
|
||||
pageSize: params.pageSize ?? "10",
|
||||
},
|
||||
...(options || {}),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/** 获得商品服务信息 获得商品服务信息 GET /product/prod/getProdService */
|
||||
export async function getProductProdGetProdService(
|
||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||
params: API.getProductProdGetProdServiceParams,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.CommonResultProdServiceVO>(
|
||||
"/product/prod/getProdService",
|
||||
{
|
||||
method: "GET",
|
||||
params: {
|
||||
...params,
|
||||
},
|
||||
...(options || {}),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/** 获得商品分页 获得商品分页 GET /product/prod/page */
|
||||
export async function getProductProdPage(
|
||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||
params: API.getProductProdPageParams,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.CommonResultPageResultProdListVO>("/product/prod/page", {
|
||||
method: "GET",
|
||||
params: {
|
||||
...params,
|
||||
pageNo: params.pageNo ?? "1",
|
||||
pageSize: params.pageSize ?? "10",
|
||||
},
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 恢复商品 恢复商品 POST /product/prod/restoreProdList */
|
||||
export async function postProductProdRestoreProdList(
|
||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||
params: API.postProductProdRestoreProdListParams,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.CommonResultBoolean>("/product/prod/restoreProdList", {
|
||||
method: "POST",
|
||||
params: {
|
||||
...params,
|
||||
},
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 更新商品 更新商品 PUT /product/prod/update */
|
||||
export async function putProductProdUpdate(
|
||||
body: API.ProdSaveReqVO,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.CommonResultBoolean>("/product/prod/update", {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 批量上下架 批量上下架 DELETE /product/prod/updateSkuShelfList */
|
||||
export async function deleteProductProdUpdateSkuShelfList(
|
||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||
params: API.deleteProductProdUpdateSkuShelfListParams,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.CommonResultBoolean>("/product/prod/updateSkuShelfList", {
|
||||
method: "DELETE",
|
||||
params: {
|
||||
...params,
|
||||
},
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 修改商品服务配置 修改商品服务配置 POST /product/prod/uptateProdService */
|
||||
export async function postProductProdUptateProdService(
|
||||
body: API.ProdServiceInfoVO,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.CommonResultBoolean>("/product/prod/uptateProdService", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 创建sku扩展服务配置 创建sku扩展服务配置 POST /product/sku/createSkuExtend */
|
||||
export async function postProductSkuCreateSkuExtend(
|
||||
body: API.SkuExtendVO,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.CommonResultBoolean>("/product/sku/createSkuExtend", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 删除单品SKU 删除单品SKU DELETE /product/sku/delete */
|
||||
export async function deleteProductSkuOpenApiDelete(
|
||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||
params: API.deleteProductSku_openAPI_deleteParams,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.CommonResultBoolean>("/product/sku/delete", {
|
||||
method: "DELETE",
|
||||
params: {
|
||||
...params,
|
||||
},
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 删除规格值 删除规格值 PUT /product/sku/deleteProp */
|
||||
export async function putProductSkuDeleteProp(
|
||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||
params: API.putProductSkuDeletePropParams,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.CommonResultBoolean>("/product/sku/deleteProp", {
|
||||
method: "PUT",
|
||||
params: {
|
||||
...params,
|
||||
},
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 批量删除SKU 批量删除SKU DELETE /product/sku/deleteSkuList */
|
||||
export async function deleteProductSkuDeleteSkuList(
|
||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||
params: API.deleteProductSkuDeleteSkuListParams,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.CommonResultBoolean>("/product/sku/deleteSkuList", {
|
||||
method: "DELETE",
|
||||
params: {
|
||||
...params,
|
||||
},
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 禁用或者启用规格值 禁用规格值 PUT /product/sku/disableProp */
|
||||
export async function putProductSkuDisableProp(
|
||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||
params: API.putProductSkuDisablePropParams,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.CommonResultBoolean>("/product/sku/disableProp", {
|
||||
method: "PUT",
|
||||
params: {
|
||||
...params,
|
||||
},
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 获得单品SKU 获得单品SKU GET /product/sku/get */
|
||||
export async function getProductSkuGet(
|
||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||
params: API.getProductSkuGetParams,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.CommonResultSkuRespVO>("/product/sku/get", {
|
||||
method: "GET",
|
||||
params: {
|
||||
...params,
|
||||
},
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 获取规格回收站 获取规格回收站 GET /product/sku/getPropRecycleBinList */
|
||||
export async function getProductSkuGetPropRecycleBinList(
|
||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||
params: API.getProductSkuGetPropRecycleBinListParams,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.CommonResultPageResultProPropRecycleBinVO>(
|
||||
"/product/sku/getPropRecycleBinList",
|
||||
{
|
||||
method: "GET",
|
||||
params: {
|
||||
...params,
|
||||
pageNo: params.pageNo ?? "1",
|
||||
pageSize: params.pageSize ?? "10",
|
||||
},
|
||||
...(options || {}),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/** 获取sku扩展服务配置信息 获取sku扩展服务配置信息 POST /product/sku/getSkuExtend */
|
||||
export async function postProductSkuGetSkuExtend(
|
||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||
params: API.postProductSkuGetSkuExtendParams,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.CommonResultSkuExtendVO>("/product/sku/getSkuExtend", {
|
||||
method: "POST",
|
||||
params: {
|
||||
...params,
|
||||
},
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 获得SKU分页列表 获得SKU分页列表 GET /product/sku/getSkuPageList */
|
||||
export async function getProductSkuGetSkuPageList(
|
||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||
params: API.getProductSkuGetSkuPageListParams,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.CommonResultPageResultSkuDO>(
|
||||
"/product/sku/getSkuPageList",
|
||||
{
|
||||
method: "GET",
|
||||
params: {
|
||||
...params,
|
||||
pageNo: params.pageNo ?? "1",
|
||||
pageSize: params.pageSize ?? "10",
|
||||
},
|
||||
...(options || {}),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/** 获取sku规格 获取sku规格 GET /product/sku/getSKuPropList */
|
||||
export async function getProductSkuGetSKuPropList(
|
||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||
params: API.getProductSkuGetSKuPropListParams,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.CommonResultSkuPropInfoVO>("/product/sku/getSKuPropList", {
|
||||
method: "GET",
|
||||
params: {
|
||||
...params,
|
||||
},
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 获得SKU回收站分页列表 获得SKU回收站分页列表 GET /product/sku/getSkuRecycleBinPageList */
|
||||
export async function getProductSkuGetSkuRecycleBinPageList(
|
||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||
params: API.getProductSkuGetSkuRecycleBinPageListParams,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.CommonResultPageResultSkuRecycleBinVO>(
|
||||
"/product/sku/getSkuRecycleBinPageList",
|
||||
{
|
||||
method: "GET",
|
||||
params: {
|
||||
...params,
|
||||
pageNo: params.pageNo ?? "1",
|
||||
pageSize: params.pageSize ?? "10",
|
||||
},
|
||||
...(options || {}),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/** 恢复规格 恢复规格 POST /product/sku/restorePropList */
|
||||
export async function postProductSkuRestorePropList(
|
||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||
params: API.postProductSkuRestorePropListParams,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.CommonResultBoolean>("/product/sku/restorePropList", {
|
||||
method: "POST",
|
||||
params: {
|
||||
...params,
|
||||
},
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 恢复SKU 恢复SKU POST /product/sku/restoreSkuList */
|
||||
export async function postProductSkuRestoreSkuList(
|
||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||
params: API.postProductSkuRestoreSkuListParams,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.CommonResultBoolean>("/product/sku/restoreSkuList", {
|
||||
method: "POST",
|
||||
params: {
|
||||
...params,
|
||||
},
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 更新单品SKU 更新单品SKU PUT /product/sku/update */
|
||||
export async function putProductSkuUpdate(
|
||||
body: API.SkuSaveReqVO,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.CommonResultBoolean>("/product/sku/update", {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 修改配送方式 修改配送方式 POST /product/sku/updateDeliver */
|
||||
export async function postProductSkuUpdateDeliver(
|
||||
body: API.SkuServiceDeliverDO[],
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.CommonResultBoolean>("/product/sku/updateDeliver", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 修物料配置 修物料配置 POST /product/sku/updateMaterial */
|
||||
export async function postProductSkuUpdateMaterial(
|
||||
body: API.SkuServiceMaterialDO[],
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.CommonResultBoolean>("/product/sku/updateMaterial", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 修改属性规格值 修改属性规格值 PUT /product/sku/updateProdProp */
|
||||
export async function putProductSkuUpdateProdProp(
|
||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||
params: API.putProductSkuUpdateProdPropParams,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.CommonResultBoolean>("/product/sku/updateProdProp", {
|
||||
method: "PUT",
|
||||
params: {
|
||||
...params,
|
||||
},
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 新增统一保存sku规格 更新sku规格 PUT /product/sku/updateProp */
|
||||
export async function putProductSkuUpdateProp(
|
||||
body: API.SkuPropVO,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.CommonResultBoolean>("/product/sku/updateProp", {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 修改属性下面规格值 修改属性下面规格值 PUT /product/sku/updatePropValue */
|
||||
export async function putProductSkuUpdatePropValue(
|
||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||
params: API.putProductSkuUpdatePropValueParams,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.CommonResultBoolean>("/product/sku/updatePropValue", {
|
||||
method: "PUT",
|
||||
params: {
|
||||
...params,
|
||||
},
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 修改扩展服务信息配置(遗体接运扩展服务,遗体清洁配置,追思告别配置,骨灰处理配置......) 修改扩展服务信息配置(遗体接运扩展服务,遗体清洁配置,追思告别配置,骨灰处理配置......) POST /product/sku/updateServiceDetails */
|
||||
export async function postProductSkuUpdateServiceDetails(
|
||||
body: API.SkuServiceDetailsDO[],
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.CommonResultBoolean>("/product/sku/updateServiceDetails", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 修改单品上下架 修改单品上下架 PUT /product/sku/updateSkuShelf */
|
||||
export async function putProductSkuUpdateSkuShelf(
|
||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||
params: API.putProductSkuUpdateSkuShelfParams,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.CommonResultBoolean>("/product/sku/updateSkuShelf", {
|
||||
method: "PUT",
|
||||
params: {
|
||||
...params,
|
||||
},
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 修改单品上下架 修改单品上下架 POST /product/sku/updateSkuShelf */
|
||||
export async function postProductSkuUpdateSkuShelf(
|
||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||
params: API.postProductSkuUpdateSkuShelfParams,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.CommonResultBoolean>("/product/sku/updateSkuShelf", {
|
||||
method: "POST",
|
||||
params: {
|
||||
...params,
|
||||
},
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 批量上下架 批量上下架 PUT /product/sku/updateSkuShelfList */
|
||||
export async function putProductSkuUpdateSkuShelfList(
|
||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||
params: API.putProductSkuUpdateSkuShelfListParams,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.CommonResultBoolean>("/product/sku/updateSkuShelfList", {
|
||||
method: "PUT",
|
||||
params: {
|
||||
...params,
|
||||
},
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 批量上下架 批量上下架 POST /product/sku/updateSkuShelfList */
|
||||
export async function postProductSkuUpdateSkuShelfList(
|
||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||
params: API.postProductSkuUpdateSkuShelfListParams,
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.CommonResultBoolean>("/product/sku/updateSkuShelfList", {
|
||||
method: "POST",
|
||||
params: {
|
||||
...params,
|
||||
},
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 修改接运地址配置 修改接运地址配置 POST /product/sku/updateTransportAdress */
|
||||
export async function postProductSkuUpdateTransportAdress(
|
||||
body: API.SkuServiceTransportDO[],
|
||||
options?: { [key: string]: any }
|
||||
) {
|
||||
return request<API.CommonResultBoolean>(
|
||||
"/product/sku/updateTransportAdress",
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
}
|
||||
);
|
||||
}
|
||||
2139
src/services/prodApi/typings.d.ts
vendored
2139
src/services/prodApi/typings.d.ts
vendored
File diff suppressed because it is too large
Load Diff
348
src/services/trade/order/detail.ts
Normal file
348
src/services/trade/order/detail.ts
Normal file
@@ -0,0 +1,348 @@
|
||||
export interface TradeServeInfo {
|
||||
boneInfo?: {
|
||||
boneUrl?: string[];
|
||||
diedReason?: string;
|
||||
diedTime?: string;
|
||||
petName?: string;
|
||||
petType?: string;
|
||||
weight?: string;
|
||||
};
|
||||
subInfo?: {
|
||||
changeRule?: string;
|
||||
merchantRemark?: string;
|
||||
pickUpAddress?: string;
|
||||
sendAddress?: string;
|
||||
subOrder?: string;
|
||||
subType?: string;
|
||||
userRemark?: string;
|
||||
};
|
||||
userId?: number;
|
||||
userMobile?: number;
|
||||
userName?: string;
|
||||
userNickName?: string;
|
||||
userRemark?: string;
|
||||
}
|
||||
export interface TradeExtendCostInfo {
|
||||
chargeType?: string; //收费方式
|
||||
costName?: string; //超区域服务费
|
||||
serveArea?: string; //可服务区域
|
||||
targetArea?: string; //目标区域
|
||||
weight?: string; //体型/体重
|
||||
respTime?: string; //响应时间
|
||||
respMode?: string; //响应模式
|
||||
chargeTime?: string; //收费时段
|
||||
payInfo?: {
|
||||
payPrice?: string;
|
||||
totalPrice?: string;
|
||||
discountPrice?: string;
|
||||
};
|
||||
refundPrice?: string;
|
||||
serveExtFee?: string; //服务附加费
|
||||
}
|
||||
export interface Serve {
|
||||
count?: string;
|
||||
handPrice?: number;
|
||||
price?: string;
|
||||
serveDesc?: string;
|
||||
serveName?: string;
|
||||
serveUrl?: string;
|
||||
}
|
||||
export interface TradeExtendServeInfo {
|
||||
discountPrice?: string;
|
||||
payPrice?: number;
|
||||
refundCount?: string;
|
||||
refundMoney?: string;
|
||||
serve?: Serve[];
|
||||
tempType?: number;
|
||||
totalPrice?: string;
|
||||
serveType?: string; //"处理方式"
|
||||
serveTitle?: string;
|
||||
address?: string;
|
||||
deliveryType?: string;
|
||||
sendUser?: string;
|
||||
userMobile?: string;
|
||||
receiveUser?: string;
|
||||
}
|
||||
|
||||
export interface TradeOrderDetailRespVO {
|
||||
/**
|
||||
* 取消原因
|
||||
*/
|
||||
cancelReason?: string;
|
||||
/**
|
||||
* 取消时间
|
||||
*/
|
||||
cancelTime?: string;
|
||||
/**
|
||||
* 下单时间
|
||||
*/
|
||||
createTime?: string;
|
||||
/**
|
||||
* 优惠金额
|
||||
*/
|
||||
discountPrice?: number;
|
||||
/**
|
||||
* 财务状态
|
||||
*/
|
||||
financeStatus?: number;
|
||||
/**
|
||||
* 订单完成时间
|
||||
*/
|
||||
finishTime?: string;
|
||||
/**
|
||||
* 订单编号
|
||||
*/
|
||||
id?: number;
|
||||
/**
|
||||
* 商品列表
|
||||
*/
|
||||
items?: Item[];
|
||||
/**
|
||||
* 实收金额
|
||||
*/
|
||||
livePrice?: number;
|
||||
/**
|
||||
* 商家备注
|
||||
*/
|
||||
merchantRemark?: string;
|
||||
/**
|
||||
* 订单类目id
|
||||
*/
|
||||
orderCategoryId?: number;
|
||||
/**
|
||||
* 订单类目名称
|
||||
*/
|
||||
orderCategoryName?: string;
|
||||
/**
|
||||
* 订单编号
|
||||
*/
|
||||
orderNum?: string;
|
||||
/**
|
||||
* 订单状态
|
||||
* {@link TradeOrderStatusEnum#getStatus()}
|
||||
*/
|
||||
orderStatus?: number;
|
||||
/**
|
||||
* 订单来源
|
||||
* {@link TerminalEnum#getTerminal()}
|
||||
*/
|
||||
orderTerminal?: number;
|
||||
/**
|
||||
* 订单类型
|
||||
* {@link TradeOrderTypeEnum#getType()}
|
||||
*/
|
||||
orderType?: number;
|
||||
/**
|
||||
* 支付渠道 (线上线下)
|
||||
*/
|
||||
payChannelCode?: number;
|
||||
/**
|
||||
* 交易流水号
|
||||
*/
|
||||
payOrderId?: string;
|
||||
/**
|
||||
* 实付金额
|
||||
*/
|
||||
payPrice?: number;
|
||||
/**
|
||||
* 支付时间
|
||||
*/
|
||||
payTime?: string;
|
||||
/**
|
||||
* 支付方式
|
||||
*/
|
||||
payType?: number;
|
||||
/**
|
||||
* 订单金额
|
||||
*/
|
||||
price?: number;
|
||||
/**
|
||||
* 保障状态
|
||||
*/
|
||||
propertyStatus?: number;
|
||||
/**
|
||||
* 保障时间
|
||||
*/
|
||||
propertyTime?: string;
|
||||
/**
|
||||
* 退款金额
|
||||
*/
|
||||
refundPrice?: number;
|
||||
/**
|
||||
* 退款时间
|
||||
*/
|
||||
refundTime?: string;
|
||||
/**
|
||||
* 订单状态流转记录
|
||||
*/
|
||||
statusList?: TradeOrderStatusRespVo[];
|
||||
/**
|
||||
* 附加费信息(order_serve_info配置)
|
||||
*/
|
||||
tradeExtendCostInfo?: TradeExtendCostInfo[];
|
||||
/**
|
||||
* 扩展服务信息(order_serve_info配置)
|
||||
*/
|
||||
tradeExtendServeInfo?: TradeExtendServeInfo[][];
|
||||
/**
|
||||
* 服务信息(order_serve_info配置)
|
||||
*/
|
||||
tradeServeInfo?: TradeServeInfo;
|
||||
/**
|
||||
* 用户头像
|
||||
*/
|
||||
userAvatar?: string;
|
||||
/**
|
||||
* 用户编号
|
||||
*/
|
||||
userId?: number;
|
||||
/**
|
||||
* 用户手机号
|
||||
*/
|
||||
userMobile?: string;
|
||||
/**
|
||||
* 用户姓名
|
||||
*/
|
||||
userName?: string;
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
userNickName?: string;
|
||||
/**
|
||||
* 用户备注 - 必填,示例:你猜
|
||||
*/
|
||||
userRemark?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* com.tashow.cloud.trade.controller.admin.order.vo.TradeOrderDetailRespVO.Item
|
||||
*
|
||||
* Item
|
||||
*/
|
||||
export interface Item {
|
||||
/**
|
||||
* 购买数量 - 必填,示例:1
|
||||
*/
|
||||
count?: number;
|
||||
/**
|
||||
* 商品优惠(总) - 必填,示例:100
|
||||
*/
|
||||
discountPrice?: number;
|
||||
/**
|
||||
* 成本价
|
||||
*/
|
||||
expensePrice?: number;
|
||||
/**
|
||||
* 到手价
|
||||
*/
|
||||
handedPrice?: number;
|
||||
/**
|
||||
* 店铺名称
|
||||
*/
|
||||
id?: number;
|
||||
/**
|
||||
* 订单类目id
|
||||
*/
|
||||
orderCategoryId?: number;
|
||||
/**
|
||||
* 订单类目名称
|
||||
*/
|
||||
orderCategoryName?: string;
|
||||
/**
|
||||
* 商品实付金额(总) - 必填,示例:100
|
||||
*/
|
||||
payPrice?: number;
|
||||
/**
|
||||
* 商品图片 - 必填,示例:https://www.iocoder.cn/1.png
|
||||
*/
|
||||
picUrl?: string;
|
||||
/**
|
||||
* 商品原价(单) - 必填,示例:100
|
||||
*/
|
||||
price?: number;
|
||||
/**
|
||||
* 属性数组
|
||||
*/
|
||||
properties?: string;
|
||||
/**
|
||||
* 累计退款数量
|
||||
*/
|
||||
refundCount?: number;
|
||||
/**
|
||||
* 累计退款金额
|
||||
*/
|
||||
refundPrice?: number;
|
||||
/**
|
||||
* 服务内容
|
||||
*/
|
||||
serveContent?: string;
|
||||
/**
|
||||
* 店铺logo
|
||||
*/
|
||||
shopLogo?: string;
|
||||
/**
|
||||
* 店铺名称
|
||||
*/
|
||||
shopName?: string;
|
||||
/**
|
||||
* 商品 SKU 编号 - 必填,示例:1
|
||||
*/
|
||||
skuId?: number;
|
||||
/**
|
||||
* 商品规格
|
||||
*/
|
||||
skuName?: string;
|
||||
/**
|
||||
* 商品 SPU 编号 - 必填,示例:1
|
||||
*/
|
||||
spuId?: number;
|
||||
/**
|
||||
* 商品 SPU 名称 - 必填,示例:芋道源码
|
||||
*/
|
||||
spuName?: string;
|
||||
/**
|
||||
* 商品总价
|
||||
*/
|
||||
totalPrice?: number;
|
||||
/**
|
||||
* 单位
|
||||
*/
|
||||
unit?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* com.tashow.cloud.trade.controller.admin.order.vo.TradeOrderStatusRespVo
|
||||
*
|
||||
* TradeOrderStatusRespVo
|
||||
*/
|
||||
export interface TradeOrderStatusRespVo {
|
||||
/**
|
||||
* 操作后状态
|
||||
*/
|
||||
afterStatus?: number;
|
||||
/**
|
||||
* 操作前状态
|
||||
*/
|
||||
beforeStatus?: number;
|
||||
/**
|
||||
* 订单日志信息
|
||||
*/
|
||||
content?: string;
|
||||
/**
|
||||
* 订单日志信息
|
||||
*/
|
||||
createTime?: string;
|
||||
id?: number;
|
||||
/**
|
||||
* 操作类型
|
||||
*
|
||||
* {@link TradeOrderOperateTypeEnum}
|
||||
*/
|
||||
operateType?: number;
|
||||
/**
|
||||
* 订单号
|
||||
*
|
||||
* 关联{@link TradeOrderDO#getId()}
|
||||
*/
|
||||
orderId?: number;
|
||||
}
|
||||
@@ -1,425 +1,6 @@
|
||||
import { request } from "@umijs/max";
|
||||
export interface TradeReq {
|
||||
/**
|
||||
* 售后状态,示例:1
|
||||
*/
|
||||
afterSaleStatus?: number;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
createTime?: string[];
|
||||
/**
|
||||
* 财务状态,示例:1
|
||||
*/
|
||||
financeStatus?: number;
|
||||
/**
|
||||
* 卖家名称
|
||||
*/
|
||||
merchantName?: string;
|
||||
/**
|
||||
* 订单类目id,示例:1
|
||||
*/
|
||||
orderCategoryId?: number;
|
||||
/**
|
||||
* 订单状态,示例:1
|
||||
*/
|
||||
orderStatus?: number;
|
||||
/**
|
||||
* 订单来源,示例:1
|
||||
*/
|
||||
orderTerminal?: number;
|
||||
/**
|
||||
* 页码,从 1 开始", example = "1
|
||||
*/
|
||||
pageNo?: number;
|
||||
/**
|
||||
* 每页条数,最大值为 100"
|
||||
*/
|
||||
pageSize?: number;
|
||||
/**
|
||||
* 聚合检索字段(商品名称,商品id,订单号)
|
||||
*/
|
||||
prodSearch?: string;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
subTime?: string[];
|
||||
/**
|
||||
* 预约类型,示例:1
|
||||
*/
|
||||
subType?: number;
|
||||
/**
|
||||
* 聚合检索字段 买家昵称/手机号
|
||||
*/
|
||||
userSearch?: string;
|
||||
}
|
||||
export interface TradeOrderPageRespVO {
|
||||
/**
|
||||
* 购买的商品数量
|
||||
*/
|
||||
count?: number;
|
||||
/**
|
||||
* 下单时间
|
||||
*/
|
||||
createTime?: string;
|
||||
/**
|
||||
* 财务状态
|
||||
*/
|
||||
financeStatus?: string;
|
||||
/**
|
||||
* 到手价
|
||||
*/
|
||||
handedPrice?: number;
|
||||
/**
|
||||
* 订单编号
|
||||
*/
|
||||
id?: number;
|
||||
/**
|
||||
* 订单类目
|
||||
*/
|
||||
orderCategoryName?: string;
|
||||
/**
|
||||
* 订单流水号
|
||||
*/
|
||||
orderNum?: string;
|
||||
/**
|
||||
* 订单状态
|
||||
*/
|
||||
orderStatus?: number;
|
||||
/**
|
||||
* 订单来源
|
||||
*/
|
||||
orderTerminal?: number;
|
||||
/**
|
||||
* 预约时间
|
||||
*/
|
||||
subTime?: string;
|
||||
/**
|
||||
* 到手价
|
||||
*/
|
||||
payPrice?: number;
|
||||
/**
|
||||
* 支付方式
|
||||
*/
|
||||
payType?: string;
|
||||
/**
|
||||
* 商品图片
|
||||
*/
|
||||
picUrl?: string;
|
||||
/**
|
||||
* 单价
|
||||
*/
|
||||
price?: number;
|
||||
/**
|
||||
* 服务地址
|
||||
*/
|
||||
serveAddress?: string;
|
||||
/**
|
||||
* 商品规格
|
||||
*/
|
||||
skuName?: string;
|
||||
/**
|
||||
* 商品名称
|
||||
*/
|
||||
spuName?: string;
|
||||
/**
|
||||
* 单位
|
||||
*/
|
||||
unit?: string;
|
||||
/**
|
||||
* 用户头像
|
||||
*/
|
||||
userAvatar?: string;
|
||||
/**
|
||||
* 用户编号
|
||||
*/
|
||||
userId?: number;
|
||||
/**
|
||||
* 用户手机号
|
||||
*/
|
||||
userMobile?: string;
|
||||
/**
|
||||
* 用户姓名
|
||||
*/
|
||||
userName?: string;
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
userNickName?: string;
|
||||
/**
|
||||
* 用户备注 - 必填,示例:你猜
|
||||
*/
|
||||
userRemark?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回数据
|
||||
*
|
||||
* TradeOrderDetailRespVO
|
||||
*/
|
||||
export interface TradeOrderDetailRespVO {
|
||||
/**
|
||||
* 附加费信息
|
||||
*/
|
||||
tradeExtendCostInfo?: TradeExtendCostInfo;
|
||||
/**
|
||||
* 扩展服务信息
|
||||
*/
|
||||
tradeExtendServeInfo?: TradeExtendServeInfo;
|
||||
/**
|
||||
* 基本信息
|
||||
*/
|
||||
tradeOrderInfoBase?: TradeOrderBaseInfo;
|
||||
/**
|
||||
* 商品信息
|
||||
*/
|
||||
tradeProductInfo?: TradeProductInfo;
|
||||
/**
|
||||
* 服务信息
|
||||
*/
|
||||
tradeServeInfo?: TradeServeInfo;
|
||||
[property: string]: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* 附加费信息
|
||||
*
|
||||
* TradeExtendCostInfo
|
||||
*/
|
||||
export interface TradeExtendCostInfo {
|
||||
/**
|
||||
* 内部存储动态属性的 Map,键为属性名称,值为属性值
|
||||
*/
|
||||
properties?: MapObject;
|
||||
[property: string]: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* 内部存储动态属性的 Map,键为属性名称,值为属性值
|
||||
*
|
||||
* MapObject
|
||||
*/
|
||||
export interface MapObject {
|
||||
key?: { [key: string]: any };
|
||||
[property: string]: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* 扩展服务信息
|
||||
*
|
||||
* TradeExtendServeInfo
|
||||
*/
|
||||
export interface TradeExtendServeInfo {
|
||||
/**
|
||||
* 内部存储动态属性的 Map,键为属性名称,值为属性值
|
||||
*/
|
||||
properties?: MapObject;
|
||||
[property: string]: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* 基本信息
|
||||
*
|
||||
* TradeOrderBaseInfo
|
||||
*/
|
||||
export interface TradeOrderBaseInfo {
|
||||
/**
|
||||
* 取消原因
|
||||
*/
|
||||
cancelReason?: string;
|
||||
/**
|
||||
* 取消时间
|
||||
*/
|
||||
cancelTime?: string;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
createTime?: string;
|
||||
/**
|
||||
* 优惠金额
|
||||
*/
|
||||
discountPrice?: string;
|
||||
/**
|
||||
* 完成时间
|
||||
*/
|
||||
finishTime?: string;
|
||||
/**
|
||||
* 订单id
|
||||
*/
|
||||
id?: string;
|
||||
/**
|
||||
* 实收金额
|
||||
*/
|
||||
livePrice?: string;
|
||||
/**
|
||||
* 商家备注
|
||||
*/
|
||||
merchantRemark?: string;
|
||||
/**
|
||||
* 订单类目
|
||||
*/
|
||||
orderCategoryId?: string;
|
||||
orderCategoryName?: string;
|
||||
/**
|
||||
* 订单编号
|
||||
*/
|
||||
orderNo?: string;
|
||||
/**
|
||||
* 订单状态
|
||||
*/
|
||||
orderStatus?: string;
|
||||
/**
|
||||
* 订单来源
|
||||
*/
|
||||
orderTerminal?: string;
|
||||
/**
|
||||
* 订单类型
|
||||
*/
|
||||
orderType?: string;
|
||||
/**
|
||||
* 支付渠道 (线上线下)
|
||||
*/
|
||||
payChannelCode?: string;
|
||||
/**
|
||||
* 交易流水号
|
||||
*/
|
||||
payOrderId?: string;
|
||||
/**
|
||||
* 订单金额
|
||||
*/
|
||||
payPrice?: number;
|
||||
/**
|
||||
* 支付时间
|
||||
*/
|
||||
payTime?: string;
|
||||
/**
|
||||
* 支付方式(支付宝微信)
|
||||
*/
|
||||
payType?: string;
|
||||
/**
|
||||
* 订单总价
|
||||
*/
|
||||
price?: string;
|
||||
/**
|
||||
* 保障状态
|
||||
*/
|
||||
propertyStatus?: string;
|
||||
/**
|
||||
* 保障时间
|
||||
*/
|
||||
propertyTime?: string;
|
||||
/**
|
||||
* 退款金额
|
||||
*/
|
||||
refundPrice?: string;
|
||||
/**
|
||||
* 退款时间
|
||||
*/
|
||||
refundTime?: string;
|
||||
/**
|
||||
* 用户信息
|
||||
*/
|
||||
userInfo?: string;
|
||||
userAvatar?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 商品信息
|
||||
*
|
||||
* TradeProductInfo
|
||||
*/
|
||||
export interface TradeProductInfo {
|
||||
/**
|
||||
* 购买数量
|
||||
*/
|
||||
count?: number;
|
||||
/**
|
||||
* 优惠金额
|
||||
*/
|
||||
discountPrice?: number;
|
||||
/**
|
||||
* 成本价
|
||||
*/
|
||||
expensePrice?: number;
|
||||
/**
|
||||
* 到手价(单价 - 优惠)
|
||||
*/
|
||||
handedPrice?: number;
|
||||
/**
|
||||
* 实付金额
|
||||
*/
|
||||
payPrice?: number;
|
||||
/**
|
||||
* 商品单价
|
||||
*/
|
||||
price?: number;
|
||||
/**
|
||||
* 保障
|
||||
*/
|
||||
properties?: string[];
|
||||
/**
|
||||
* 累计退款数量
|
||||
*/
|
||||
refundCount?: number;
|
||||
/**
|
||||
* 累计退款金额
|
||||
*/
|
||||
refundPrice?: number;
|
||||
/**
|
||||
* 服务内容
|
||||
*/
|
||||
serveContent?: string;
|
||||
/**
|
||||
* 店铺log
|
||||
*/
|
||||
shopLogoUrl?: string;
|
||||
/**
|
||||
* 店铺名称
|
||||
*/
|
||||
shopName?: string;
|
||||
/**
|
||||
* skuid
|
||||
*/
|
||||
skuId?: number;
|
||||
/**
|
||||
* 商品规格
|
||||
*/
|
||||
skuName?: string;
|
||||
/**
|
||||
* 商品规格图
|
||||
*/
|
||||
skuPicUrl?: string;
|
||||
/**
|
||||
* 商品id
|
||||
*/
|
||||
spuId?: number;
|
||||
/**
|
||||
* 商品名称
|
||||
*/
|
||||
spuName?: string;
|
||||
/**
|
||||
* 商品总价
|
||||
*/
|
||||
totalPrice?: number;
|
||||
/**
|
||||
* 商品单位
|
||||
*/
|
||||
unit?: string;
|
||||
[property: string]: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* 服务信息
|
||||
*
|
||||
* TradeServeInfo
|
||||
*/
|
||||
export interface TradeServeInfo {
|
||||
/**
|
||||
* 内部存储动态属性的 Map,键为属性名称,值为属性值
|
||||
*/
|
||||
properties?: MapObject;
|
||||
[property: string]: any;
|
||||
}
|
||||
import { TradeOrderPageRespVO, TradeReq } from "./list";
|
||||
import { TradeOrderDetailRespVO } from "./detail";
|
||||
|
||||
export const getTradeOrderPage = async (params: TradeReq) => {
|
||||
return request<PageResult<TradeOrderPageRespVO[]>>("/trade/order/page", {
|
||||
@@ -429,8 +10,10 @@ export const getTradeOrderPage = async (params: TradeReq) => {
|
||||
};
|
||||
|
||||
export const getTradeOrderDetail = async (id: number) => {
|
||||
return request<IResponse<TradeOrderDetailRespVO>>("/trade/order/get-detail", {
|
||||
return request<TradeOrderDetailRespVO>("/trade/order/get-detail", {
|
||||
method: "GET",
|
||||
params: { id },
|
||||
});
|
||||
};
|
||||
|
||||
export { TradeOrderPageRespVO, TradeOrderDetailRespVO, TradeReq };
|
||||
|
||||
194
src/services/trade/order/list.ts
Normal file
194
src/services/trade/order/list.ts
Normal file
@@ -0,0 +1,194 @@
|
||||
/**
|
||||
* CommonResultPageResultTradeOrderPageRespVO
|
||||
*/
|
||||
|
||||
/**
|
||||
* com.tashow.cloud.trade.controller.admin.order.vo.TradeOrderPageRespVO
|
||||
*
|
||||
* TradeOrderPageRespVO
|
||||
*/
|
||||
export interface TradeOrderPageRespVO {
|
||||
serveAddress?: string;
|
||||
subTime?: string;
|
||||
payPrice?: string;
|
||||
payType?: string;
|
||||
financeStatus?: string;
|
||||
/**
|
||||
* 下单时间
|
||||
*/
|
||||
createTime?: string;
|
||||
/**
|
||||
* 订单完成时间
|
||||
*/
|
||||
finishTime?: string;
|
||||
/**
|
||||
* 订单编号
|
||||
*/
|
||||
id?: number;
|
||||
/**
|
||||
* 订单项列表
|
||||
*/
|
||||
items?: Item[];
|
||||
/**
|
||||
* 订单流水号
|
||||
*/
|
||||
orderNum?: string;
|
||||
/**
|
||||
* 订单状态
|
||||
*/
|
||||
orderStatus?: number;
|
||||
/**
|
||||
* 订单来源
|
||||
*/
|
||||
orderTerminal?: number;
|
||||
/**
|
||||
* 订单类型
|
||||
* {@link TradeOrderTypeEnum#getType()}
|
||||
*/
|
||||
orderType?: number;
|
||||
/**
|
||||
* 支付剩余时间
|
||||
*/
|
||||
payLastTime?: string;
|
||||
/**
|
||||
* 店铺log
|
||||
*/
|
||||
shopLogo?: string;
|
||||
/**
|
||||
* 店铺名称
|
||||
*/
|
||||
shopName?: string;
|
||||
/**
|
||||
* 用户头像
|
||||
*/
|
||||
userAvatar?: string;
|
||||
/**
|
||||
* 用户编号
|
||||
*/
|
||||
userId?: number;
|
||||
/**
|
||||
* 用户手机号
|
||||
*/
|
||||
userMobile?: string;
|
||||
/**
|
||||
* 用户姓名
|
||||
*/
|
||||
userName?: string;
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
userNickName?: string;
|
||||
/**
|
||||
* 用户备注 - 必填,示例:你猜
|
||||
*/
|
||||
userRemark?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* com.tashow.cloud.trade.controller.admin.order.vo.TradeOrderPageRespVO.Item
|
||||
*
|
||||
* Item
|
||||
*/
|
||||
export interface Item {
|
||||
id?: number;
|
||||
/**
|
||||
*
|
||||
* 购买数量 - 必填,示例:1
|
||||
*/
|
||||
count?: number;
|
||||
/**
|
||||
* 商品优惠(总) - 必填,示例:100
|
||||
*/
|
||||
discountPrice?: number;
|
||||
/**
|
||||
* 到手价
|
||||
*/
|
||||
handedPrice?: number;
|
||||
/**
|
||||
* 商品实付金额(总) - 必填,示例:100
|
||||
*/
|
||||
payPrice?: number;
|
||||
/**
|
||||
* 商品图片 - 必填,示例:https://www.iocoder.cn/1.png
|
||||
*/
|
||||
picUrl?: string;
|
||||
/**
|
||||
* 商品原价(单) - 必填,示例:100
|
||||
*/
|
||||
price?: number;
|
||||
/**
|
||||
* 服务地址
|
||||
*/
|
||||
serveAddress?: string;
|
||||
/**
|
||||
* 商品规格
|
||||
*/
|
||||
skuName?: string;
|
||||
/**
|
||||
* 商品 SPU 名称 - 必填,示例:芋道源码
|
||||
*/
|
||||
spuName?: string;
|
||||
/**
|
||||
* 预约时间
|
||||
*/
|
||||
subTime?: string;
|
||||
/**
|
||||
* 单位
|
||||
*/
|
||||
unit?: string;
|
||||
}
|
||||
|
||||
export interface TradeReq {
|
||||
/**
|
||||
* 售后状态,示例:1
|
||||
*/
|
||||
afterSaleStatus?: number;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
createTime?: string[];
|
||||
/**
|
||||
* 财务状态,示例:1
|
||||
*/
|
||||
financeStatus?: number;
|
||||
/**
|
||||
* 卖家名称
|
||||
*/
|
||||
merchantName?: string;
|
||||
/**
|
||||
* 订单类目id,示例:1
|
||||
*/
|
||||
orderCategoryId?: number;
|
||||
/**
|
||||
* 订单状态,示例:1
|
||||
*/
|
||||
orderStatus?: number;
|
||||
/**
|
||||
* 订单来源,示例:1
|
||||
*/
|
||||
orderTerminal?: number;
|
||||
/**
|
||||
* 页码,从 1 开始", example = "1
|
||||
*/
|
||||
pageNo: number;
|
||||
/**
|
||||
* 每页条数,最大值为 100"
|
||||
*/
|
||||
pageSize: number;
|
||||
/**
|
||||
* 聚合检索字段(商品名称,商品id,订单号)
|
||||
*/
|
||||
prodSearch?: string;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
subTime?: string[];
|
||||
/**
|
||||
* 预约类型,示例:1
|
||||
*/
|
||||
subType?: number;
|
||||
/**
|
||||
* 聚合检索字段 买家昵称/手机号
|
||||
*/
|
||||
userSearch?: string;
|
||||
}
|
||||
1
src/typings.d.ts
vendored
1
src/typings.d.ts
vendored
@@ -14,3 +14,4 @@ declare module 'omit.js';
|
||||
declare module 'numeral';
|
||||
declare module 'mockjs';
|
||||
declare module 'react-fittext';
|
||||
declare module 'react-video-thumbnail';
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { Navigate } from '@umijs/max';
|
||||
import { Spin } from 'antd';
|
||||
import React from 'react';
|
||||
import type { MenuVO } from '@/services/system/menu';
|
||||
|
||||
export const loopMenuItem = (menus: any[], pId: number | string): any[] => {
|
||||
// console.log(menus, "menus");
|
||||
return menus.flatMap((item) => {
|
||||
export const loopMenuItem = (menus: MenuVO[], pId: number | string): any[] => {
|
||||
return menus.map((item) => {
|
||||
let Component: React.ComponentType<any> | null = null;
|
||||
if (item.component && item.component.length > 0) {
|
||||
if (item.component && item.component.trim().length > 0) {
|
||||
// 防止配置了路由,但本地暂未添加对应的页面,产生的错误
|
||||
Component = React.lazy(() => {
|
||||
const importComponent = () => import(`@/pages/${item.component}`);
|
||||
@@ -14,56 +13,106 @@ export const loopMenuItem = (menus: any[], pId: number | string): any[] => {
|
||||
return importComponent().catch(import404);
|
||||
});
|
||||
}
|
||||
if (item.children && item.children.length > 0) {
|
||||
return [
|
||||
{
|
||||
path: item.path,
|
||||
name: item.name,
|
||||
// icon: item.icon,
|
||||
id: item.id,
|
||||
parentId: pId,
|
||||
children: [
|
||||
{
|
||||
path: item.path,
|
||||
element: (
|
||||
<Navigate
|
||||
to={getFirstLeafPath(item.children, item.path)}
|
||||
replace
|
||||
/>
|
||||
),
|
||||
},
|
||||
...loopMenuItem(item.children, item.menuID),
|
||||
],
|
||||
},
|
||||
];
|
||||
} else {
|
||||
return [
|
||||
{
|
||||
path: item.path,
|
||||
name: item.name,
|
||||
// icon: item.icon,
|
||||
id: item.menuID,
|
||||
parentId: pId,
|
||||
element: (
|
||||
<React.Suspense
|
||||
fallback={<Spin style={{ width: '100%', height: '100%' }} />}
|
||||
>
|
||||
{Component && <Component />}
|
||||
</React.Suspense>
|
||||
),
|
||||
children: [], // 添加缺失的 children 属性
|
||||
},
|
||||
];
|
||||
|
||||
const routeItem: any = {
|
||||
path: item.path,
|
||||
name: item.name,
|
||||
icon: '',
|
||||
id: item.id,
|
||||
parentId: pId,
|
||||
hideInMenu: !item.visible,
|
||||
children: [],
|
||||
};
|
||||
|
||||
// 只有当 Component 存在时才添加 element 属性
|
||||
if (Component) {
|
||||
routeItem.element = (
|
||||
<React.Suspense
|
||||
fallback={<Spin style={{ width: '100%', height: '100%' }} />}
|
||||
>
|
||||
<Component />
|
||||
</React.Suspense>
|
||||
);
|
||||
} else if (item.children && item.children.length > 0) {
|
||||
// routeItem.redirect = "/prod/list";
|
||||
// // 只有当没有 Component 但有子菜单时,才添加重定向
|
||||
// const firstLeafPath = getFirstLeafPath(item.children);
|
||||
// // 确保 firstLeafPath 存在,且不是一个会导致循环的路径
|
||||
// if (
|
||||
// firstLeafPath &&
|
||||
// firstLeafPath !== item.path &&
|
||||
// firstLeafPath.length > 0
|
||||
// ) {
|
||||
// // 在 UmiJS 中,路径是相对的,不需要构建完整路径
|
||||
// const separator =
|
||||
// item.path.endsWith("/") || firstLeafPath.startsWith("/") ? "" : "/";
|
||||
// const fullPath = `${item.path}${separator}${firstLeafPath}`;
|
||||
// console.log(`Redirecting from ${item.path} to ${fullPath}`);
|
||||
// routeItem.element = <Navigate to={fullPath} replace={true} />;
|
||||
// }
|
||||
}
|
||||
// 处理子菜单
|
||||
if (item.children && item.children.length > 0) {
|
||||
routeItem.children = loopMenuItem(item.children, item.id);
|
||||
}
|
||||
|
||||
return routeItem;
|
||||
});
|
||||
};
|
||||
|
||||
function getFirstLeafPath(menus: any[], parentPath: string): string {
|
||||
const firstMenu = menus[0];
|
||||
const currentPath = `${parentPath}/${firstMenu.path}`;
|
||||
if (firstMenu.children && firstMenu.children.length > 0) {
|
||||
return getFirstLeafPath(firstMenu.children, currentPath);
|
||||
} else {
|
||||
return currentPath;
|
||||
}
|
||||
}
|
||||
// return menus.flatMap((item) => {
|
||||
// let Component: React.ComponentType<any> | null = null;
|
||||
// if (item.component && item.component.length > 0) {
|
||||
// // 防止配置了路由,但本地暂未添加对应的页面,产生的错误
|
||||
// Component = React.lazy(() => {
|
||||
// const importComponent = () => import(`@/pages/${item.component}`);
|
||||
// const import404 = () => import("@/pages/404");
|
||||
// return importComponent().catch(import404);
|
||||
// });
|
||||
// }
|
||||
// if (item.children && item.children.length > 0) {
|
||||
// return [
|
||||
// {
|
||||
// path: item.path,
|
||||
// hideInMenu: false,
|
||||
// parentId: pId,
|
||||
// id: item.id,
|
||||
// children: [...loopMenuItem(item.children, item.id)], // 添加缺失的 children 属性
|
||||
// },
|
||||
// ];
|
||||
// } else {
|
||||
// return [
|
||||
// {
|
||||
// path: item.path,
|
||||
// name: item.name,
|
||||
// // icon: item.icon,
|
||||
// id: item.id,
|
||||
// parentId: pId,
|
||||
// hideInMenu: !item.visible,
|
||||
// element: (
|
||||
// <React.Suspense
|
||||
// fallback={<Spin style={{ width: "100%", height: "100%" }} />}
|
||||
// >
|
||||
// {Component && <Component />}
|
||||
// </React.Suspense>
|
||||
// ),
|
||||
// },
|
||||
// ];
|
||||
// }
|
||||
// });
|
||||
// return [];
|
||||
// };
|
||||
|
||||
// function getFirstLeafPath(menus: any[], parentPath: string): string {
|
||||
// const firstMenu = menus[0];
|
||||
// const currentPath = `${parentPath}/${firstMenu.path}`;
|
||||
// if (firstMenu.children && firstMenu.children.length > 0) {
|
||||
// if (!firstMenu.hideInMenu) {
|
||||
// return getFirstLeafPath(firstMenu.children, currentPath);
|
||||
// } else {
|
||||
// return getFirstLeafPath(firstMenu.children, parentPath);
|
||||
// }
|
||||
// } else {
|
||||
// return currentPath;
|
||||
// }
|
||||
// }
|
||||
|
||||
Reference in New Issue
Block a user