300 lines
17 KiB
HTML
Executable File
300 lines
17 KiB
HTML
Executable File
<?php include_once("/opt/wevads-arsenal/public/api/wevads-metrics.php"); ?>
|
||
<!DOCTYPE html>
|
||
<html lang="en" data-theme="dark">
|
||
<head>
|
||
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
||
<title>WEVADS — Global Vision</title>
|
||
<link href="https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&family=DM+Sans:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||
<style>
|
||
:root{--bg:#06090f;--s:#0d1117;--s2:#161b22;--b:#21262d;--t:#e6edf3;--d:#7d8590;--cy:#58a6ff;--gn:#3fb950;--am:#d29922;--rd:#f85149;--pu:#bc8cff;--pk:#f778ba;--or:#ff7b72}
|
||
*{box-sizing:border-box;margin:0;padding:0}
|
||
body{font-family:'DM Sans',sans-serif;background:var(--bg);color:var(--t);overflow-x:hidden}
|
||
.top{background:linear-gradient(135deg,#0d1117 0%,#161b22 100%);border-bottom:1px solid var(--b);padding:16px 24px;display:flex;align-items:center;justify-content:space-between}
|
||
.top h1{font-family:'Space Mono',monospace;font-size:18px;color:var(--cy)}
|
||
.top h1 span{color:var(--d);font-weight:400}
|
||
.top-links{display:flex;gap:8px}
|
||
.top-links a{padding:6px 14px;background:var(--s2);border:1px solid var(--b);border-radius:6px;color:var(--d);text-decoration:none;font-size:12px;font-weight:500;transition:.2s}
|
||
.top-links a:hover{color:var(--cy);border-color:var(--cy)}
|
||
.grid{display:grid;grid-template-columns:1fr 1fr 1fr 1fr;gap:12px;padding:16px 24px}
|
||
@media(max-width:1200px){.grid{grid-template-columns:1fr 1fr}}
|
||
.card{background:var(--s);border:1px solid var(--b);border-radius:10px;padding:16px;position:relative;overflow:hidden}
|
||
.card::before{content:'';position:absolute;top:0;left:0;right:0;height:2px}
|
||
.card.cy::before{background:var(--cy)}.card.gn::before{background:var(--gn)}.card.am::before{background:var(--am)}.card.rd::before{background:var(--rd)}.card.pu::before{background:var(--pu)}.card.pk::before{background:var(--pk)}.card.or::before{background:var(--or)}
|
||
.card-title{font-family:'Space Mono',monospace;font-size:11px;text-transform:uppercase;letter-spacing:1.5px;color:var(--d);margin-bottom:12px;display:flex;align-items:center;gap:8px}
|
||
.card-title .ico{font-size:14px}
|
||
.big{font-size:28px;font-weight:700;font-family:'Space Mono',monospace;margin-bottom:4px}
|
||
.big.cy{color:var(--cy)}.big.gn{color:var(--gn)}.big.am{color:var(--am)}.big.rd{color:var(--rd)}.big.pu{color:var(--pu)}
|
||
.sub{font-size:12px;color:var(--d)}
|
||
.row{display:flex;gap:16px;flex-wrap:wrap;margin-top:10px}
|
||
.mini{flex:1;min-width:80px;background:var(--s2);border-radius:6px;padding:8px 10px;text-align:center}
|
||
.mini-val{font-size:16px;font-weight:700;font-family:'Space Mono',monospace}
|
||
.mini-lbl{font-size:10px;color:var(--d);margin-top:2px}
|
||
.isp-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(100px,1fr));gap:6px;margin-top:10px}
|
||
.isp-chip{background:var(--s2);border:1px solid var(--b);border-radius:6px;padding:6px 8px;text-align:center;font-size:11px}
|
||
.isp-chip .name{font-weight:600;color:var(--t);text-transform:uppercase;font-size:10px}
|
||
.isp-chip .cnt{font-family:'Space Mono',monospace;color:var(--cy);font-size:13px;font-weight:700}
|
||
.isp-chip.seed{border-color:#d29922;background:rgba(210,153,34,.08)}
|
||
.isp-chip.seed .cnt{color:var(--am)}
|
||
.flow{grid-column:1/-1;display:flex;align-items:center;justify-content:center;gap:4px;padding:12px;flex-wrap:wrap}
|
||
.flow-step{background:var(--s2);border:1px solid var(--b);border-radius:8px;padding:10px 14px;text-align:center;min-width:100px;transition:.2s}
|
||
.flow-step:hover{border-color:var(--cy);transform:translateY(-2px)}
|
||
.flow-step .f-ico{font-size:20px;margin-bottom:4px}
|
||
.flow-step .f-name{font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.5px}
|
||
.flow-step .f-val{font-family:'Space Mono',monospace;font-size:14px;font-weight:700;color:var(--cy)}
|
||
.flow-arrow{color:var(--d);font-size:18px;font-family:'Space Mono',monospace}
|
||
.bar{height:6px;background:var(--s2);border-radius:3px;margin-top:6px;overflow:hidden}
|
||
.bar-fill{height:100%;border-radius:3px;transition:width .8s ease}
|
||
.bar-fill.cy{background:var(--cy)}.bar-fill.gn{background:var(--gn)}.bar-fill.am{background:var(--am)}.bar-fill.rd{background:var(--rd)}.bar-fill.pu{background:var(--pu)}
|
||
.link-row{display:flex;gap:6px;margin-top:8px;flex-wrap:wrap}
|
||
.link-btn{padding:4px 10px;background:var(--s2);border:1px solid var(--b);border-radius:4px;color:var(--cy);text-decoration:none;font-size:10px;font-weight:600;transition:.2s}
|
||
.link-btn:hover{background:var(--cy);color:var(--bg)}
|
||
.status-dot{width:8px;height:8px;border-radius:50%;display:inline-block}
|
||
.status-dot.on{background:var(--gn);box-shadow:0 0 6px var(--gn)}.status-dot.off{background:var(--rd)}
|
||
.wide{grid-column:span 2}
|
||
.full{grid-column:1/-1}
|
||
#loading{position:fixed;top:0;left:0;right:0;bottom:0;background:var(--bg);display:flex;align-items:center;justify-content:center;z-index:999;font-family:'Space Mono',monospace;color:var(--cy)}
|
||
@keyframes pulse{0%,100%{opacity:.4}50%{opacity:1}}
|
||
#loading span{animation:pulse 1s infinite}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div id="loading"><span>LOADING GLOBAL VISION...</span></div>
|
||
|
||
<div class="top">
|
||
<h1>⚡ WEVADS GLOBAL VISION <span>/ pipeline × crm × data</span></h1>
|
||
<div class="top-links">
|
||
<a href="crm.php">📇 CRM</a>
|
||
<a href="data-manager.html">💾 Data Manager</a>
|
||
<a href="emailing-pipeline.html">🔗 Pipeline</a>
|
||
<a href="brain-central.html">🧠 Brain</a>
|
||
<a href="ceo-dashboard.html">👔 CEO</a>
|
||
<a href="menu.html">☰ Menu</a>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="grid" id="dash"></div>
|
||
|
||
<script>
|
||
const API = '/api/crm-api.php';
|
||
const fmt = n => {
|
||
if(n===null||n===undefined) return '0';
|
||
n = parseInt(n)||0;
|
||
if(n>=1e6) return (n/1e6).toFixed(1)+'M';
|
||
if(n>=1e3) return (n/1e3).toFixed(1)+'K';
|
||
return n.toLocaleString();
|
||
};
|
||
|
||
async function load() {
|
||
try {
|
||
const [vision, pipeline] = await Promise.all([
|
||
fetch(API+'?action=global_vision').then(r=>r.json()),
|
||
fetch(API+'?action=pipeline_status').then(r=>r.json())
|
||
]);
|
||
const v = vision.vision;
|
||
const p = pipeline.pipeline;
|
||
render(v, p);
|
||
} catch(e) {
|
||
document.getElementById('dash').innerHTML = `<div class="card full rd"><div class="card-title">ERROR</div><div class="sub">${e.message}</div></div>`;
|
||
}
|
||
document.getElementById('loading').style.display='none';
|
||
}
|
||
|
||
function render(v, p) {
|
||
const dash = document.getElementById('dash');
|
||
|
||
// E2E FLOW
|
||
const flowSteps = [
|
||
{ico:'🏭',name:'Supply',val:fmt(v.infra.o365_tenants)+' O365'},
|
||
{ico:'🏗️',name:'Infra',val:fmt(v.capacity.warming)+' warm'},
|
||
{ico:'🧠',name:'Brain',val:v.capacity.send_methods+' methods'},
|
||
{ico:'👥',name:'CRM',val:fmt(v.data.crm_leads)+' leads'},
|
||
{ico:'🎯',name:'Offers',val:v.offers.active+' active'},
|
||
{ico:'📤',name:'Send',val:fmt(v.capacity.daily_cap)+'/day'},
|
||
{ico:'📊',name:'Track',val:fmt(v.tracking.clicks)+' clicks'},
|
||
{ico:'💰',name:'Revenue',val:'$'+v.tracking.revenue.toFixed(0)},
|
||
];
|
||
|
||
let flowHTML = '<div class="card full" style="border-color:var(--cy)"><div class="card-title"><span class="ico">🔗</span>E2E PIPELINE FLOW</div><div class="flow">';
|
||
flowSteps.forEach((s,i) => {
|
||
flowHTML += `<div class="flow-step"><div class="f-ico">${s.ico}</div><div class="f-name">${s.name}</div><div class="f-val">${s.val}</div></div>`;
|
||
if(i < flowSteps.length-1) flowHTML += '<span class="flow-arrow">→</span>';
|
||
});
|
||
flowHTML += '</div></div>';
|
||
|
||
// DATA POOLS
|
||
const dataPools = `
|
||
<div class="card wide cy">
|
||
<div class="card-title"><span class="ico">💾</span>DATA POOLS</div>
|
||
<div class="big cy">${fmt(v.data.crm_leads + v.data.send_data + v.data.encrypted)}</div>
|
||
<div class="sub">Total addressable contacts</div>
|
||
<div class="row">
|
||
<div class="mini"><div class="mini-val" style="color:var(--cy)">${fmt(v.data.crm_leads)}</div><div class="mini-lbl">CRM Leads</div></div>
|
||
<div class="mini"><div class="mini-val" style="color:var(--gn)">${fmt(v.data.send_data)}</div><div class="mini-lbl">Send Data</div></div>
|
||
<div class="mini"><div class="mini-val" style="color:var(--pu)">${fmt(v.data.encrypted)}</div><div class="mini-lbl">Encrypted</div></div>
|
||
<div class="mini"><div class="mini-val" style="color:var(--am)">${v.data.adx_bridge}</div><div class="mini-lbl">ADX Bridge</div></div>
|
||
<div class="mini"><div class="mini-val" style="color:var(--pk)">${fmt(v.data.seeds)}</div><div class="mini-lbl">Seeds</div></div>
|
||
<div class="mini"><div class="mini-val" style="color:var(--rd)">${fmt(v.data.suppressed)}</div><div class="mini-lbl">Suppressed</div></div>
|
||
</div>
|
||
<div class="link-row">
|
||
<a href="crm.php" class="link-btn">📇 CRM</a>
|
||
<a href="data-manager.html" class="link-btn">💾 Data Mgr</a>
|
||
<a href="send-data-factory.html" class="link-btn">📦 Send Data</a>
|
||
<a href="seed-cleaner.html" class="link-btn">🧹 Seeds</a>
|
||
<a href="harvest-manager.html" class="link-btn">🌾 Harvest</a>
|
||
</div>
|
||
</div>`;
|
||
|
||
// ISP COVERAGE
|
||
const totalLeads = v.isps.reduce((s,i)=>s+parseInt(i.cnt),0);
|
||
let ispHTML = '<div class="card wide am"><div class="card-title"><span class="ico">📧</span>ISP COVERAGE — ' + v.isps.length + ' ISPs</div>';
|
||
ispHTML += '<div class="isp-grid">';
|
||
v.isps.forEach(isp => {
|
||
const pct = (parseInt(isp.cnt)/totalLeads*100).toFixed(1);
|
||
const cls = parseInt(isp.cnt) <= 5 ? ' seed' : '';
|
||
ispHTML += `<div class="isp-chip${cls}"><div class="name">${isp.isp}</div><div class="cnt">${fmt(isp.cnt)}</div><div style="font-size:9px;color:var(--d)">${pct}%</div></div>`;
|
||
});
|
||
ispHTML += '</div><div class="sub" style="margin-top:8px">🟡 Seeds needed: ' + v.isps.filter(i=>parseInt(i.cnt)<=5).map(i=>i.isp).join(', ') + '</div></div>';
|
||
|
||
// CAPACITY
|
||
const capacity = `
|
||
<div class="card gn">
|
||
<div class="card-title"><span class="ico">⚡</span>SEND CAPACITY</div>
|
||
<div class="big gn">${fmt(v.capacity.daily_cap)}</div>
|
||
<div class="sub">emails/day capacity</div>
|
||
<div class="row">
|
||
<div class="mini"><div class="mini-val">${fmt(v.capacity.accounts)}</div><div class="mini-lbl">Accounts</div></div>
|
||
<div class="mini"><div class="mini-val">${v.capacity.warming}</div><div class="mini-lbl">Warming</div></div>
|
||
<div class="mini"><div class="mini-val">${v.capacity.send_methods}</div><div class="mini-lbl">Methods</div></div>
|
||
</div>
|
||
<div class="link-row">
|
||
<a href="warming-engine.html" class="link-btn">🔥 Warmup</a>
|
||
<a href="send-engines-dashboard.html" class="link-btn">🚀 Engines</a>
|
||
<a href="operations-overview.html" class="link-btn">🖥️ MTA</a>
|
||
</div>
|
||
</div>`;
|
||
|
||
// BRAIN
|
||
const brain = `
|
||
<div class="card pu">
|
||
<div class="card-title"><span class="ico">🧠</span>BRAIN ENGINE</div>
|
||
<div class="big pu">${v.brain.configs}</div>
|
||
<div class="sub">${v.brain.winners} winners / ${v.brain.tests} tests</div>
|
||
<div class="row">
|
||
<div class="mini"><div class="mini-val">${fmt(v.brain.creatives)}</div><div class="mini-lbl">Creatives</div></div>
|
||
<div class="mini"><div class="mini-val">${v.capacity.send_methods}</div><div class="mini-lbl">Methods</div></div>
|
||
</div>
|
||
<div class="link-row">
|
||
<a href="brain-central.html" class="link-btn">🧠 Central</a>
|
||
<a href="brain-combo-discovery.html" class="link-btn">🔬 Combos</a>
|
||
<a href="winning-config.html" class="link-btn">🏆 Winners</a>
|
||
</div>
|
||
</div>`;
|
||
|
||
// OFFERS
|
||
const offers = `
|
||
<div class="card or">
|
||
<div class="card-title"><span class="ico">🎯</span>OFFERS</div>
|
||
<div class="big" style="color:var(--or)">${v.offers.active}</div>
|
||
<div class="sub">${v.offers.total} total / ${v.offers.countries} countries</div>
|
||
<div class="link-row">
|
||
<a href="offer-engine.html" class="link-btn">🎯 Offers</a>
|
||
<a href="affiliate-monitor.html" class="link-btn">📡 CX3</a>
|
||
<a href="ai-copywriter.html" class="link-btn">✍️ Copy</a>
|
||
</div>
|
||
</div>`;
|
||
|
||
// TRACKING
|
||
const sent = v.tracking.sent;
|
||
const openRate = sent > 0 ? ((v.tracking.opens/sent)*100).toFixed(1) : '0';
|
||
const clickRate = sent > 0 ? ((v.tracking.clicks/sent)*100).toFixed(1) : '0';
|
||
const convRate = v.tracking.clicks > 0 ? ((v.tracking.conversions/v.tracking.clicks)*100).toFixed(1) : '0';
|
||
const tracking = `
|
||
<div class="card pk">
|
||
<div class="card-title"><span class="ico">📊</span>TRACKING & FUNNEL</div>
|
||
<div class="row">
|
||
<div class="mini"><div class="mini-val">${fmt(sent)}</div><div class="mini-lbl">Sent</div></div>
|
||
<div class="mini"><div class="mini-val">${fmt(v.tracking.opens)}</div><div class="mini-lbl">Opens ${openRate}%</div></div>
|
||
<div class="mini"><div class="mini-val">${fmt(v.tracking.clicks)}</div><div class="mini-lbl">Clicks ${clickRate}%</div></div>
|
||
<div class="mini"><div class="mini-val">${v.tracking.conversions}</div><div class="mini-lbl">Conv ${convRate}%</div></div>
|
||
<div class="mini"><div class="mini-val">${v.tracking.bounces}</div><div class="mini-lbl">Bounces</div></div>
|
||
</div>
|
||
<div class="bar"><div class="bar-fill pk" style="width:${Math.min(100,sent>0?v.tracking.opens/sent*100:5)}%"></div></div>
|
||
<div class="link-row">
|
||
<a href="tracking-arsenal.html" class="link-btn">📊 Tracking</a>
|
||
<a href="world-map-live.html" class="link-btn">🗺️ Map</a>
|
||
<a href="test-results-live.html" class="link-btn">📈 Live</a>
|
||
</div>
|
||
</div>`;
|
||
|
||
// REVENUE
|
||
const revenue = `
|
||
<div class="card gn">
|
||
<div class="card-title"><span class="ico">💰</span>REVENUE</div>
|
||
<div class="big gn">$${v.tracking.revenue.toFixed(2)}</div>
|
||
<div class="sub">${v.tracking.conversions} conversions</div>
|
||
<div class="link-row">
|
||
<a href="profit-orchestrator.html" class="link-btn">💎 Profit</a>
|
||
<a href="financial-guard.html" class="link-btn">🏦 Finance</a>
|
||
<a href="ceo-dashboard.html" class="link-btn">👔 CEO</a>
|
||
</div>
|
||
</div>`;
|
||
|
||
// INFRASTRUCTURE
|
||
const infra = `
|
||
<div class="card cy">
|
||
<div class="card-title"><span class="ico">🏗️</span>INFRASTRUCTURE</div>
|
||
<div class="row">
|
||
<div class="mini"><div class="mini-val">${v.infra.o365_tenants}</div><div class="mini-lbl">O365</div></div>
|
||
<div class="mini"><div class="mini-val">${v.infra.cf_accounts}</div><div class="mini-lbl">CF Accts</div></div>
|
||
<div class="mini"><div class="mini-val">${v.infra.cf_zones}</div><div class="mini-lbl">CF Zones</div></div>
|
||
<div class="mini"><div class="mini-val">${v.infra.domains}</div><div class="mini-lbl">Domains</div></div>
|
||
<div class="mini"><div class="mini-val">${v.infra.ia_accounts}</div><div class="mini-lbl">IA Accts</div></div>
|
||
<div class="mini"><div class="mini-val">${v.infra.personas}</div><div class="mini-lbl">Personas</div></div>
|
||
</div>
|
||
<div class="link-row">
|
||
<a href="cloudflare-manager.html" class="link-btn">☁️ CF</a>
|
||
<a href="office-admins.html" class="link-btn">📧 O365</a>
|
||
<a href="ia-provider-factory.html" class="link-btn">🤖 IA</a>
|
||
<a href="mail-personas.html" class="link-btn">🎭 Personas</a>
|
||
</div>
|
||
</div>`;
|
||
|
||
// CRM SEGMENTS
|
||
const segs = v.segments || [];
|
||
const hot = segs.find(s=>s.segment==='hot')?.cnt || 0;
|
||
const warm = segs.find(s=>s.segment==='warm')?.cnt || 0;
|
||
const cold = segs.find(s=>s.segment==='cold')?.cnt || 0;
|
||
const segments = `
|
||
<div class="card am">
|
||
<div class="card-title"><span class="ico">📇</span>CRM SEGMENTS</div>
|
||
<div class="row">
|
||
<div class="mini"><div class="mini-val" style="color:var(--rd)">${fmt(hot)}</div><div class="mini-lbl">🔥 Hot</div></div>
|
||
<div class="mini"><div class="mini-val" style="color:var(--am)">${fmt(warm)}</div><div class="mini-lbl">🌡️ Warm</div></div>
|
||
<div class="mini"><div class="mini-val" style="color:var(--d)">${fmt(cold)}</div><div class="mini-lbl">❄️ Cold</div></div>
|
||
</div>
|
||
<div class="bar"><div class="bar-fill rd" style="width:${v.data.crm_leads>0?hot/v.data.crm_leads*100:0}%"></div></div>
|
||
<div class="sub" style="margin-top:4px">Sync tracking → <a href="#" onclick="syncTracking()" style="color:var(--cy)">🔄 Sync Now</a></div>
|
||
<div class="link-row">
|
||
<a href="crm.php" class="link-btn">📇 Full CRM</a>
|
||
<a href="crm.php?filter=hot" class="link-btn">🔥 Hot</a>
|
||
<a href="crm.php?filter=clickers" class="link-btn">🖱️ Clickers</a>
|
||
</div>
|
||
</div>`;
|
||
|
||
dash.innerHTML = flowHTML + dataPools + ispHTML + capacity + brain + offers + tracking + revenue + infra + segments;
|
||
}
|
||
|
||
async function syncTracking() {
|
||
const r = await fetch(API+'?action=sync_tracking');
|
||
const d = await r.json();
|
||
alert(`Synced: ${d.opens_synced} opens, ${d.clicks_synced} clicks, ${d.conversions_synced} conversions`);
|
||
load();
|
||
}
|
||
|
||
load();
|
||
setInterval(load, 60000);
|
||
</script>
|
||
<?php include("/opt/wevads-arsenal/public/universal-drill.html"); ?>
|
||
</body>
|
||
</html>
|