diff --git a/src/api/orders/index.ts b/src/api/orders/index.ts new file mode 100644 index 0000000..4a38ef5 --- /dev/null +++ b/src/api/orders/index.ts @@ -0,0 +1,106 @@ +/** + * 订单管理 API + * 注意:/admin 前缀已通过 VITE_API_BASE_URL 统一注入(见 .env.*),此文件中只写业务路径。 + */ +import { get, post } from '@/utils/request'; +import { USE_MOCK, MOCK_DELAY } from '@/config/mock'; +import { buildMockOrderListPage } from '@/config/mock/orderList'; +import { MOCK_ORDER_DETAIL } from '@/config/mock/orderDetail'; +import { + MOCK_ORDER_PLAYER_LIST, + buildMockOrderPlayerListPage, +} from '@/config/mock/orderPlayerList'; +import type { + OrderListQueryParams, + OrderDetailQueryParams, + OrderPlayerListQueryParams, + RetryRefundParams, + TournamentAdminOrderPageVO, + TournamentAdminOrderInfoVO, + TournamentAdminOrderInfoPageVO, + PageData, + ApiResult, +} from './types'; + +export type { + TournamentAdminOrderPageVO, + TournamentAdminOrderInfoVO, + TournamentAdminOrderInfoPageVO, + InnerRefundInfo, + OrderListQueryParams, + OrderDetailQueryParams, + OrderPlayerListQueryParams, + RetryRefundParams, + PageData, + ApiResult, +} from './types'; + +const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); + +/** + * 订单管理 - 订单分页 + * GET /admin/manager/order/page → /manager/order/page + */ +export async function getOrderList( + params: OrderListQueryParams, +): Promise>> { + if (USE_MOCK) { + await delay(MOCK_DELAY); + const page = Number(params.page) || 1; + const limit = Number(params.limit) || 10; + return { + code: 200, + msg: 'success', + data: buildMockOrderListPage(page, limit), + }; + } + return get('/manager/order/page', params as Record); +} + +/** + * 订单管理 - 订单详情 + * GET /admin/manager/order/info → /manager/order/info + */ +export async function getOrderDetail( + params: OrderDetailQueryParams, +): Promise> { + if (USE_MOCK) { + await delay(MOCK_DELAY); + return { + code: 200, + msg: 'success', + data: { ...MOCK_ORDER_DETAIL }, + }; + } + return get('/manager/order/info', params as Record); +} + +/** + * 订单管理 - 订单详情 - 选手列表 + * GET /admin/manager/order/info/page → /manager/order/info/page + */ +export async function getOrderPlayerList( + params: OrderPlayerListQueryParams, +): Promise>> { + if (USE_MOCK) { + await delay(MOCK_DELAY); + const page = Number(params.page) || 1; + const limit = Number(params.limit) || 10; + return { + code: 200, + msg: 'success', + data: buildMockOrderPlayerListPage(page, limit), + }; + } + return get('/manager/order/info/page', params as Record); +} + +/** + * 订单管理 - 重新退款 + * POST /admin/manager/order/retryRefund → /manager/order/retryRefund + */ +export function retryRefundOrder( + params: RetryRefundParams, +): Promise>> { + return post('/manager/order/retryRefund', params); +} diff --git a/src/api/orders/types.ts b/src/api/orders/types.ts new file mode 100644 index 0000000..540f3db --- /dev/null +++ b/src/api/orders/types.ts @@ -0,0 +1,185 @@ +/** + * 订单管理 — 类型定义 + * 对应 OpenAPI: /admin/manager/order/page + */ + +/** 订单列表项 */ +export interface TournamentAdminOrderPageVO { + /** 订单编号 */ + orderNo: string; + /** 选手ID */ + uniqueId: number; + /** 赛事名称 */ + name: string; + /** 选手名称 */ + realName: string; + /** 手机号 */ + phone: string; + /** 报名比赛组别名称 */ + categoryName: string; + /** 报名人名称 */ + creatorName: string; + /** 报名人手机号 */ + creatorPhone: string; + /** 报名人一共报名人数 */ + creatorSignupCount: number; + /** 订单金额;0.00格式 */ + creatorSignupFee: string; + /** 优惠金额;0.00格式 */ + creatorSignupFeeDiscount: string; + /** 实付金额;0.00格式 */ + creatorSignupFeeActual: string; + /** 退款金额;0.00格式 */ + creatorSignupFeeRefund: string; + /** 订单时间;yyyy.MM.dd HH:mm:ss */ + orderTime: string; + /** 支付时间;yyyy.MM.dd HH:mm:ss */ + payTime: string; + /** 订单状态;1=已支付,2=部分退款,3=全部退款,4=已关闭,-1=其他 */ + orderStatus: number; + /** 退款状态;1=无退款,2=退款成功,3=退款失败,-1=其他 */ + refundStatus: number; +} + +/** 订单列表查询参数 */ +export interface OrderListQueryParams { + page?: string; + limit?: string; + /** 订单时间开始 yyyy-MM-dd */ + orderDate?: string; + /** 订单时间结束 yyyy-MM-dd */ + orderDateEnd?: string; + /** 订单编号 */ + orderNo?: string; + /** 赛事名称 */ + tName?: string; + /** 选手名称 */ + sName?: string; + /** + * 订单状态 + * 不传=全部、1=支付成功,2=部分退款,3=全部退款,4=超时关闭 + */ + status?: string; + /** + * 退款状态 + * 不传=全部、0=退款失败,1=退款成功 + */ + refundStatus?: string; +} + +/** 分页数据 */ +export interface PageData { + total: number; + list: T[]; +} + +/** 统一响应包裹 */ +export interface ApiResult { + code: number; + msg: string; + data: T; +} + +// ============================================================ +// 订单详情(对应 /manager/order/info) +// ============================================================ + +/** 退款记录 */ +export interface InnerRefundInfo { + /** 已退金额;0.00格式 */ + refundedAmount: string; + /** 总退款次数(接口实际返回 string) */ + totalRefundCount: string; + /** 退款金额;0.00格式 */ + refundAmount: string; + /** 是否全部退款;0=否,1=是(接口实际返回 string) */ + isFullRefund: string; + /** 退款方式 */ + refundMethod: string; + /** 退款申请时间 */ + refundApplyTime: string; + /** 第三方退款单号 */ + refundOutTradeNo: string; + /** 退款完成时间 */ + refundTime: string; +} + +/** 订单详情 */ +export interface TournamentAdminOrderInfoVO { + /** 赛事名称 */ + tournamentName: string; + /** 订单编号 */ + orderNumber: string; + /** 订单时间 */ + orderTime: string; + /** 支付时间 */ + payTime: string; + /** 订单金额;0.00格式 */ + orderAmount: string; + /** 优惠金额;0.00格式 */ + discountAmount: string; + /** 实付金额;0.00格式 */ + payAmount: string; + /** 退款金额;0.00格式 */ + refundAmount: string; + /** 退款信息list */ + refundInfoList: InnerRefundInfo[]; +} + +/** 订单详情查询参数 */ +export interface OrderDetailQueryParams { + /** 订单编号 */ + orderNo: string; + /** 选手ID */ + uniqueId: string; +} + +// ============================================================ +// 订单详情 — 选手列表(对应 /manager/order/info/page) +// ============================================================ + +/** 订单下选手信息 */ +export interface TournamentAdminOrderInfoPageVO { + /** 姓名 */ + realName: string; + /** 性别;1=男,2=女(接口实际返回 string) */ + gender: string; + /** 手机号 */ + phone: string; + /** 证件号 */ + idCard: string; + /** 证件号图片 */ + idCardImg: string; + /** 选手身份证图片列表 */ + idCardImgList: string[]; + /** 选手组别名称 */ + categoryName: string; + /** 订单金额;0.00 */ + orderAmount: string; + /** 优惠金额;0.00 */ + discountAmount: string; + /** 实付金额;0.00 */ + payAmount: string; + /** 退款金额;0.00 */ + refundAmount: string; +} + +/** 选手列表查询参数 */ +export interface OrderPlayerListQueryParams { + /** 订单编号 */ + orderNo: string; + /** 选手ID */ + uniqueId: string; + page: string; + limit: string; +} + +// ============================================================ +// 重新退款(对应 /manager/order/retryRefund) +// ============================================================ + +/** 重新退款请求参数 */ +export interface RetryRefundParams { + /** 支付单号 */ + payOrderNo: string; +} diff --git a/src/config/mock/eventDetail.ts b/src/config/mock/eventDetail.ts index 87b8329..5dd51c8 100644 --- a/src/config/mock/eventDetail.ts +++ b/src/config/mock/eventDetail.ts @@ -5,7 +5,7 @@ * 对应接口:`GET /manager/tm/info` * 类型:`TournamentAdminInfoVO` */ -import type { TournamentAdminInfoVO } from '@/api/events'; +import type { TournamentAdminInfoVO } from '@/api/events/types'; export const MOCK_EVENT_DETAIL: TournamentAdminInfoVO = { name: '第二届全国地学羽毛球邀请赛', diff --git a/src/config/mock/eventList.ts b/src/config/mock/eventList.ts index 6681d3c..55ac581 100644 --- a/src/config/mock/eventList.ts +++ b/src/config/mock/eventList.ts @@ -5,7 +5,7 @@ * 对应接口:`GET /manager/tm/page` * 类型:`TournamentAdminVO[]` */ -import type { TournamentAdminVO, PageData } from '@/api/events'; +import type { TournamentAdminVO, PageData } from '@/api/events/types'; export const MOCK_EVENT_LIST: TournamentAdminVO[] = [ { diff --git a/src/config/mock/eventSignup.ts b/src/config/mock/eventSignup.ts index 4b8940c..20ffce5 100644 --- a/src/config/mock/eventSignup.ts +++ b/src/config/mock/eventSignup.ts @@ -5,7 +5,11 @@ * 对应接口:`GET /manager/tm/info/signupPage` * 类型:`TournamentAdminInfoSignupVO[]` */ -import type { TournamentAdminInfoSignupVO, PageData, SignupListQueryParams } from '@/api/events'; +import type { + TournamentAdminInfoSignupVO, + PageData, + SignupListQueryParams, +} from '@/api/events/types'; export const MOCK_SIGNUP_LIST: TournamentAdminInfoSignupVO[] = [ { diff --git a/src/config/mock/orderDetail.ts b/src/config/mock/orderDetail.ts new file mode 100644 index 0000000..24dae23 --- /dev/null +++ b/src/config/mock/orderDetail.ts @@ -0,0 +1,41 @@ +/** + * 订单详情弹窗假数据 + * + * 使用页面:`src/pages/events/orders/components/OrderDetailModal.tsx` + * 对应接口:`GET /manager/order/info` + * 类型:`TournamentAdminOrderInfoVO` + */ +import type { TournamentAdminOrderInfoVO } from '@/api/orders/types'; + +export const MOCK_ORDER_DETAIL: TournamentAdminOrderInfoVO = { + tournamentName: '2026全国青少年羽毛球锦标赛暨体育文化交流大会', + orderNumber: 'ORD20260700001', + orderTime: '2026.07.12 08:11:07', + payTime: '2026.07.12 08:12:30', + orderAmount: '188.00', + discountAmount: '20.00', + payAmount: '168.00', + refundAmount: '50.00', + refundInfoList: [ + { + refundedAmount: '30.00', + totalRefundCount: '2', + refundAmount: '30.00', + isFullRefund: '0', + refundMethod: '原路退回(微信支付)', + refundApplyTime: '2026.07.15 09:30:00', + refundOutTradeNo: '5030000789202607150930000123', + refundTime: '2026.07.15 09:35:00', + }, + { + refundedAmount: '20.00', + totalRefundCount: '2', + refundAmount: '20.00', + isFullRefund: '1', + refundMethod: '原路退回(微信支付)', + refundApplyTime: '2026.07.16 14:00:00', + refundOutTradeNo: '5030000789202607161400000456', + refundTime: '', + }, + ], +}; diff --git a/src/config/mock/orderList.ts b/src/config/mock/orderList.ts new file mode 100644 index 0000000..8e66a44 --- /dev/null +++ b/src/config/mock/orderList.ts @@ -0,0 +1,256 @@ +/** + * 订单列表页假数据 + * + * 使用页面:`src/pages/events/orders/index.tsx` + * 对应接口:`GET /manager/order/page` + * 类型:`TournamentAdminOrderPageVO[]` + */ +import type { TournamentAdminOrderPageVO, PageData } from '@/api/orders/types'; + +export const MOCK_ORDER_LIST: TournamentAdminOrderPageVO[] = [ + { + orderNo: 'ORD20260700001', + uniqueId: 101, + name: '2026全国青少年羽毛球锦标赛暨体育文化交流大会', + realName: '张选手', + phone: '13800138001', + categoryName: '男子青年组', + creatorName: '张报名', + creatorPhone: '13800138001', + creatorSignupCount: 2, + creatorSignupFee: '188.00', + creatorSignupFeeDiscount: '20.00', + creatorSignupFeeActual: '168.00', + creatorSignupFeeRefund: '0.00', + orderTime: '2026.07.12 08:11:07', + payTime: '2026.07.12 08:12:30', + orderStatus: 1, + refundStatus: 1, + }, + { + orderNo: 'ORD20260700002', + uniqueId: 102, + name: '国际马拉松城市联赛', + realName: '李选手', + phone: '13900139002', + categoryName: '女子青年组', + creatorName: '李报名', + creatorPhone: '13900139002', + creatorSignupCount: 1, + creatorSignupFee: '256.50', + creatorSignupFeeDiscount: '10.00', + creatorSignupFeeActual: '246.50', + creatorSignupFeeRefund: '50.00', + orderTime: '2026.07.11 11:28:20', + payTime: '2026.07.11 11:30:05', + orderStatus: 2, + refundStatus: 2, + }, + { + orderNo: 'ORD20260700003', + uniqueId: 103, + name: '全民健身运动会', + realName: '王选手', + phone: '13700137003', + categoryName: '男子中年组', + creatorName: '王报名', + creatorPhone: '13700137003', + creatorSignupCount: 1, + creatorSignupFee: '399.00', + creatorSignupFeeDiscount: '0.00', + creatorSignupFeeActual: '399.00', + creatorSignupFeeRefund: '399.00', + orderTime: '2026.07.10 14:45:33', + payTime: '2026.07.10 14:46:10', + orderStatus: 3, + refundStatus: 2, + }, + { + orderNo: 'ORD20260700004', + uniqueId: 104, + name: '2026全国青少年羽毛球锦标赛暨体育文化交流大会', + realName: '赵选手', + phone: '13600136004', + categoryName: '女子中年组', + creatorName: '赵报名', + creatorPhone: '13600136004', + creatorSignupCount: 3, + creatorSignupFee: '128.00', + creatorSignupFeeDiscount: '20.00', + creatorSignupFeeActual: '108.00', + creatorSignupFeeRefund: '0.00', + orderTime: '2026.07.09 18:02:46', + payTime: '2026.07.09 18:03:15', + orderStatus: 4, + refundStatus: 1, + }, + { + orderNo: 'ORD20260700005', + uniqueId: 105, + name: '国际马拉松城市联赛', + realName: '张选手', + phone: '13800138001', + categoryName: '男子青年组', + creatorName: '张报名', + creatorPhone: '13800138001', + creatorSignupCount: 2, + creatorSignupFee: '520.00', + creatorSignupFeeDiscount: '10.00', + creatorSignupFeeActual: '510.00', + creatorSignupFeeRefund: '0.00', + orderTime: '2026.07.08 21:19:59', + payTime: '2026.07.08 21:21:20', + orderStatus: 1, + refundStatus: 1, + }, + { + orderNo: 'ORD20260700006', + uniqueId: 106, + name: '全民健身运动会', + realName: '李选手', + phone: '13900139002', + categoryName: '女子青年组', + creatorName: '李报名', + creatorPhone: '13900139002', + creatorSignupCount: 1, + creatorSignupFee: '188.00', + creatorSignupFeeDiscount: '0.00', + creatorSignupFeeActual: '188.00', + creatorSignupFeeRefund: '0.00', + orderTime: '2026.07.07 00:36:12', + payTime: '2026.07.07 00:37:00', + orderStatus: 1, + refundStatus: 1, + }, + { + orderNo: 'ORD20260700007', + uniqueId: 107, + name: '2026全国青少年羽毛球锦标赛暨体育文化交流大会', + realName: '王选手', + phone: '13700137003', + categoryName: '男子中年组', + creatorName: '王报名', + creatorPhone: '13700137003', + creatorSignupCount: 1, + creatorSignupFee: '256.50', + creatorSignupFeeDiscount: '20.00', + creatorSignupFeeActual: '236.50', + creatorSignupFeeRefund: '236.50', + orderTime: '2026.07.06 03:53:25', + payTime: '2026.07.06 03:54:00', + orderStatus: 3, + refundStatus: 3, + }, + { + orderNo: 'ORD20260700008', + uniqueId: 108, + name: '国际马拉松城市联赛', + realName: '赵选手', + phone: '13600136004', + categoryName: '女子中年组', + creatorName: '赵报名', + creatorPhone: '13600136004', + creatorSignupCount: 3, + creatorSignupFee: '399.00', + creatorSignupFeeDiscount: '10.00', + creatorSignupFeeActual: '389.00', + creatorSignupFeeRefund: '30.00', + orderTime: '2026.07.05 07:10:38', + payTime: '2026.07.05 07:11:00', + orderStatus: 2, + refundStatus: 2, + }, + { + orderNo: 'ORD20260700009', + uniqueId: 109, + name: '全民健身运动会', + realName: '张选手', + phone: '13800138001', + categoryName: '男子青年组', + creatorName: '张报名', + creatorPhone: '13800138001', + creatorSignupCount: 2, + creatorSignupFee: '128.00', + creatorSignupFeeDiscount: '0.00', + creatorSignupFeeActual: '128.00', + creatorSignupFeeRefund: '0.00', + orderTime: '2026.07.04 10:27:51', + payTime: '2026.07.04 10:28:30', + orderStatus: 4, + refundStatus: 1, + }, + { + orderNo: 'ORD20260700010', + uniqueId: 110, + name: '2026全国青少年羽毛球锦标赛暨体育文化交流大会', + realName: '李选手', + phone: '13900139002', + categoryName: '女子青年组', + creatorName: '李报名', + creatorPhone: '13900139002', + creatorSignupCount: 1, + creatorSignupFee: '520.00', + creatorSignupFeeDiscount: '20.00', + creatorSignupFeeActual: '500.00', + creatorSignupFeeRefund: '0.00', + orderTime: '2026.07.03 13:44:04', + payTime: '2026.07.03 13:45:00', + orderStatus: 1, + refundStatus: 1, + }, + { + orderNo: 'ORD20260700011', + uniqueId: 111, + name: '国际马拉松城市联赛', + realName: '王选手', + phone: '13700137003', + categoryName: '男子中年组', + creatorName: '王报名', + creatorPhone: '13700137003', + creatorSignupCount: 1, + creatorSignupFee: '188.00', + creatorSignupFeeDiscount: '10.00', + creatorSignupFeeActual: '178.00', + creatorSignupFeeRefund: '50.00', + orderTime: '2026.07.02 17:01:17', + payTime: '2026.07.02 17:02:00', + orderStatus: 2, + refundStatus: 3, + }, + { + orderNo: 'ORD20260700012', + uniqueId: 112, + name: '全民健身运动会', + realName: '赵选手', + phone: '13600136004', + categoryName: '女子中年组', + creatorName: '赵报名', + creatorPhone: '13600136004', + creatorSignupCount: 3, + creatorSignupFee: '256.50', + creatorSignupFeeDiscount: '0.00', + creatorSignupFeeActual: '256.50', + creatorSignupFeeRefund: '0.00', + orderTime: '2026.07.01 20:18:30', + payTime: '2026.07.01 20:19:00', + orderStatus: 1, + refundStatus: 1, + }, +]; + +/** 金额汇总假数据(汇总接口独立,此为 mock 占位) */ +export const MOCK_ORDER_SUMMARY = { + totalOrderAmount: 113255.0, + totalPaidAmount: 113255.0, + totalRefundAmount: 1255.0, +}; + +/** 构建分页响应 */ +export function buildMockOrderListPage( + page: number, + limit: number, +): PageData { + const start = (page - 1) * limit; + const list = MOCK_ORDER_LIST.slice(start, start + limit); + return { total: MOCK_ORDER_LIST.length, list }; +} diff --git a/src/config/mock/orderPlayerList.ts b/src/config/mock/orderPlayerList.ts new file mode 100644 index 0000000..287e20a --- /dev/null +++ b/src/config/mock/orderPlayerList.ts @@ -0,0 +1,104 @@ +/** + * 订单详情 — 选手列表假数据 + * + * 使用页面:`src/pages/events/orders/components/OrderDetailModal.tsx` + * 对应接口:`GET /manager/order/info/page` + * 类型:`TournamentAdminOrderInfoPageVO[]` + */ +import type { TournamentAdminOrderInfoPageVO } from '@/api/orders/types'; + +export const MOCK_ORDER_PLAYER_LIST: TournamentAdminOrderInfoPageVO[] = [ + { + realName: '张三', + gender: '1', + phone: '13800138001', + idCard: '110101199001011234', + idCardImg: 'https://picsum.photos/seed/idcard1/96/64', + idCardImgList: [ + 'https://picsum.photos/seed/idcard1a/96/64', + 'https://picsum.photos/seed/idcard1b/96/64', + ], + categoryName: '男子青年组', + orderAmount: '100.00', + discountAmount: '10.00', + payAmount: '90.00', + refundAmount: '0.00', + }, + { + realName: '李四', + gender: '1', + phone: '13900139002', + idCard: '110101199002022345', + idCardImg: '', + idCardImgList: [], + categoryName: '男子青年组', + orderAmount: '88.00', + discountAmount: '10.00', + payAmount: '78.00', + refundAmount: '50.00', + }, + { + realName: '王芳', + gender: '2', + phone: '13700137003', + idCard: '110101199103033456', + idCardImg: 'https://picsum.photos/seed/idcard3/96/64', + idCardImgList: ['https://picsum.photos/seed/idcard3a/96/64'], + categoryName: '女子双打', + orderAmount: '0.00', + discountAmount: '0.00', + payAmount: '0.00', + refundAmount: '-', + }, + { + realName: '赵六', + gender: '1', + phone: '13600136004', + idCard: '110101199204044567', + idCardImg: '', + idCardImgList: [], + categoryName: '女子双打', + orderAmount: '50.00', + discountAmount: '0.00', + payAmount: '50.00', + refundAmount: '-', + }, + { + realName: '孙七', + gender: '2', + phone: '13500135005', + idCard: '110101199305055678', + idCardImg: 'https://picsum.photos/seed/idcard5/96/64', + idCardImgList: [ + 'https://picsum.photos/seed/idcard5a/96/64', + 'https://picsum.photos/seed/idcard5b/96/64', + ], + categoryName: '男子青年组', + orderAmount: '60.00', + discountAmount: '5.00', + payAmount: '55.00', + refundAmount: '0.00', + }, + { + realName: '周八', + gender: '1', + phone: '13400134006', + idCard: '110101199406066789', + idCardImg: 'https://picsum.photos/seed/idcard6/96/64', + idCardImgList: ['https://picsum.photos/seed/idcard6a/96/64'], + categoryName: '男子中年组', + orderAmount: '120.00', + discountAmount: '20.00', + payAmount: '100.00', + refundAmount: '-', + }, +]; + +export function buildMockOrderPlayerListPage( + page: number, + limit: number, +): { total: number; list: TournamentAdminOrderInfoPageVO[] } { + const start = (page - 1) * limit; + const list = MOCK_ORDER_PLAYER_LIST.slice(start, start + limit); + return { total: MOCK_ORDER_PLAYER_LIST.length, list }; +} diff --git a/src/pages/events/banner/model/useBannerModel.ts b/src/pages/events/banner/model/useBannerModel.ts index 258cb8b..0bab510 100644 --- a/src/pages/events/banner/model/useBannerModel.ts +++ b/src/pages/events/banner/model/useBannerModel.ts @@ -194,7 +194,7 @@ export function useBannerModel() { setPagination({ ...pagination.value, total: SORTED_MOCK_DATA.length }); message.success('查询成功'); } catch (error: any) { - message.error(error.msg || '查询失败'); + console.error('Banner查询失败:', error); } finally { setLoading(false); } @@ -247,7 +247,7 @@ export function useBannerModel() { handleCloseModal(); handleSearch(); } catch (error: any) { - message.error(error.msg || '操作失败'); + console.error('Banner提交失败:', error); } finally { setFormSubmitting(false); } @@ -262,7 +262,7 @@ export function useBannerModel() { message.success('删除成功'); handleSearch(); } catch (error: any) { - message.error(error.msg || '删除失败'); + console.error('Banner删除失败:', error); } finally { setLoading(false); } @@ -284,7 +284,7 @@ export function useBannerModel() { ); message.success(`${actionText}成功`); } catch (error: any) { - message.error(error.msg || '操作失败'); + console.error('Banner状态切换失败:', error); } finally { setLoading(false); } diff --git a/src/pages/events/list/components/EventDetailModal.tsx b/src/pages/events/list/components/EventDetailModal.tsx index 6e3edc4..10af427 100644 --- a/src/pages/events/list/components/EventDetailModal.tsx +++ b/src/pages/events/list/components/EventDetailModal.tsx @@ -140,7 +140,7 @@ export default defineComponent({ message.error(res.msg || '获取详情失败'); } } catch (e: any) { - message.error(e.msg || '获取详情失败'); + console.error('获取赛事详情失败:', e); } finally { setDetailLoading(false); } diff --git a/src/pages/events/list/index.tsx b/src/pages/events/list/index.tsx index ab8b1cb..f0fb526 100644 --- a/src/pages/events/list/index.tsx +++ b/src/pages/events/list/index.tsx @@ -159,7 +159,7 @@ export default defineComponent({ message.error(res.msg || `${actionText}失败`); } } catch (e: any) { - message.error(e.msg || `${actionText}失败`); + console.error(`${actionText}失败:`, e); } }, }); @@ -230,17 +230,23 @@ export default defineComponent({ (filterForm.name = val.target?.value ?? val ?? '')} onPressEnter={handleSearch} /> + (filterForm.createName = val.target?.value ?? val ?? '') + } onPressEnter={handleSearch} /> diff --git a/src/pages/events/list/model/useEventListModel.ts b/src/pages/events/list/model/useEventListModel.ts index b867c8b..5c30fa1 100644 --- a/src/pages/events/list/model/useEventListModel.ts +++ b/src/pages/events/list/model/useEventListModel.ts @@ -205,11 +205,11 @@ export function useEventListModel() { if (filterForm.region.length > 0) { params.areaName = filterForm.region[filterForm.region.length - 1]; } - if (debouncedName.value.trim()) { - params.name = debouncedName.value.trim(); + if (filterForm.name.trim()) { + params.name = filterForm.name.trim(); } - if (debouncedCreator.value.trim()) { - params.createName = debouncedCreator.value.trim(); + if (filterForm.createName.trim()) { + params.createName = filterForm.createName.trim(); } if (filterForm.status) { params.status = filterForm.status; @@ -249,6 +249,7 @@ export function useEventListModel() { setLoading(true); try { const queryParams = buildQueryParams(); + console.log('赛事列表查询参数:', queryParams); const res = await getEventList(queryParams); if (res.code === 200) { @@ -258,7 +259,7 @@ export function useEventListModel() { message.error(res.msg || '查询失败'); } } catch (error: any) { - message.error(error.msg || '查询失败'); + console.error('赛事列表查询失败:', error); } finally { setLoading(false); } @@ -277,6 +278,8 @@ export function useEventListModel() { filterForm.idCardImg = ''; setPagination({ current: 1, pageSize: 10, total: 0 }); setDataSource([]); + // 等待 debounce 生效后自动查询 + setTimeout(() => handleSearch(), 350); }, 500); const handlePageChange = (page: number, pageSize: number) => { diff --git a/src/pages/events/orders/components/OrderDetailModal.tsx b/src/pages/events/orders/components/OrderDetailModal.tsx index 66ad6fa..b94ab68 100644 --- a/src/pages/events/orders/components/OrderDetailModal.tsx +++ b/src/pages/events/orders/components/OrderDetailModal.tsx @@ -1,39 +1,74 @@ -import { defineComponent, computed } from 'vue'; -import { Modal, Table, Button, Pagination, Image, Space } from 'ant-design-vue'; +import { defineComponent, computed, onMounted } from 'vue'; +import { Modal, Table, Button, Pagination, Image, Space, Spin } from 'ant-design-vue'; import { StatusTag, type StatusTagTone } from '@/components'; import { useState } from '@/hooks'; +import { + getOrderDetail, + getOrderPlayerList, + type TournamentAdminOrderInfoVO, + type InnerRefundInfo, + type TournamentAdminOrderInfoPageVO, +} from '@/api/orders'; import styles from './OrderDetailModal.module.less'; interface OrderDetailModalProps { visible: boolean; - record: any; + orderNo: string; + uniqueId: string; onClose: () => void; - /** 触发"重新退款"二次确认对话框 */ - onReRefund: (record: any) => void; + onReRefund: () => void; } +// ===== 选手表格列(对齐 TournamentAdminOrderInfoPageVO) ===== +const GENDER_MAP: Record = { '1': '男', '2': '女' }; +const formatGender = (v: string) => GENDER_MAP[v] ?? v; +const formatMoney = (v: string) => { + const n = parseFloat(v); + return isNaN(n) ? '-' : `${n.toFixed(2)}`; +}; + const PLAYER_COLUMNS = [ - { title: '真实姓名', dataIndex: 'name', key: 'name', width: 100, align: 'center' as const }, - { title: '性别', dataIndex: 'gender', key: 'gender', width: 80, align: 'center' as const }, + { + title: '真实姓名', + dataIndex: 'realName', + key: 'realName', + width: 100, + align: 'center' as const, + }, + { + title: '性别', + dataIndex: 'gender', + key: 'gender', + width: 60, + align: 'center' as const, + customRender: ({ text }: { text: string }) => formatGender(text), + }, { title: '手机号', dataIndex: 'phone', key: 'phone', width: 130 }, - { title: '证件号', dataIndex: 'idNo', key: 'idNo', width: 180 }, + { title: '证件号', dataIndex: 'idCard', key: 'idCard', width: 180 }, { title: '证件图片', - dataIndex: 'idImg', - key: 'idImg', + key: 'idCardImg', width: 170, - customRender: ({ text }: { text: string[] }) => ( - - {(text || []).map((src) => ( - - ))} - - ), + customRender: ({ record }: { record: TournamentAdminOrderInfoPageVO }) => { + const urls = record.idCardImgList?.length + ? record.idCardImgList + : record.idCardImg + ? [record.idCardImg] + : []; + if (!urls.length) return -; + return ( + + {urls.map((src) => ( + + ))} + + ); + }, }, { title: '比赛组别', - dataIndex: 'groupName', - key: 'groupName', + dataIndex: 'categoryName', + key: 'categoryName', width: 110, align: 'center' as const, }, @@ -43,7 +78,7 @@ const PLAYER_COLUMNS = [ key: 'orderAmount', width: 100, align: 'right' as const, - customRender: ({ text }: { text: number }) => `${(text || 0).toFixed(2)}`, + customRender: ({ text }: { text: string }) => formatMoney(text), }, { title: '优惠金额', @@ -51,15 +86,15 @@ const PLAYER_COLUMNS = [ key: 'discountAmount', width: 100, align: 'right' as const, - customRender: ({ text }: { text: number }) => `${(text || 0).toFixed(2)}`, + customRender: ({ text }: { text: string }) => formatMoney(text), }, { title: '实付金额', - dataIndex: 'paidAmount', - key: 'paidAmount', + dataIndex: 'payAmount', + key: 'payAmount', width: 100, align: 'right' as const, - customRender: ({ text }: { text: number }) => `${(text || 0).toFixed(2)}`, + customRender: ({ text }: { text: string }) => formatMoney(text), }, { title: '退款金额', @@ -67,7 +102,7 @@ const PLAYER_COLUMNS = [ key: 'refundAmount', width: 100, align: 'right' as const, - customRender: ({ text }: { text: number }) => (text ? text.toFixed(2) : '-'), + customRender: ({ text }: { text: string }) => (text === '-' || !text ? '-' : formatMoney(text)), }, ]; @@ -80,43 +115,79 @@ export default defineComponent({ name: 'OrderDetailModal', props: { visible: { type: Boolean, default: false }, - record: { type: Object, default: () => ({}) }, + orderNo: { type: String, default: '' }, + uniqueId: { type: String, default: '' }, onClose: { type: Function, required: true }, onReRefund: { type: Function, required: true }, }, setup(props: OrderDetailModalProps) { - const [refundPage, setRefundPage] = useState(1); - const [refundPageSize, setRefundPageSize] = useState(2); + // ===== 数据状态 ===== + const [detail, setDetail] = useState(null); + const [detailLoading, setDetailLoading] = useState(true); - /** 退款记录 */ - const refundRecords = computed(() => props.record?.refundRecords || []); + // ===== 选手列表分页状态 ===== + const [players, setPlayers] = useState([]); + const [playersLoading, setPlayersLoading] = useState(true); + const [playerPage, setPlayerPage] = useState(1); + const [playerTotal, setPlayerTotal] = useState(0); + const playerPageSize = 5; + + /** 获取选手列表(分页) */ + const fetchPlayers = async (page: number) => { + setPlayersLoading(true); + try { + const res = await getOrderPlayerList({ + orderNo: props.orderNo, + uniqueId: props.uniqueId, + page: String(page), + limit: String(playerPageSize), + }); + if (res.code === 200) { + setPlayers(res.data.list); + setPlayerTotal(res.data.total); + setPlayerPage(page); + } + } finally { + setPlayersLoading(false); + } + }; + + // ===== 退款记录分页 ===== + const [refundPage, setRefundPage] = useState(1); + const [refundPageSize] = useState(2); + + const refundRecords = computed(() => detail.value?.refundInfoList || []); const hasRefund = computed(() => refundRecords.value.length > 0); - /** 当前页展示的退款记录 */ const pagedRefunds = computed(() => { const start = (refundPage.value - 1) * refundPageSize.value; return refundRecords.value.slice(start, start + refundPageSize.value); }); - /** 已退金额合计 */ - const totalRefunded = computed(() => - refundRecords.value - .filter((r) => r.status === 'success') - .reduce((sum, r) => sum + (r.amount || 0), 0), - ); + const totalRefunded = computed(() => { + const records = refundRecords.value; + if (!records.length) return 0; + return records.reduce((sum, r) => sum + parseFloat(r.refundAmount || '0'), 0); + }); - const handleRefundPageChange = (page: number, pageSize: number) => { + // ===== 初始化:获取详情 + 选手列表第一页 ===== + onMounted(async () => { + const params = { orderNo: props.orderNo, uniqueId: props.uniqueId }; + + const [detailRes] = await Promise.all([getOrderDetail(params), fetchPlayers(1)]); + + if (detailRes.code === 200) { + setDetail(detailRes.data); + } + setDetailLoading(false); + }); + + const handlePlayerPageChange = (page: number) => { + fetchPlayers(page); + }; + + const handleRefundPageChange = (page: number) => { setRefundPage(page); - setRefundPageSize(pageSize); - }; - - const handleConfirm = () => { - // 无退款信息时:仅关闭弹窗 - props.onClose(); - }; - - const handleReRefund = () => { - props.onReRefund(props.record); }; return () => ( @@ -139,130 +210,159 @@ export default defineComponent({ -
- {/* ===== 订单信息 ===== */} -
-
- 赛事名称: - {props.record?.eventName} -
-
- 订单编号: - {props.record?.orderId} -
-
- 订单时间: - {props.record?.orderTime} -
-
- 支付时间: - {props.record?.payTime} -
-
- 订单金额: - {props.record?.totalAmount?.toFixed(2)}元 -
-
- 优惠金额: - {(props.record?.discountAmount || 0).toFixed(2)}元 -
-
- 实付金额: - {props.record?.paidAmount?.toFixed(2)}元 -
-
- 退款金额: - {props.record?.refundAmount?.toFixed(2)}元 -
+ {detailLoading.value ? ( +
+
- - {/* ===== 选手信息 ===== */} -
-
选手信息
- - - - {/* ===== 退款记录 ===== */} -
-
- 退款记录 + ) : detail.value ? ( +
+ {/* ===== 订单信息 ===== */} +
+
+ 赛事名称: + {detail.value.tournamentName} +
+
+ 订单编号: + {detail.value.orderNumber} +
+
+ 订单时间: + {detail.value.orderTime} +
+
+ 支付时间: + {detail.value.payTime} +
+
+ 订单金额: + {formatMoney(detail.value.orderAmount)}元 +
+
+ 优惠金额: + {formatMoney(detail.value.discountAmount)}元 +
+
+ 实付金额: + {formatMoney(detail.value.payAmount)}元 +
+
+ 退款金额: + {formatMoney(detail.value.refundAmount)}元 +
- {hasRefund.value ? ( - <> -
- 已退金额:{totalRefunded.value.toFixed(2)}元 - 退款次数:{refundRecords.value.length}次 -
- {/* 固定高度 + 内部滚动 */} -
- {pagedRefunds.value.map((r, idx) => { - const statusInfo = REFUND_STATUS_MAP[r.status] || { - label: '-', - tone: 'default' as const, - }; - const realIdx = (refundPage.value - 1) * refundPageSize.value + idx + 1; - return ( -
-
- 第{realIdx}次退款 - -
-
-
-
- 退款金额: - - ¥{r.amount.toFixed(2)} - {r.isPartial && ( - (部分退款) - )} - + + {/* ===== 选手信息 ===== */} +
+
选手信息
+
+
+ +
+ + + {/* ===== 退款记录 ===== */} +
+
+ 退款记录 +
+ {hasRefund.value ? ( + <> +
+ 已退金额:{totalRefunded.value.toFixed(2)}元 + 退款次数:{refundRecords.value.length}次 +
+
+ {pagedRefunds.value.map((r, idx) => { + const realIdx = (refundPage.value - 1) * refundPageSize.value + idx + 1; + const isSuccess = parseFloat(r.refundTime || '') > 0 || !!r.refundTime; + const statusInfo = { + label: isSuccess + ? '退款成功' + : r.isFullRefund === '1' + ? '退款待处理' + : '退款中', + tone: (isSuccess + ? 'success' + : r.isFullRefund === '1' + ? 'warning' + : 'orange') as StatusTagTone, + }; + return ( +
+
+ 第{realIdx}次退款 + +
+
+
+
+ 退款金额: + + ¥{formatMoney(r.refundAmount)} + {r.isFullRefund === '1' && ( + (全部退款) + )} + {r.isFullRefund === '0' && ( + (部分退款) + )} + +
+
申请时间:{r.refundApplyTime}
+
完款时间:{r.refundTime || '-'}
+
+
+
退款方式:{r.refundMethod}
+
第三方退款单号:{r.refundOutTradeNo || '-'}
+
已退金额:¥{formatMoney(r.refundedAmount)}
-
申请时间:{r.applyTime}
-
完款时间:{r.completeTime || '-'}
-
-
-
退款方式:{r.method}
-
第三方退款单号:{r.thirdPartyNo || '-'}
-
- ); - })} -
-
- -
- - ) : ( -
暂无退款记录
- )} + ); + })} + +
+ +
+ + ) : ( +
暂无退款记录
+ )} + - + ) : null} {/* ===== 底部按钮 ===== */}
{hasRefund.value ? ( - ) : ( - )} diff --git a/src/pages/events/orders/index.tsx b/src/pages/events/orders/index.tsx index 12f81be..2e050df 100644 --- a/src/pages/events/orders/index.tsx +++ b/src/pages/events/orders/index.tsx @@ -1,4 +1,4 @@ -import { defineComponent } from 'vue'; +import { defineComponent, onMounted } from 'vue'; import { Button, Input, @@ -10,8 +10,10 @@ import { Tooltip, Pagination, Modal, + message, } from 'ant-design-vue'; import { useOrderModel, ORDER_STATUS_OPTIONS, REFUND_STATUS_OPTIONS } from './model/useOrderModel'; +import { retryRefundOrder } from '@/api/orders'; import { useContainerSize, useState } from '@/hooks'; import OrderDetailModal from './components/OrderDetailModal'; import pageStyles from '@/assets/styles/pageLayout.module.less'; @@ -20,22 +22,29 @@ const { RangePicker } = DatePicker; /** * 触发「重新退款」二次确认对话框 - * 表格中的重新退款按钮和详情弹窗中的重新退款按钮均调用此函数。 */ function promptReRefund(record: any) { Modal.confirm({ title: '确认要重新退款吗?', content: (
-
退款金额:¥{(record.refundAmount || 0).toFixed(2)}
+
退款金额:¥{parseFloat(record.creatorSignupFeeRefund || '0').toFixed(2)}
退款方式:原路退回(微信支付)
), okText: '确认', cancelText: '取消', - onOk: () => { - console.log('重新退款:', record.orderId); - // TODO: 替换为真实 API 调用 + onOk: async () => { + try { + const res = await retryRefundOrder({ payOrderNo: record.orderNo }); + if (res.code === 200) { + message.success('重新退款提交成功'); + } else { + message.error(res.msg || '操作失败'); + } + } catch (e: any) { + console.error('重新退款失败:', e); + } }, }); } @@ -57,7 +66,7 @@ function renderBodyCell({ onReRefund: (record: any) => void; }) { // 赛事名称:最多15字符,超出显示 Tooltip - if (column.dataIndex === 'eventName') { + if (column.dataIndex === 'name') { const maxLen = 15; const raw = text || ''; const display = raw.length > maxLen ? raw.slice(0, maxLen) + '...' : raw; @@ -71,7 +80,7 @@ function renderBodyCell({ } if (column.key === 'action') { - const showReRefund = record.refundStatus === 'refund_failed'; + const showReRefund = record.refundStatus === 3; return (