feat: 订单管理联调
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -80,6 +80,8 @@ function renderBodyCell({
|
||||
}
|
||||
|
||||
if (column.key === 'action') {
|
||||
// 退款状态:1=无退款,2=退款成功,3=退款失败,-1=其他
|
||||
// 只有退款失败(3)时显示重新退款按钮
|
||||
const showReRefund = record.refundStatus === 3;
|
||||
return (
|
||||
<Space>
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user