<!DOCTYPE html>
<html lang="vi">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Demo: Modal Chi tiết Liên kết Via-BM</title>
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
theme: {
extend: {
colors: {
'primary': '#6366f1',
'primary-light': '#818cf8',
'dark-card': '#1e293b',
}
}
}
}
</script>
<style>
.custom-scroll::-webkit-scrollbar {
width: 6px;
}
.custom-scroll::-webkit-scrollbar-track {
background: #f1f5f9;
border-radius: 3px;
}
.custom-scroll::-webkit-scrollbar-thumb {
background: #cbd5e1;
border-radius: 3px;
}
</style>
</head>
<body class="bg-gray-100 min-h-screen p-8">
<!-- Header -->
<div class="max-w-6xl mx-auto mb-6">
<h1 class="text-2xl font-bold text-gray-800">Demo: Bảng Ads với Cột Liên kết</h1>
<p class="text-gray-600 mt-1">Click vào badge để xem Modal chi tiết</p>
</div>
<!-- Table -->
<div class="max-w-6xl mx-auto bg-white rounded-lg shadow overflow-hidden">
<table class="w-full">
<thead class="bg-gray-50 border-b">
<tr>
<th class="px-4 py-3 text-left text-sm font-semibold text-gray-700">Ads ID</th>
<th class="px-4 py-3 text-left text-sm font-semibold text-gray-700">Status</th>
<th class="px-4 py-3 text-left text-sm font-semibold text-gray-700">Spend</th>
<th class="px-4 py-3 text-left text-sm font-semibold text-gray-700">Liên kết</th>
<th class="px-4 py-3 text-left text-sm font-semibold text-gray-700">Actions</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200">
<!-- Row 1: Normal case -->
<tr class="hover:bg-gray-50">
<td class="px-4 py-3 text-sm font-mono">ADS-001</td>
<td class="px-4 py-3">
<span class="px-2 py-1 text-xs font-medium bg-green-100 text-green-800 rounded">Active</span>
</td>
<td class="px-4 py-3 text-sm">$500/day</td>
<td class="px-4 py-3">
<button onclick="openModal('normal')" class="inline-flex gap-2 cursor-pointer hover:opacity-80">
<span class="px-2 py-1 text-xs font-medium bg-green-100 text-green-800 rounded-full">👤 3/5</span>
<span class="px-2 py-1 text-xs font-medium bg-green-100 text-green-800 rounded-full">BM 2/3+1G</span>
</button>
</td>
<td class="px-4 py-3">
<button class="text-blue-600 hover:text-blue-800 text-sm">Check</button>
</td>
</tr>
<!-- Row 2: Warning case -->
<tr class="hover:bg-gray-50">
<td class="px-4 py-3 text-sm font-mono">ADS-002</td>
<td class="px-4 py-3">
<span class="px-2 py-1 text-xs font-medium bg-yellow-100 text-yellow-800 rounded">Paused</span>
</td>
<td class="px-4 py-3 text-sm">$0</td>
<td class="px-4 py-3">
<button onclick="openModal('warning')" class="inline-flex gap-2 cursor-pointer hover:opacity-80">
<span class="px-2 py-1 text-xs font-medium bg-yellow-100 text-yellow-800 rounded-full">👤 1/3</span>
<span class="px-2 py-1 text-xs font-medium bg-yellow-100 text-yellow-800 rounded-full">BM 1/2+1G</span>
</button>
</td>
<td class="px-4 py-3">
<button class="text-blue-600 hover:text-blue-800 text-sm">Check</button>
</td>
</tr>
<!-- Row 3: Critical case - 0 Via -->
<tr class="hover:bg-gray-50 bg-red-50">
<td class="px-4 py-3 text-sm font-mono">ADS-003</td>
<td class="px-4 py-3">
<span class="px-2 py-1 text-xs font-medium bg-green-100 text-green-800 rounded">Active</span>
</td>
<td class="px-4 py-3 text-sm">$200/day</td>
<td class="px-4 py-3">
<button onclick="openModal('critical')" class="inline-flex gap-2 cursor-pointer hover:opacity-80">
<span class="px-2 py-1 text-xs font-medium bg-red-100 text-red-800 rounded-full">👤 0/2</span>
<span class="px-2 py-1 text-xs font-medium bg-red-100 text-red-800 rounded-full">BM 0/1+1G</span>
</button>
</td>
<td class="px-4 py-3">
<button class="text-blue-600 hover:text-blue-800 text-sm">Check</button>
</td>
</tr>
<!-- Row 4: BM Gốc DIE -->
<tr class="hover:bg-gray-50 bg-red-100">
<td class="px-4 py-3 text-sm font-mono">ADS-004</td>
<td class="px-4 py-3">
<span class="px-2 py-1 text-xs font-medium bg-gray-100 text-gray-800 rounded">Disabled</span>
</td>
<td class="px-4 py-3 text-sm">$100/day</td>
<td class="px-4 py-3">
<button onclick="openModal('goc-die')" class="inline-flex gap-2 cursor-pointer hover:opacity-80">
<span class="px-2 py-1 text-xs font-medium bg-green-100 text-green-800 rounded-full">👤 2/2</span>
<span class="px-2 py-1 text-xs font-medium bg-red-200 text-red-900 rounded-full font-bold">💀 GỐC DIE</span>
</button>
</td>
<td class="px-4 py-3">
<button class="text-gray-400 cursor-not-allowed text-sm">Check</button>
</td>
</tr>
<!-- Row 5: Chưa sync -->
<tr class="hover:bg-gray-50">
<td class="px-4 py-3 text-sm font-mono">ADS-005</td>
<td class="px-4 py-3">
<span class="px-2 py-1 text-xs font-medium bg-green-100 text-green-800 rounded">Active</span>
</td>
<td class="px-4 py-3 text-sm">$50/day</td>
<td class="px-4 py-3">
<button onclick="openModal('chua-sync')" class="inline-flex gap-2 cursor-pointer hover:opacity-80">
<span class="px-2 py-1 text-xs font-medium bg-yellow-100 text-yellow-800 rounded-full">👤 1/1</span>
<span class="px-2 py-1 text-xs font-medium bg-yellow-100 text-yellow-800 rounded-full">BM 1/1+⚠️0G</span>
</button>
</td>
<td class="px-4 py-3">
<button class="text-blue-600 hover:text-blue-800 text-sm">Check</button>
</td>
</tr>
</tbody>
</table>
</div>
<!-- Legend -->
<div class="max-w-6xl mx-auto mt-4 p-4 bg-white rounded-lg shadow">
<h3 class="text-sm font-semibold text-gray-700 mb-2">Chú thích màu:</h3>
<div class="flex flex-wrap gap-4 text-sm">
<div class="flex items-center gap-2">
<span class="w-4 h-4 bg-green-500 rounded"></span>
<span>2+ live (An toàn)</span>
</div>
<div class="flex items-center gap-2">
<span class="w-4 h-4 bg-yellow-500 rounded"></span>
<span>1 live (Rủi ro)</span>
</div>
<div class="flex items-center gap-2">
<span class="w-4 h-4 bg-red-500 rounded"></span>
<span>0 live (Critical)</span>
</div>
<div class="flex items-center gap-2">
<span class="px-2 py-0.5 text-xs bg-red-200 text-red-900 rounded">💀 GỐC DIE</span>
<span>BM Gốc chết = GAME OVER</span>
</div>
</div>
</div>
<!-- Modal Overlay -->
<div id="modal-overlay" class="fixed inset-0 bg-black/50 hidden items-center justify-center z-50" onclick="closeModal()">
<!-- Modal Content -->
<div id="modal-content" class="bg-gray-50 rounded-2xl shadow-2xl w-full max-w-3xl max-h-[95vh] overflow-hidden" onclick="event.stopPropagation()">
<!-- Modal Header -->
<div class="flex items-center justify-between px-6 py-4 bg-white border-b">
<div class="flex items-center gap-3">
<div class="w-10 h-10 bg-indigo-100 rounded-xl flex items-center justify-center">
<svg class="w-5 h-5 text-indigo-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1"/>
</svg>
</div>
<div>
<h2 class="text-lg font-semibold text-gray-800">Chi tiết Liên kết - <span id="modal-ads-id">Ads 001</span></h2>
<div class="flex items-center gap-1.5 text-sm text-gray-500">
<span class="w-2 h-2 bg-green-500 rounded-full"></span>
<span>Hệ thống hoạt động</span>
</div>
</div>
</div>
<div class="flex items-center gap-2">
<button class="p-2 text-gray-400 hover:text-gray-600 hover:bg-gray-100 rounded-lg transition">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/>
</svg>
</button>
<button onclick="closeModal()" class="p-2 text-gray-400 hover:text-gray-600 hover:bg-gray-100 rounded-lg transition">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
</svg>
</button>
</div>
</div>
<!-- Modal Body -->
<div id="modal-body" class="p-6 overflow-y-auto custom-scroll max-h-[calc(95vh-180px)]">
<!-- Content will be injected here -->
</div>
<!-- Modal Footer -->
<div class="px-6 py-4 bg-white border-t flex items-center justify-between">
<div class="text-sm text-gray-500">
Last updated: <span id="modal-timestamp">Just now</span>
</div>
<div class="flex items-center gap-3">
<button class="px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 flex items-center gap-2">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12"/>
</svg>
Export
</button>
<button class="px-4 py-2 text-sm font-medium text-white bg-indigo-600 rounded-lg hover:bg-indigo-700 flex items-center gap-2">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"/>
</svg>
Edit Structure
</button>
</div>
</div>
</div>
</div>
<script>
const mockData = {
normal: {
adsId: 'Ads 001',
stats: { total: 9, livePercent: 66, risks: 2 },
bmGoc: {
status: 'live',
name: 'BM Root ABC',
id: '123456789',
adsCount: 50,
createdBy: 'Via X',
createdAt: '2024-01-15'
},
bmTrungGian: [
{ name: 'BM Trung gian Alpha', status: 'live', vias: ['A', 'B'], hasToken: true },
{ name: 'BM Proxy Beta', status: 'live', vias: ['C'], hasToken: false },
{ name: 'BM Proxy Gamma', status: 'die', vias: [], diedAt: '2025-12-20' }
],
vias: [
{ name: 'Via A', status: 'live', isWorker: true, tasks: 150, bms: [{ name: 'BM Proxy Alpha', type: 'proxy' }, { name: 'BM Proxy Beta', type: 'proxy' }] },
{ name: 'Via B', status: 'live', isWorker: false, tasks: 0, bms: [{ name: 'BM Root ABC', type: 'goc' }] },
{ name: 'Via C', status: 'live', isWorker: true, tasks: 89, bms: [{ name: 'BM Proxy Alpha', type: 'proxy' }] },
{ name: 'Via D', status: 'die', isWorker: false, tasks: 0, bms: [{ name: 'BM Proxy Gamma', type: 'die' }] },
{ name: 'Via E', status: 'die', isWorker: false, tasks: 0, bms: [{ name: 'BM Root ABC', type: 'goc' }] }
],
risks: [
{ type: 'success', label: 'BM GỐC', text: 'An toàn' },
{ type: 'success', label: 'BM TRUNG GIAN', text: '2 Live (Đủ dự phòng)' },
{ type: 'success', label: 'VIA WORKER', text: '2 Worker active' },
{ type: 'warning', label: 'CẢNH BÁO CẤU TRÚC', text: 'Via B, Via E cầm BM Gốc trực tiếp' }
]
},
warning: {
adsId: 'Ads 002',
stats: { total: 6, livePercent: 33, risks: 3 },
bmGoc: {
status: 'live',
name: 'BM Root XYZ',
id: '987654321',
adsCount: 30,
createdBy: 'Via Main',
createdAt: '2024-03-20'
},
bmTrungGian: [
{ name: 'BM Proxy Delta', status: 'live', vias: ['F'], hasToken: true },
{ name: 'BM Proxy Epsilon', status: 'die', vias: [], diedAt: '2025-11-15' }
],
vias: [
{ name: 'Via F', status: 'live', isWorker: true, tasks: 45, bms: [{ name: 'BM Proxy Delta', type: 'proxy' }] },
{ name: 'Via G', status: 'die', isWorker: false, tasks: 0, bms: [{ name: 'BM Proxy Epsilon', type: 'die' }] },
{ name: 'Via H', status: 'die', isWorker: false, tasks: 0, bms: [{ name: 'BM Root XYZ', type: 'goc' }] }
],
risks: [
{ type: 'success', label: 'BM GỐC', text: 'An toàn' },
{ type: 'warning', label: 'BM TRUNG GIAN', text: 'Chỉ 1 live (ít dự phòng)' },
{ type: 'warning', label: 'VIA WORKER', text: 'Chỉ 1 worker (rủi ro)' },
{ type: 'warning', label: 'ĐỀ XUẤT', text: 'Cần bổ sung Via và BM Trung gian' }
]
},
critical: {
adsId: 'Ads 003',
stats: { total: 4, livePercent: 0, risks: 4 },
bmGoc: {
status: 'live',
name: 'BM Root DEF',
id: '111222333',
adsCount: 25,
createdBy: 'Via Old',
createdAt: '2023-06-10'
},
bmTrungGian: [
{ name: 'BM Proxy Zeta', status: 'die', vias: [], diedAt: '2025-12-01' }
],
vias: [
{ name: 'Via I', status: 'die', isWorker: false, tasks: 0, bms: [{ name: 'BM Proxy Zeta', type: 'die' }] },
{ name: 'Via J', status: 'die', isWorker: false, tasks: 0, bms: [{ name: 'BM Root DEF', type: 'goc' }] }
],
risks: [
{ type: 'success', label: 'BM GỐC', text: 'Còn sống' },
{ type: 'error', label: 'BM TRUNG GIAN', text: '0 live - KHÔNG CÓ ĐƯỜNG CHECK' },
{ type: 'error', label: 'VIA', text: '0 live - KHÔNG THỂ THAO TÁC' },
{ type: 'error', label: 'HÀNH ĐỘNG', text: 'Tạo BM TG mới, share từ gốc NGAY' }
]
},
'goc-die': {
adsId: 'Ads 004',
stats: { total: 4, livePercent: 50, risks: 1 },
bmGoc: {
status: 'die',
name: 'BM Root OLD',
id: '555666777',
diedAt: '2025-12-25'
},
bmTrungGian: [
{ name: 'BM Proxy Eta', status: 'live', vias: ['K', 'L'], hasToken: true }
],
vias: [
{ name: 'Via K', status: 'live', isWorker: true, tasks: 200, bms: [{ name: 'BM Proxy Eta', type: 'proxy' }] },
{ name: 'Via L', status: 'live', isWorker: false, tasks: 0, bms: [{ name: 'BM Proxy Eta', type: 'proxy' }] }
],
risks: [
{ type: 'fatal', label: 'BM GỐC', text: '💀 DIE = GAME OVER' },
{ type: 'error', label: 'ADS', text: 'KHÔNG THỂ sử dụng' },
{ type: 'error', label: 'QUẢNG CÁO', text: 'Không thể chạy được' },
{ type: 'error', label: 'KHÔI PHỤC', text: 'MẤT TRẮNG - Không thể khôi phục' }
]
},
'chua-sync': {
adsId: 'Ads 005',
stats: { total: 3, livePercent: 66, risks: 2 },
bmGoc: {
status: 'unknown',
name: null
},
bmTrungGian: [
{ name: 'BM Proxy Theta', status: 'live', vias: ['M'], hasToken: true }
],
vias: [
{ name: 'Via M', status: 'live', isWorker: true, tasks: 30, bms: [{ name: 'BM Proxy Theta', type: 'proxy' }] }
],
risks: [
{ type: 'warning', label: 'BM GỐC', text: 'CHƯA XÁC ĐỊNH' },
{ type: 'warning', label: 'HÀNH ĐỘNG', text: 'Cần sync Via để lấy thông tin BM Gốc' },
{ type: 'warning', label: 'VIA WORKER', text: 'Chỉ 1 (rủi ro)' }
]
}
};
function openModal(type) {
const data = mockData[type];
const overlay = document.getElementById('modal-overlay');
const body = document.getElementById('modal-body');
document.getElementById('modal-ads-id').textContent = data.adsId;
let html = '';
// Summary Cards
html += `
<div class="grid grid-cols-3 gap-4 mb-6">
<div class="bg-white rounded-xl p-4 border border-gray-200">
<div class="text-xs font-medium text-gray-500 uppercase tracking-wide mb-1">TỔNG TÀI NGUYÊN</div>
<div class="flex items-center justify-between">
<span class="text-3xl font-bold text-gray-800">${String(data.stats.total).padStart(2, '0')}</span>
<div class="w-10 h-10 bg-blue-100 rounded-lg flex items-center justify-center">
<svg class="w-5 h-5 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/>
</svg>
</div>
</div>
</div>
<div class="bg-white rounded-xl p-4 border border-gray-200">
<div class="text-xs font-medium text-gray-500 uppercase tracking-wide mb-1">TỶ LỆ LIVE</div>
<div class="flex items-center justify-between">
<span class="text-3xl font-bold ${data.stats.livePercent >= 50 ? 'text-green-600' : data.stats.livePercent > 0 ? 'text-yellow-600' : 'text-red-600'}">${data.stats.livePercent}%</span>
<div class="w-10 h-10 ${data.stats.livePercent >= 50 ? 'bg-green-100' : data.stats.livePercent > 0 ? 'bg-yellow-100' : 'bg-red-100'} rounded-lg flex items-center justify-center">
<svg class="w-5 h-5 ${data.stats.livePercent >= 50 ? 'text-green-600' : data.stats.livePercent > 0 ? 'text-yellow-600' : 'text-red-600'}" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"/>
</svg>
</div>
</div>
</div>
<div class="bg-white rounded-xl p-4 border border-gray-200">
<div class="text-xs font-medium text-gray-500 uppercase tracking-wide mb-1">RỦI RO PHÁT HIỆN</div>
<div class="flex items-center justify-between">
<span class="text-3xl font-bold ${data.stats.risks > 2 ? 'text-red-600' : data.stats.risks > 0 ? 'text-yellow-600' : 'text-green-600'}">${String(data.stats.risks).padStart(2, '0')}</span>
<div class="w-10 h-10 ${data.stats.risks > 2 ? 'bg-red-100' : data.stats.risks > 0 ? 'bg-yellow-100' : 'bg-green-100'} rounded-lg flex items-center justify-center">
<svg class="w-5 h-5 ${data.stats.risks > 2 ? 'text-red-600' : data.stats.risks > 0 ? 'text-yellow-600' : 'text-green-600'}" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/>
</svg>
</div>
</div>
</div>
</div>`;
// BM Gốc Section
html += '<div class="mb-6">';
html += `
<div class="flex items-center justify-between mb-3">
<div class="flex items-center gap-2">
<div class="w-6 h-6 bg-indigo-100 rounded flex items-center justify-center">
<svg class="w-4 h-4 text-indigo-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4"/>
</svg>
</div>
<span class="text-sm font-semibold text-indigo-700">BM GỐC</span>
<span class="text-xs text-gray-400">(Root Business Manager)</span>
</div>
<span class="px-3 py-1 text-xs font-medium bg-indigo-100 text-indigo-700 rounded-full">Quan trọng</span>
</div>`;
if (data.bmGoc.status === 'die') {
html += `
<div class="bg-red-50 border-2 border-red-200 rounded-xl p-4">
<div class="flex items-center gap-3">
<div class="w-12 h-12 bg-red-200 rounded-xl flex items-center justify-center text-2xl">💀</div>
<div class="flex-1">
<div class="flex items-center gap-2">
<span class="font-semibold text-red-800">${data.bmGoc.name}</span>
<span class="px-2 py-0.5 text-xs font-medium bg-red-600 text-white rounded">Die</span>
</div>
<div class="text-sm text-red-600 mt-1">
<span class="font-medium">GAME OVER</span> - Died: ${data.bmGoc.diedAt}
</div>
</div>
</div>
</div>`;
} else if (data.bmGoc.status === 'unknown') {
html += `
<div class="bg-yellow-50 border-2 border-yellow-200 rounded-xl p-4">
<div class="flex items-center gap-3">
<div class="w-12 h-12 bg-yellow-200 rounded-xl flex items-center justify-center text-xl">⚠️</div>
<div class="flex-1">
<div class="font-semibold text-yellow-800">CHƯA XÁC ĐỊNH</div>
<div class="text-sm text-yellow-600 mt-1">
Ads chưa được đồng bộ đủ để xác định BM gốc
</div>
</div>
</div>
</div>`;
} else {
html += `
<div class="bg-indigo-50 border border-indigo-200 rounded-xl p-4">
<div class="flex items-center gap-3">
<div class="w-12 h-12 bg-indigo-200 rounded-xl flex items-center justify-center text-indigo-700 font-bold text-lg">
${data.bmGoc.name.substring(0, 2).toUpperCase()}
</div>
<div class="flex-1">
<div class="flex items-center gap-2">
<span class="font-semibold text-gray-800">${data.bmGoc.name}</span>
<span class="px-2 py-0.5 text-xs font-medium bg-green-500 text-white rounded flex items-center gap-1">
<span class="w-1.5 h-1.5 bg-white rounded-full"></span> Live
</span>
</div>
<div class="text-sm text-gray-500 mt-1">ID: ${data.bmGoc.id}</div>
</div>
</div>
<div class="flex items-center gap-6 mt-3 pt-3 border-t border-indigo-200 text-sm text-gray-600">
<span>📊 Ads: <strong>${data.bmGoc.adsCount}</strong></span>
<span>👤 Tạo bởi: <strong>${data.bmGoc.createdBy}</strong></span>
<span>📅 ${data.bmGoc.createdAt}</span>
</div>
</div>`;
}
html += '</div>';
// Two columns: BM Trung Gian + Via
const liveBMs = data.bmTrungGian.filter(bm => bm.status === 'live').length;
const totalBMs = data.bmTrungGian.length;
const liveVias = data.vias.filter(v => v.status === 'live').length;
const totalVias = data.vias.length;
html += '<div class="grid grid-cols-2 gap-4 mb-6">';
// BM Trung Gian Column
html += `
<div class="bg-white rounded-xl border border-gray-200 p-4">
<div class="flex items-center justify-between mb-4">
<div class="flex items-center gap-2">
<div class="w-6 h-6 bg-teal-100 rounded flex items-center justify-center">
<svg class="w-4 h-4 text-teal-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 14v6m-3-3h6M6 10h2a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v2a2 2 0 002 2zm10 0h2a2 2 0 002-2V6a2 2 0 00-2-2h-2a2 2 0 00-2 2v2a2 2 0 002 2zM6 20h2a2 2 0 002-2v-2a2 2 0 00-2-2H6a2 2 0 00-2 2v2a2 2 0 002 2z"/>
</svg>
</div>
<span class="text-sm font-semibold text-gray-700">BM TRUNG GIAN</span>
</div>
<span class="px-2 py-1 text-xs font-medium ${liveBMs >= 2 ? 'bg-green-100 text-green-700' : liveBMs === 1 ? 'bg-yellow-100 text-yellow-700' : 'bg-red-100 text-red-700'} rounded">
${liveBMs} Live / ${totalBMs} Total
</span>
</div>
<div class="space-y-2">`;
data.bmTrungGian.forEach(bm => {
if (bm.status === 'live') {
html += `
<div class="flex items-center justify-between p-3 bg-gray-50 rounded-lg">
<div class="flex items-center gap-2">
<div class="w-8 h-8 bg-gray-200 rounded-lg flex items-center justify-center">
<svg class="w-4 h-4 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4"/>
</svg>
</div>
<div>
<div class="text-sm font-medium text-gray-800">${bm.name}</div>
<div class="text-xs text-gray-500">↔ Via: ${bm.vias.join(', ') || '-'}</div>
</div>
</div>
<div class="flex items-center gap-2">
<span class="px-2 py-0.5 text-xs font-medium bg-green-100 text-green-700 rounded">Live</span>
${bm.hasToken ? '<span class="px-2 py-0.5 text-xs font-medium bg-blue-100 text-blue-700 rounded">Có Token</span>' : ''}
</div>
</div>`;
} else {
html += `
<div class="flex items-center justify-between p-3 bg-red-50 rounded-lg opacity-60">
<div class="flex items-center gap-2">
<div class="w-8 h-8 bg-red-200 rounded-lg flex items-center justify-center">
<svg class="w-4 h-4 text-red-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
</svg>
</div>
<div>
<div class="text-sm font-medium text-gray-500">${bm.name}</div>
<div class="text-xs text-red-500">☠ Died: ${bm.diedAt}</div>
</div>
</div>
<span class="px-2 py-0.5 text-xs font-medium bg-red-100 text-red-700 rounded">Die</span>
</div>`;
}
});
html += '</div></div>';
// Via Column
html += `
<div class="bg-white rounded-xl border border-gray-200 p-4">
<div class="flex items-center justify-between mb-4">
<div class="flex items-center gap-2">
<div class="w-6 h-6 bg-orange-100 rounded flex items-center justify-center">
<svg class="w-4 h-4 text-orange-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z"/>
</svg>
</div>
<span class="text-sm font-semibold text-gray-700">VIA</span>
<span class="text-xs text-gray-400">(User Accounts)</span>
</div>
<span class="px-2 py-1 text-xs font-medium ${liveVias >= 2 ? 'bg-green-100 text-green-700' : liveVias === 1 ? 'bg-yellow-100 text-yellow-700' : 'bg-red-100 text-red-700'} rounded">
${liveVias} Live / ${totalVias} Total
</span>
</div>
<div class="space-y-2 max-h-64 overflow-y-auto custom-scroll">`;
data.vias.forEach(via => {
const isLive = via.status === 'live';
html += `
<div class="p-3 ${isLive ? 'bg-gray-50' : 'bg-red-50 opacity-60'} rounded-lg">
<div class="flex items-center justify-between">
<div class="flex items-center gap-2">
<div class="w-8 h-8 ${isLive ? 'bg-green-500' : 'bg-red-400'} rounded-full flex items-center justify-center text-white text-xs font-bold">
${via.name.split(' ')[1] || via.name.charAt(0)}
</div>
<div>
<div class="flex items-center gap-2">
<span class="text-sm font-medium ${isLive ? 'text-gray-800' : 'text-gray-500'}">${via.name}</span>
${via.isWorker ? '<span class="text-xs text-green-600 font-medium">WORKER</span>' : ''}
</div>
${isLive && via.isWorker ? `<div class="text-xs text-gray-400">● Tasks: ${via.tasks}</div>` : ''}
</div>
</div>
<div class="text-right">
<span class="px-2 py-0.5 text-xs font-medium ${isLive ? 'bg-green-100 text-green-700' : 'bg-red-100 text-red-700'} rounded">${isLive ? 'Live' : 'DIE'}</span>
${isLive && via.isWorker ? `<div class="text-xs text-gray-400 mt-1">Tasks: ${via.tasks}</div>` : ''}
</div>
</div>
<div class="flex items-center gap-1 mt-2 ml-10 flex-wrap">
<span class="text-xs text-gray-400">↳ Qua:</span>
${via.bms.map(bm => {
let bgClass = 'bg-gray-100 text-gray-600';
let icon = '';
if (bm.type === 'goc') {
bgClass = 'bg-yellow-100 text-yellow-700 border border-yellow-300';
icon = '⚠ ';
} else if (bm.type === 'die') {
bgClass = 'bg-red-100 text-red-600';
}
return `<span class="px-2 py-0.5 text-xs ${bgClass} rounded">${icon}${bm.name}${bm.type === 'goc' ? ' (GỐC)' : ''}</span>`;
}).join('')}
</div>
</div>`;
});
html += '</div></div></div>';
// Risk Summary Section
html += `
<div class="bg-slate-800 rounded-xl p-5 relative overflow-hidden">
<div class="absolute right-4 top-1/2 -translate-y-1/2 opacity-10">
<svg class="w-32 h-32 text-white" fill="currentColor" viewBox="0 0 24 24">
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/>
</svg>
</div>
<div class="flex items-center gap-2 mb-4">
<div class="w-6 h-6 bg-indigo-500 rounded flex items-center justify-center">
<svg class="w-4 h-4 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"/>
</svg>
</div>
<span class="text-white font-semibold">Phân Tích & Tóm Tắt Rủi Ro</span>
</div>
<div class="grid grid-cols-2 gap-3 relative z-10">`;
data.risks.forEach(risk => {
let iconBg = 'bg-green-500';
let icon = '✓';
if (risk.type === 'warning') {
iconBg = 'bg-yellow-500';
icon = '!';
} else if (risk.type === 'error' || risk.type === 'fatal') {
iconBg = 'bg-red-500';
icon = '✕';
}
html += `
<div class="flex items-start gap-3">
<div class="w-5 h-5 ${iconBg} rounded-full flex items-center justify-center text-white text-xs font-bold flex-shrink-0 mt-0.5">${icon}</div>
<div>
<div class="text-xs text-gray-400 uppercase">${risk.label}</div>
<div class="text-sm ${risk.type === 'fatal' ? 'text-red-400 font-bold' : risk.type === 'error' ? 'text-red-400' : risk.type === 'warning' ? 'text-yellow-400' : 'text-green-400'}">${risk.text}</div>
</div>
</div>`;
});
html += '</div></div>';
body.innerHTML = html;
overlay.classList.remove('hidden');
overlay.classList.add('flex');
}
function closeModal() {
const overlay = document.getElementById('modal-overlay');
overlay.classList.add('hidden');
overlay.classList.remove('flex');
}
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') closeModal();
});
</script>
</body>
</html>
Số dòng: 667