demo nạp tiền thủ công xác nhận giao dịch.html

18.92 KB • 24/12/2025 10:27:55 • HTML

Tải về
demo nạp tiền thủ công xác nhận giao dịch.html
Html
<!DOCTYPE html>
<html lang="vi">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Quy Trình Admin Nạp Tiền Full</title>
    <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
    <style>
        :root {
            --primary: #5c67f2;
            --primary-hover: #4851c2;
            --success: #10b981;
            --error: #ef4444;
            --warning: #f59e0b;
            --text-main: #1f2937;
            --text-sub: #6b7280;
            --border: #e5e7eb;
            --bg-modal: #ffffff;
        }

        body {
            font-family: 'Segoe UI', sans-serif;
            background-color: #aaadc4;
            height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            margin: 0;
        }

        /* MODAL CHÍNH */
        .modal {
            background: var(--bg-modal);
            width: 700px;
            max-width: 95%;
            border-radius: 16px;
            box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
            display: flex;
            flex-direction: column;
            overflow: hidden;
            transition: height 0.3s ease;
        }

        /* HEADER */
        .modal-header {
            padding: 20px 30px;
            border-bottom: 1px solid var(--border);
            display: flex;
            justify-content: space-between;
            align-items: center;
            background: #fff;
        }
        .step-info { display: flex; align-items: center; gap: 12px; }
        .step-badge {
            background: #e0e7ff; color: var(--primary);
            padding: 4px 12px; border-radius: 99px; font-size: 12px; font-weight: 700;
        }
        .modal-title { font-size: 18px; font-weight: 600; color: var(--text-main); }

        /* BODY CONTENT */
        .modal-body {
            padding: 30px;
            min-height: 350px; /* Giữ chiều cao ổn định */
            position: relative;
        }
        
        .step-content { display: none; animation: fadeIn 0.4s ease; }
        .step-content.active { display: block; }

        @keyframes fadeIn { from { opacity: 0; transform: translateY(5px); } to { opacity: 1; transform: translateY(0); } }

        /* FORM ELEMENTS */
        label { display: block; margin-bottom: 8px; font-weight: 500; font-size: 14px; color: var(--text-main); }
        select, input {
            width: 100%; padding: 12px; border: 1px solid var(--border);
            border-radius: 8px; font-size: 14px; box-sizing: border-box; outline: none;
            transition: border-color 0.2s;
        }
        select:focus, input:focus { border-color: var(--primary); box-shadow: 0 0 0 3px rgba(92, 103, 242, 0.15); }

        /* STEP 1: WALLET CARDS */
        .wallet-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 15px; margin-bottom: 20px; }
        .card-select {
            border: 1px solid var(--border); padding: 15px; border-radius: 10px;
            cursor: pointer; display: flex; align-items: center; gap: 12px;
            transition: all 0.2s;
        }
        .card-select:hover { border-color: var(--primary); background: #f9fafb; }
        .card-select.selected { border-color: var(--primary); background: #eff6ff; box-shadow: 0 4px 6px -1px rgba(92, 103, 242, 0.1); }
        .icon-box {
            width: 40px; height: 40px; border-radius: 50%; display: flex;
            align-items: center; justify-content: center; color: white; font-size: 18px;
        }

        /* STEP 3: RESULT BOXES */
        .result-box {
            margin-top: 20px; padding: 15px; border-radius: 8px;
            display: none; border-left: 4px solid transparent;
        }
        .res-success { background: #ecfdf5; border-color: var(--success); }
        .res-fail { background: #fef2f2; border-color: var(--error); }
        .res-used { background: #fffbeb; border-color: var(--warning); }
        
        .res-title { font-weight: bold; font-size: 14px; margin-bottom: 5px; display: flex; align-items: center; gap: 8px; }
        .res-desc { font-size: 13px; color: var(--text-sub); margin: 0; line-height: 1.5; }

        /* FOOTER */
        .modal-footer {
            padding: 20px 30px; border-top: 1px solid var(--border);
            display: flex; justify-content: flex-end; gap: 12px;
            background: #fff;
        }
        .btn { padding: 10px 24px; border-radius: 8px; border: none; font-weight: 600; cursor: pointer; transition: 0.2s; font-size: 14px; }
        .btn-back { background: white; border: 1px solid var(--border); color: var(--text-sub); }
        .btn-back:hover { background: #f3f4f6; }
        .btn-primary { background: var(--primary); color: white; }
        .btn-primary:hover { background: var(--primary-hover); }
        .btn:disabled { opacity: 0.5; cursor: not-allowed; }

        /* LOADING */
        .loading-overlay {
            display: none; text-align: center; padding: 20px;
        }
        
        /* DEV TOOLS (Test Button) */
        .dev-tools {
            margin-top: 25px; padding: 10px; background: #111827; border-radius: 8px;
        }
        .dev-header { font-size: 11px; text-transform: uppercase; color: #9ca3af; margin-bottom: 8px; letter-spacing: 1px; }
        .btn-test { font-size: 11px; padding: 5px 10px; border-radius: 4px; border: none; cursor: pointer; color: white; margin-right: 5px; font-weight: bold;}
    </style>
</head>
<body>

<div class="modal">
    <div class="modal-header">
        <div class="step-info">
            <span class="step-badge" id="step-badge">Bước 1/3</span>
            <span class="modal-title" id="step-title">Thông tin nạp</span>
        </div>
        <i class="fas fa-times" style="color: #9ca3af; cursor: pointer;"></i>
    </div>

    <div class="modal-body">
        
        <div id="step-1" class="step-content active">
            <div style="margin-bottom: 20px;">
                <label>Doanh nghiệp</label>
                <select id="enterprise" onchange="validateStep1()">
                    <option value="">-- Chọn doanh nghiệp --</option>
                    <option value="1">Công ty Công Nghệ ABC</option>
                    <option value="2">Global Dropshipping LLC</option>
                </select>
            </div>

            <label>Chọn Ví nhận tiền</label>
            <div class="wallet-grid">
                <div class="card-select selected" onclick="selectWallet(this, 'USD')" id="wallet-usd">
                    <div class="icon-box" style="background: #10b981;"><i class="fas fa-dollar-sign"></i></div>
                    <div>
                        <div style="font-weight: 600;">Ví USD</div>
                        <div style="font-size: 12px; color: var(--text-sub);">Balance: $1,200</div>
                    </div>
                </div>
                <div class="card-select" onclick="selectWallet(this, 'VND')" id="wallet-vnd">
                    <div class="icon-box" style="background: #3b82f6;"><i class="fas fa-university"></i></div>
                    <div>
                        <div style="font-weight: 600;">Ví VND</div>
                        <div style="font-size: 12px; color: var(--text-sub);">Balance: 0 đ</div>
                    </div>
                </div>
            </div>

            <label>Số tiền muốn nạp</label>
            <input type="number" id="amount" placeholder="Nhập số tiền..." oninput="validateStep1()">
        </div>

        <div id="step-2" class="step-content">
            <p style="color: var(--text-sub); margin-bottom: 15px;">Bạn đang nạp <b id="display-amount">...</b> vào ví <b id="display-wallet">...</b></p>
            <div class="wallet-grid">
                <div class="card-select" onclick="selectMethod(this, 'usdt')">
                    <div class="icon-box" style="background: #2563eb;"><i class="fab fa-bitcoin"></i></div>
                    <div>
                        <div style="font-weight: 600;">USDT (Tron)</div>
                        <div style="font-size: 12px; color: var(--text-sub);">Tự động check Blockchain</div>
                    </div>
                </div>
                <div class="card-select" onclick="selectMethod(this, 'pingpong')">
                    <div class="icon-box" style="background: #db2777;"><i class="fas fa-envelope-open-text"></i></div>
                    <div>
                        <div style="font-weight: 600;">PingPong</div>
                        <div style="font-size: 12px; color: var(--text-sub);">Tự động quét Email</div>
                    </div>
                </div>
            </div>
        </div>

        <div id="step-3" class="step-content">
            <div style="background: #f8fafc; padding: 15px; border-radius: 8px; border: 1px dashed var(--border); margin-bottom: 20px;">
                <label id="lbl-input-code">Mã giao dịch (TxID/Hash)</label>
                <div style="display: flex; gap: 8px;">
                    <input type="text" id="tx-input" placeholder="Nhập mã..." oninput="resetCheckState()">
                    <button class="btn-primary" style="padding: 0 20px; border-radius: 8px; border:none; cursor: pointer;" onclick="checkTransaction()">
                        <i class="fas fa-search"></i> Check
                    </button>
                </div>
            </div>

            <div id="loading" class="loading-overlay">
                <i class="fas fa-circle-notch fa-spin fa-2x" style="color: var(--primary);"></i>
                <div style="margin-top: 10px; font-size: 13px; color: var(--text-sub);">Đang kết nối API để kiểm tra...</div>
            </div>

            <div id="res-success" class="result-box res-success">
                <div class="res-title" style="color: #047857;"><i class="fas fa-check-circle"></i> Hợp lệ: Sẵn sàng nạp</div>
                <div class="res-desc">
                    Mã giao dịch chính xác. Số tiền <b>$1,000</b>. Chưa từng sử dụng.<br>
                    Bạn có thể xác nhận nạp ngay bây giờ.
                </div>
            </div>

            <div id="res-fail" class="result-box res-fail">
                <div class="res-title" style="color: #b91c1c;"><i class="fas fa-times-circle"></i> Không tìm thấy giao dịch</div>
                <div class="res-desc">
                    Hệ thống không tìm thấy mã này trên Blockchain/Email. Vui lòng kiểm tra lại ký tự hoặc thử lại sau vài phút.
                </div>
            </div>

            <div id="res-used" class="result-box res-used">
                <div class="res-title" style="color: #b45309;"><i class="fas fa-exclamation-triangle"></i> Cảnh báo: Mã đã sử dụng</div>
                <div class="res-desc">
                    Mã này đã được nạp thành công vào lúc <b>14:30 12/10/2025</b> bởi <b>Admin_Huy</b>. Không thể nạp lại.
                </div>
            </div>

            <div class="dev-tools">
                <div class="dev-header">Test Nhanh (Click để điền code mẫu)</div>
                <button class="btn-test" style="background: var(--success);" onclick="autoFill('VALID_CODE_123')">1. Case OK</button>
                <button class="btn-test" style="background: var(--error);" onclick="autoFill('FAIL_CODE_XYZ')">2. Case Lỗi</button>
                <button class="btn-test" style="background: var(--warning);" onclick="autoFill('USED_CODE_999')">3. Case Trùng</button>
            </div>
        </div>

        <div id="step-4" class="step-content" style="text-align: center; padding-top: 40px;">
            <div style="width: 80px; height: 80px; background: #d1fae5; color: #10b981; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 40px; margin: 0 auto 20px auto;">
                <i class="fas fa-check"></i>
            </div>
            <h2 style="color: var(--text-main); margin: 0;">Nạp tiền thành công!</h2>
            <p style="color: var(--text-sub);">Số dư ví đã được cập nhật.</p>
        </div>

    </div>

    <div class="modal-footer" id="modal-footer">
        <button class="btn btn-back" id="btn-back" onclick="prevStep()" disabled>Quay lại</button>
        <button class="btn btn-primary" id="btn-next" onclick="nextStep()" disabled>Tiếp theo</button>
    </div>
</div>
<script>
    // STATE
    let currentStep = 1;
    let formData = {
        enterprise: '',
        wallet: 'USD',
        amount: '',
        method: '',
        txCode: ''
    };

    // MOCK DATA (Giả lập Database)
    const MOCK_DB = {
        'USED_CODE_999': { status: 'USED' },
        'VALID_CODE_123': { status: 'NEW', amount: 1000 },
        'FAIL_CODE_XYZ': { status: 'NOT_FOUND' }
    };

    // --- LOGIC BƯỚC 1 ---
    function selectWallet(el, type) {
        document.querySelectorAll('#step-1 .card-select').forEach(c => c.classList.remove('selected'));
        el.classList.add('selected');
        formData.wallet = type;
        
        // Cập nhật hiển thị ngay lập tức
        validateStep1();
    }

    function validateStep1() {
        formData.enterprise = document.getElementById('enterprise').value;
        formData.amount = document.getElementById('amount').value;
        
        // CẬP NHẬT MỚI: Không disable nút nữa, chỉ kiểm tra ngầm
        // Logic cũ gây lỗi đã được loại bỏ ở đây
    }

    // --- LOGIC BƯỚC 2 ---
    function selectMethod(el, method) {
        document.querySelectorAll('#step-2 .card-select').forEach(c => c.classList.remove('selected'));
        el.classList.add('selected');
        formData.method = method;
    }

    // --- LOGIC BƯỚC 3 (CHECK CORE) ---
    function resetCheckState() {
        document.querySelectorAll('.result-box').forEach(b => b.style.display = 'none');
        document.getElementById('btn-next').disabled = true;
        document.getElementById('btn-next').innerText = "Tiếp theo";
    }

    function autoFill(code) {
        document.getElementById('tx-input').value = code;
        resetCheckState();
        checkTransaction();
    }

    async function checkTransaction() {
        const code = document.getElementById('tx-input').value.trim();
        if(!code) return;

        resetCheckState();
        document.getElementById('loading').style.display = 'block';

        await new Promise(r => setTimeout(r, 800)); // Giảm thời gian chờ xuống 0.8s cho nhanh
        document.getElementById('loading').style.display = 'none';

        if (code.includes('FAIL') || (!MOCK_DB[code] && !code.includes('VALID') && !code.includes('USED'))) {
            document.getElementById('res-fail').style.display = 'block';
            return;
        }

        if (code.includes('USED')) {
            document.getElementById('res-used').style.display = 'block';
            return;
        }

        document.getElementById('res-success').style.display = 'block';
        
        const btnNext = document.getElementById('btn-next');
        btnNext.disabled = false;
        btnNext.innerHTML = '<i class="fas fa-check"></i> Xác nhận & Nạp';
        btnNext.setAttribute('onclick', 'finishProcess()');
    }

    // --- NAVIGATION (SỬA LỖI CHÍNH Ở ĐÂY) ---
    function nextStep() {
        // KIỂM TRA DỮ LIỆU TRƯỚC KHI NEXT
        if (currentStep === 1) {
            const ent = document.getElementById('enterprise').value;
            const amt = document.getElementById('amount').value;
            
            // Nếu thiếu dữ liệu -> Báo lỗi ngay lập tức thay vì im lặng
            if (ent === "" || amt <= 0 || amt === "") {
                alert("Vui lòng chọn Doanh nghiệp và nhập Số tiền hợp lệ!");
                return; // Dừng lại, không cho qua
            }
            
            // Gán dữ liệu hiển thị
            document.getElementById('display-amount').innerText = formData.wallet === 'USD' ? `$${amt}` : `${amt} VND`;
            document.getElementById('display-wallet').innerText = formData.wallet;
        }

        if (currentStep === 2) {
            if (!formData.method) {
                alert("Vui lòng chọn Phương thức thanh toán (USDT hoặc PingPong)!");
                return;
            }
        }

        // CHUYỂN BƯỚC
        document.getElementById(`step-${currentStep}`).classList.remove('active');
        currentStep++;
        document.getElementById(`step-${currentStep}`).classList.add('active');
        
        // Update UI Header/Footer
        document.getElementById('step-badge').innerText = `Bước ${currentStep}/3`;
        document.getElementById('btn-back').disabled = false;
        
        // Xử lý nút Next ở các bước
        const btnNext = document.getElementById('btn-next');
        
        if(currentStep === 2) {
             document.getElementById('step-title').innerText = "Phương thức";
             // Ở bước 2, ta vẫn cho bấm next để nó check xem đã chọn chưa (như logic if ở trên)
        }
        
        if(currentStep === 3) {
             document.getElementById('step-title').innerText = "Xác thực Giao dịch";
             const methodLabel = formData.method === 'usdt' ? 'Mạng Tron (Hash)' : 'Mã PingPong (TxID)';
             document.getElementById('lbl-input-code').innerText = `Nhập ${methodLabel}`;
             
             // Riêng bước 3 thì PHẢI disable nút Next chờ check xong
             btnNext.disabled = true; 
        }
    }

    function prevStep() {
        if(currentStep === 1) return;
        
        document.getElementById(`step-${currentStep}`).classList.remove('active');
        currentStep--;
        document.getElementById(`step-${currentStep}`).classList.add('active');

        document.getElementById('step-badge').innerText = `Bước ${currentStep}/3`;
        
        const btnNext = document.getElementById('btn-next');
        btnNext.disabled = false; // Luôn mở khóa khi quay lại
        btnNext.innerText = "Tiếp theo";
        btnNext.setAttribute('onclick', 'nextStep()');

        if(currentStep === 1) {
            document.getElementById('step-title').innerText = "Thông tin nạp";
            document.getElementById('btn-back').disabled = true;
        }
        if(currentStep === 2) {
            document.getElementById('step-title').innerText = "Phương thức";
            resetCheckState();
        }
    }

    function finishProcess() {
        document.getElementById('step-3').classList.remove('active');
        document.getElementById('step-4').classList.add('active');
        document.getElementById('modal-footer').style.display = 'none';
        document.getElementById('step-badge').innerText = "Hoàn tất";
        document.getElementById('step-title').innerText = "Kết quả";
    }

    // Kích hoạt ngay khi load trang để nút bấm được luôn (Bỏ trạng thái disabled mặc định của HTML cũ)
    window.onload = function() {
        document.getElementById('btn-next').disabled = false;
    }
</script>

</body>
</html>

Số dòng: 434