| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- 'use client';
- import { useState, useEffect } from 'react';
- import { X, User, CreditCard, ShoppingBag, Loader2, CheckCircle } from 'lucide-react';
- import api from '@/lib/api';
- import LocalTime from '@/components/common/LocalTime';
- import { PaymentConfirmation } from '@/types/payment';
- interface ConfirmationDetailModalProps {
- isOpen: boolean;
- onClose: () => void;
- data: PaymentConfirmation | null;
- onApprove: (item: PaymentConfirmation) => void;
- // onReject: (item: PaymentConfirmation) => void; // 移除
- }
- export default function ConfirmationDetailModal({ isOpen, onClose, data, onApprove }: ConfirmationDetailModalProps) {
- const [loading, setLoading] = useState(false);
-
- // 详情数据状态
- const [paymentInfo, setPaymentInfo] = useState<any>(null);
- const [orderInfo, setOrderInfo] = useState<any>(null);
- const [userInfo, setUserInfo] = useState<any>(null);
- useEffect(() => {
- if (isOpen && data) {
- fetchDetails();
- } else {
- // 重置数据
- setPaymentInfo(null);
- setOrderInfo(null);
- setUserInfo(null);
- }
- }, [isOpen, data]);
- const fetchDetails = async () => {
- if (!data) return;
- setLoading(true);
- try {
- // 1. 获取用户信息 (已有 user_id)
- const userRes = await api.get('/api/user/detail', { params: { user_id: data.user_id } });
- setUserInfo(userRes.data.data);
- // 2. 获取支付详情 (已有 payment_id)
- const payRes = await api.get('/api/vas/payment/detail', { params: { payment_id: data.payment_id } });
- const paymentData = payRes.data.data;
- setPaymentInfo(paymentData);
- // 3. 获取订单详情 (通过支付详情里的 order_id)
- if (paymentData && paymentData.order_id) {
- const orderRes = await api.get('/api/vas/order/detail', { params: { order_id: paymentData.order_id } });
- setOrderInfo(orderRes.data.data);
- }
- } catch (error) {
- console.error("Failed to load details", error);
- } finally {
- setLoading(false);
- }
- };
- if (!isOpen || !data) return null;
- return (
- <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm p-4 animate-in fade-in duration-200">
- <div className="bg-white rounded-xl shadow-2xl w-full max-w-4xl max-h-[90vh] flex flex-col overflow-hidden">
-
- {/* Header */}
- <div className="px-6 py-4 border-b flex justify-between items-center bg-slate-50">
- <div>
- <h3 className="font-bold text-gray-900 text-lg">支付确认详情</h3>
- <p className="text-xs text-gray-500 mt-1">Confirmation ID: #{data.id}</p>
- </div>
- <button onClick={onClose} className="p-1 hover:bg-gray-200 rounded-full transition">
- <X size={24} className="text-gray-500" />
- </button>
- </div>
- {/* Content */}
- <div className="flex-1 overflow-y-auto p-6 bg-slate-50/50">
- {loading ? (
- <div className="flex flex-col items-center justify-center py-20 text-slate-400">
- <Loader2 className="w-10 h-10 animate-spin mb-2" />
- <p>正在加载关联数据...</p>
- </div>
- ) : (
- <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
-
- {/* 1. 用户提交的确认信息 */}
- <div className="md:col-span-2 bg-white p-5 rounded-xl shadow-sm border border-blue-100">
- <h4 className="text-sm font-bold text-slate-800 mb-4 flex items-center gap-2">
- <CheckCircle size={16} className="text-blue-600" /> 用户提交的确认信息
- </h4>
- <div className="grid grid-cols-2 sm:grid-cols-4 gap-4 text-sm">
- <div>
- <span className="block text-xs text-slate-400">提交金额</span>
- <span className="font-bold text-slate-900 text-lg">
- {(data.amount / 100).toFixed(2)} {data.currency}
- </span>
- </div>
- <div>
- <span className="block text-xs text-slate-400">随机立减</span>
- <span className="font-medium text-red-500">
- -{(data.random_offset / 100).toFixed(2)}
- </span>
- </div>
- <div>
- <span className="block text-xs text-slate-400">用户点击时间</span>
- <LocalTime date={data.confirmed_at} className="font-medium text-slate-700"/>
- </div>
- <div>
- <span className="block text-xs text-slate-400">当前状态</span>
- <span className={`inline-block px-2 py-0.5 rounded text-xs font-bold ${
- data.status === 'pending' ? 'bg-yellow-100 text-yellow-700' : 'bg-gray-100 text-gray-700'
- }`}>
- {data.status.toUpperCase()}
- </span>
- </div>
- </div>
- </div>
- {/* 2. 支付单详情 (系统记录) */}
- <div className="bg-white p-5 rounded-xl shadow-sm border border-slate-200">
- <h4 className="text-sm font-bold text-slate-800 mb-4 flex items-center gap-2">
- <CreditCard size={16} className="text-slate-500" /> 关联支付单 (Payment)
- </h4>
- {paymentInfo ? (
- <div className="space-y-3 text-sm">
- <div className="flex justify-between border-b border-slate-50 pb-2">
- <span className="text-slate-500">Payment ID</span>
- <span className="font-mono">{paymentInfo.id}</span>
- </div>
- <div className="flex justify-between border-b border-slate-50 pb-2">
- <span className="text-slate-500">渠道 Provider</span>
- <span className="font-medium uppercase">{paymentInfo.provider}</span>
- </div>
- <div className="flex justify-between border-b border-slate-50 pb-2">
- <span className="text-slate-500">应付金额</span>
- <span className="font-bold">
- {(paymentInfo.amount / 100).toFixed(2)} {paymentInfo.currency}
- </span>
- </div>
- <div className="flex justify-between">
- <span className="text-slate-500">外部流水号</span>
- <span className="font-mono text-xs max-w-[150px] truncate" title={paymentInfo.external_trade_no}>
- {paymentInfo.external_trade_no || '-'}
- </span>
- </div>
- </div>
- ) : (
- <p className="text-slate-400 text-xs">未找到支付记录</p>
- )}
- </div>
- {/* 3. 订单详情 */}
- <div className="bg-white p-5 rounded-xl shadow-sm border border-slate-200">
- <h4 className="text-sm font-bold text-slate-800 mb-4 flex items-center gap-2">
- <ShoppingBag size={16} className="text-slate-500" /> 关联订单 (Order)
- </h4>
- {orderInfo ? (
- <div className="space-y-3 text-sm">
- <div className="flex justify-between border-b border-slate-50 pb-2">
- <span className="text-slate-500">Order ID</span>
- <span className="font-mono">{orderInfo.id}</span>
- </div>
- <div className="flex justify-between border-b border-slate-50 pb-2">
- <span className="text-slate-500">商品名称</span>
- <span className="font-medium text-right max-w-[180px] truncate" title={orderInfo.product_title}>
- {orderInfo.product_title}
- </span>
- </div>
- <div className="flex justify-between">
- <span className="text-slate-500">申请人</span>
- <span className="font-medium">
- {orderInfo.user_inputs?.first_name} {orderInfo.user_inputs?.last_name}
- </span>
- </div>
- </div>
- ) : (
- <p className="text-slate-400 text-xs">未找到订单记录</p>
- )}
- </div>
- {/* 4. 用户信息 */}
- <div className="md:col-span-2 bg-white p-5 rounded-xl shadow-sm border border-slate-200">
- <h4 className="text-sm font-bold text-slate-800 mb-4 flex items-center gap-2">
- <User size={16} className="text-slate-500" /> 下单用户 (User)
- </h4>
- {userInfo ? (
- <div className="flex items-center gap-6 text-sm">
- <div className="w-12 h-12 bg-slate-100 rounded-full flex items-center justify-center overflow-hidden">
- {userInfo.avatar_url ? (
- <img src={userInfo.avatar_url} className="w-full h-full object-cover" />
- ) : (
- <User className="text-slate-400" />
- )}
- </div>
- <div className="grid grid-cols-1 sm:grid-cols-3 gap-x-12 gap-y-2 flex-1">
- <div>
- <span className="block text-xs text-slate-400">昵称</span>
- <span className="font-medium">{userInfo.nickname || '-'}</span>
- </div>
- <div>
- <span className="block text-xs text-slate-400">邮箱</span>
- <span className="font-medium">{userInfo.email}</span>
- </div>
- <div>
- <span className="block text-xs text-slate-400">手机号</span>
- <span className="font-medium">{userInfo.phone || '-'}</span>
- </div>
- </div>
- </div>
- ) : (
- <p className="text-slate-400 text-xs">未找到用户信息</p>
- )}
- </div>
- </div>
- )}
- </div>
- {/* Footer Actions */}
- <div className="p-4 bg-white border-t flex justify-end gap-3">
- <button onClick={onClose} className="px-4 py-2 border border-slate-300 rounded-lg text-slate-700 hover:bg-slate-50 text-sm font-medium">关闭</button>
-
- {data.status === 'pending' && (
- // 移除了驳回按钮
- <button
- onClick={() => { onApprove(data); onClose(); }}
- className="px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 text-sm font-bold flex items-center gap-2 shadow-sm"
- >
- <CheckCircle size={16} /> 确认已收款
- </button>
- )}
- </div>
- </div>
- </div>
- );
- }
|