From 9d98ebfc388752cbc2d182743dd9da0c12a4d1ec Mon Sep 17 00:00:00 2001 From: Disciple_C Date: Tue, 4 Aug 2026 10:27:58 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=AE=A2=E5=8D=95=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E8=81=94=E8=B0=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 21 ++++++++++ package.json | 2 + .../orders/components/OrderDetailModal.tsx | 41 +++++++++---------- src/pages/events/orders/index.tsx | 2 + .../events/orders/model/useOrderModel.ts | 33 ++++++++------- 5 files changed, 63 insertions(+), 36 deletions(-) diff --git a/package-lock.json b/package-lock.json index 53c3ffa..796765a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,8 +9,10 @@ "version": "0.0.0", "dependencies": { "@ant-design/icons-vue": "^7.0.1", + "@types/big.js": "^7.0.0", "@yp-component/root": "^0.0.48", "ant-design-vue": "^4.0.0", + "big.js": "^7.0.1", "china-area-data": "^5.0.1", "dayjs": "^1.11.21", "echarts": "^5.6.0", @@ -1050,6 +1052,12 @@ "url": "https://ko-fi.com/dangreen" } }, + "node_modules/@types/big.js": { + "version": "7.0.0", + "resolved": "https://registry.npmmirror.com/@types/big.js/-/big.js-7.0.0.tgz", + "integrity": "sha512-WfAGp7IbJvyB8EmWK4tJD24rJRAL6uVbw3LV/hJntFNam+os9KWKj0PzXo8rRRpjupYK8U0M8FoBB8dBhWF2dg==", + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.9", "dev": true, @@ -1677,6 +1685,19 @@ "node": ">=6.0.0" } }, + "node_modules/big.js": { + "version": "7.0.1", + "resolved": "https://registry.npmmirror.com/big.js/-/big.js-7.0.1.tgz", + "integrity": "sha512-iFgV784tD8kq4ccF1xtNMZnXeZzVuXWWM+ERFzKQjv+A5G9HC8CY3DuV45vgzFFcW+u2tIvmF95+AzWgs6BjCg==", + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/bigjs" + } + }, "node_modules/body-parser": { "version": "2.3.0", "license": "MIT", diff --git a/package.json b/package.json index 5d6104e..0ba973b 100644 --- a/package.json +++ b/package.json @@ -18,8 +18,10 @@ }, "dependencies": { "@ant-design/icons-vue": "^7.0.1", + "@types/big.js": "^7.0.0", "@yp-component/root": "^0.0.48", "ant-design-vue": "^4.0.0", + "big.js": "^7.0.1", "china-area-data": "^5.0.1", "dayjs": "^1.11.21", "echarts": "^5.6.0", diff --git a/src/pages/events/orders/components/OrderDetailModal.tsx b/src/pages/events/orders/components/OrderDetailModal.tsx index 3c1d666..9f8e374 100644 --- a/src/pages/events/orders/components/OrderDetailModal.tsx +++ b/src/pages/events/orders/components/OrderDetailModal.tsx @@ -1,7 +1,7 @@ -import { defineComponent, computed, onMounted } from 'vue'; +import { defineComponent, computed } 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 { useState, useEffect } from '@/hooks'; import { getOrderDetail, getOrderPlayerList, @@ -19,7 +19,6 @@ interface OrderDetailModalProps { onReRefund: () => void; } -// ===== 选手表格列(对齐 TournamentAdminOrderInfoPageVO) ===== const GENDER_MAP: Record = { '1': '男', '2': '女' }; const formatGender = (v: string) => GENDER_MAP[v] ?? v; const formatMoney = (v: string) => { @@ -117,19 +116,18 @@ export default defineComponent({ visible: { type: Boolean, default: false }, orderNo: { type: String, default: '' }, uniqueId: { type: String, default: '' }, - onClose: { type: Function, required: true }, - onReRefund: { type: Function, required: true }, + onClose: { type: Function, default: null }, + onReRefund: { type: Function, default: null }, }, setup(props: OrderDetailModalProps) { - // ===== 数据状态 ===== const [detail, setDetail] = useState(null); const [detailLoading, setDetailLoading] = useState(true); - - // ===== 选手列表分页状态 ===== const [players, setPlayers] = useState([]); const [playersLoading, setPlayersLoading] = useState(true); const [playerPage, setPlayerPage] = useState(1); const [playerTotal, setPlayerTotal] = useState(0); + const [refundPage, setRefundPage] = useState(1); + const [refundPageSize] = useState(2); const playerPageSize = 5; /** 获取选手列表(分页) */ @@ -152,12 +150,18 @@ export default defineComponent({ } }; - // ===== 退款记录分页 ===== - const [refundPage, setRefundPage] = useState(1); - const [refundPageSize] = useState(2); - const refundRecords = computed(() => detail.value?.refundInfoList || []); const hasRefund = computed(() => refundRecords.value.length > 0); + const hasRefundFailed = computed(() => { + const records = refundRecords.value; + if (!records || !records.length) return false; + return records.some((r) => { + if (!r) return false; + const hasRefundAmount = parseFloat(r.refundAmount || '0') > 0; + const hasRefundTime = r.refundTime && r.refundTime !== '-'; + return hasRefundAmount && !hasRefundTime; + }); + }); const pagedRefunds = computed(() => { const start = (refundPage.value - 1) * refundPageSize.value; @@ -170,8 +174,7 @@ export default defineComponent({ return records.reduce((sum, r) => sum + parseFloat(r.refundAmount || '0'), 0); }); - // ===== 初始化:获取详情 + 选手列表第一页 ===== - onMounted(async () => { + useEffect(async () => { const params = { orderNo: props.orderNo, uniqueId: props.uniqueId }; const [detailRes] = await Promise.all([getOrderDetail(params), fetchPlayers(1)]); @@ -180,7 +183,7 @@ export default defineComponent({ setDetail(detailRes.data); } setDetailLoading(false); - }); + }, []); const handlePlayerPageChange = (page: number) => { fetchPlayers(page); @@ -202,7 +205,6 @@ export default defineComponent({ wrapClassName={styles.orderModalWrap} >
- {/* ===== 自定义标题栏 ===== */}
订单信息
) : detail.value ? (
- {/* ===== 订单信息 ===== */}
赛事名称: @@ -252,7 +253,6 @@ export default defineComponent({
- {/* ===== 选手信息 ===== */}
选手信息
- {/* ===== 退款记录 ===== */}
退款记录 @@ -354,10 +353,10 @@ export default defineComponent({
) : null} - {/* ===== 底部按钮 ===== */}
- {hasRefund.value ? ( + {/* 只有存在退款失败记录时才显示重新退款按钮 */} + {hasRefundFailed.value ? ( diff --git a/src/pages/events/orders/index.tsx b/src/pages/events/orders/index.tsx index 5f5de26..30791f0 100644 --- a/src/pages/events/orders/index.tsx +++ b/src/pages/events/orders/index.tsx @@ -80,6 +80,8 @@ function renderBodyCell({ } if (column.key === 'action') { + // 退款状态:1=无退款,2=退款成功,3=退款失败,-1=其他 + // 只有退款失败(3)时显示重新退款按钮 const showReRefund = record.refundStatus === 3; return ( diff --git a/src/pages/events/orders/model/useOrderModel.ts b/src/pages/events/orders/model/useOrderModel.ts index 16da8d8..6b14a91 100644 --- a/src/pages/events/orders/model/useOrderModel.ts +++ b/src/pages/events/orders/model/useOrderModel.ts @@ -1,4 +1,5 @@ import { computed, reactive, toRef, Ref, h } from 'vue'; +import Big from 'big.js'; import { StatusTag, type StatusTagTone } from '@/components'; import { useState, useDebounce } from '@/hooks'; import { useRequest } from '@/hooks/useRequest'; @@ -76,7 +77,6 @@ export function useOrderModel() { return { page: String(page), limit: String(pageSize), ...params } as OrderListQueryParams; }; - // ===== 列表数据请求 ===== const { data, loading, @@ -86,7 +86,6 @@ export function useOrderModel() { { refreshDeps: [], formatResult: (res) => res }, ); - // 提取列表数据 const listData = computed | undefined>(() => { const res = data.value; return res ? (res as any).data : undefined; @@ -94,20 +93,30 @@ export function useOrderModel() { const dataSource = computed(() => listData.value?.list || []); - // 同步分页总条数 useEffect(() => { const total = (data.value as any)?.data?.total; if (total !== undefined) pagination.setTotal(total); }, [data]); - // ===== 金额汇总(TODO: 汇总应来自独立接口) ===== - const [summary] = useState({ - totalOrderAmount: 0, - totalPaidAmount: 0, - totalRefundAmount: 0, + const summary = computed(() => { + const list = listData.value?.list || []; + let totalOrder = new Big(0); + let totalPaid = new Big(0); + let totalRefund = new Big(0); + + for (const item of list) { + totalOrder = totalOrder.plus(new Big(item.creatorSignupFee || 0)); + totalPaid = totalPaid.plus(new Big(item.creatorSignupFeeActual || 0)); + totalRefund = totalRefund.plus(new Big(item.creatorSignupFeeRefund || 0)); + } + + return { + totalOrderAmount: totalOrder.toNumber(), + totalPaidAmount: totalPaid.toNumber(), + totalRefundAmount: totalRefund.toNumber(), + }; }); - // ===== 计算属性 ===== const hasFilter = computed(() => { const f = filterForm; return ( @@ -120,7 +129,6 @@ export function useOrderModel() { ); }); - // ===== 表格列配置 ===== const formatMoney = (text: string) => { const n = parseFloat(text); return isNaN(n) ? '0.00元' : `${n.toFixed(2)}元`; @@ -202,7 +210,6 @@ export function useOrderModel() { }, ]; - // ===== 列表操作 ===== const handleSearch = () => fetchList(); const handleReset = () => { @@ -220,7 +227,6 @@ export function useOrderModel() { }; return { - // 数据 filterForm, loading, dataSource, @@ -228,15 +234,12 @@ export function useOrderModel() { summary, pagination, hasFilter, - // 方法 handleSearch, handleReset, handlePageChange, }; } -// ===== 工具函数 ===== - function hasValue(v: any): boolean { if (v == null) return false; if (Array.isArray(v)) return v.length > 0 && v.some((item) => item != null);