3 Commits

Author SHA1 Message Date
ZhuRui 0b06cdca69 Merge remote-tracking branch 'origin/feature/0804-CZ' into feature/0723/ZR 2026-08-04 10:37:01 +08:00
chenzhen ce80c6a839 feat: 修改函数 2026-08-04 10:33:45 +08:00
chenzhen 9d98ebfc38 feat: 订单管理联调 2026-08-04 10:27:58 +08:00
5 changed files with 63 additions and 36 deletions
+21
View File
@@ -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",
+2
View File
@@ -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",
@@ -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<string, string> = { '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<TournamentAdminOrderInfoVO | null>(null);
const [detailLoading, setDetailLoading] = useState(true);
// ===== 选手列表分页状态 =====
const [players, setPlayers] = useState<TournamentAdminOrderInfoPageVO[]>([]);
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<InnerRefundInfo[]>(() => 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}
>
<div class={styles.orderDetailModalMain}>
{/* ===== 自定义标题栏 ===== */}
<div class={styles.modalHeader}>
<span class={styles.modalTitle}></span>
<button class={styles.closeBtn} onClick={props.onClose} aria-label="关闭">
@@ -216,7 +218,6 @@ export default defineComponent({
</div>
) : detail.value ? (
<div class={styles.modalBody}>
{/* ===== 订单信息 ===== */}
<div class={styles.infoGrid}>
<div class={styles.infoItem}>
<span class={styles.infoLabel}></span>
@@ -252,7 +253,6 @@ export default defineComponent({
</div>
</div>
{/* ===== 选手信息 ===== */}
<div class={styles.section}>
<div class={styles.sectionTitle}></div>
<Table
@@ -276,7 +276,6 @@ export default defineComponent({
</div>
</div>
{/* ===== 退款记录 ===== */}
<div class={styles.section}>
<div class={styles.refundHeader}>
<span class={styles.sectionTitle}>退</span>
@@ -354,10 +353,10 @@ export default defineComponent({
</div>
) : null}
{/* ===== 底部按钮 ===== */}
<div class={styles.modalFooter}>
<Button onClick={props.onClose}></Button>
{hasRefund.value ? (
{/* 只有存在退款失败记录时才显示重新退款按钮 */}
{hasRefundFailed.value ? (
<Button danger onClick={props.onReRefund}>
退
</Button>
+2
View File
@@ -80,6 +80,8 @@ function renderBodyCell({
}
if (column.key === 'action') {
// 退款状态:1=无退款,2=退款成功,3=退款失败,-1=其他
// 只有退款失败(3)时显示重新退款按钮
const showReRefund = record.refundStatus === 3;
return (
<Space>
+18 -15
View File
@@ -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<PageData<TournamentAdminOrderPageVO> | 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);