<?php
session_start();
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Pragma: no-cache");
$expire = 1800;
if (empty($_SESSION['user_id']) || (time() - $_SESSION['login_time'] > $expire)) {
    session_destroy();
    header("Location: login.php");
    exit;
}
$userName = $_SESSION['user_name'] ?? '';
$today = date("Y-m-d");
$grafanaUrl = "http://10.150.117.190:3000";
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>告警时序监控面板</title>
<link rel="stylesheet" href="/static/css/font-awesome.min.css">
<script src="/static/js/jquery.min.js"></script>
<script src="/static/js/chart.js"></script>
<style>
*{box-sizing:border-box;margin:0;padding:0}
body{background:#F5F7FA;font-family:"Microsoft YaHei",system-ui,sans-serif;color:#1D2129;font-size:14px;}
.container{max-width:1400px;margin:0 auto;padding:20px;}
.header-bar{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px;}
.nav-group{display:flex;gap:12px;align-items:center;}
.back-link{color:#165DFF;text-decoration:none;}
.user-info{display:flex;gap:12px;align-items:center;}
.card{background:#FFFFFF;border-radius:8px;padding:20px;box-shadow:0 1px 2px rgba(0,0,0,0.06);margin-bottom:16px;}
.card-title{font-size:15px;font-weight:500;color:#1D2129;margin-bottom:14px;}
.filter-row{display:flex;flex-wrap:wrap;gap:16px;align-items:flex-end;margin-bottom:16px;}
.filter-full{width:100%;}
.filter-item{display:flex;flex-direction:column;gap:6px;min-width:160px;}
label{font-size:13px;color:#4E5969;}
input[type="date"],input[type="text"]{height:36px;padding:0 12px;border:1px solid #DCDFE6;border-radius:6px;font-size:14px;color:#1D2129;}
.check-group{display:flex;gap:12px;flex-wrap:wrap;}
.btn{height:36px;padding:0 16px;border:none;border-radius:6px;cursor:pointer;font-size:14px;display:flex;align-items:center;gap:6px;transition:0.15s;}
.btn-primary{background:#165DFF;color:#fff;}
.btn-primary:hover{background:#0E4BDB;}
.btn-warning{background:#FF7D00;color:#fff;}
.btn-outline{background:#fff;color:#4E5969;border:1px solid #DCDFE6;}
.btn-outline:hover{border-color:#165DFF;color:#165DFF;}
.btn-sm{height:28px;padding:0 8px;font-size:13px;}
.stat-row{display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-bottom:16px;}
.stat-card{padding:16px;border-radius:8px;text-align:center;}
.stat-1{background:#E8F3FF;}
.stat-2{background:#FFECE8;}
.stat-3{background:#E6FFEA;}
.stat-4{background:#FFF7E6;}
.stat-label{font-size:13px;color:#4E5969;}
.stat-num{font-size:26px;font-weight:600;margin:8px 0;}
.chart-row{display:grid;grid-template-columns:2fr 1fr;gap:16px;margin-bottom:16px;}
.chart-box{width:100%;height:260px;position:relative;overflow:hidden;}
canvas{width:100% !important;height:100% !important;}
.table-wrap{overflow-x:auto;}
table{width:100%;border-collapse:collapse;font-size:14px;}
th{background:#F5F7FA;padding:12px 10px;text-align:left;border-bottom:1px solid #E5E6EB;color:#4E5969;font-weight:500;white-space:nowrap;}
td{padding:12px 10px;border-bottom:1px solid #F2F3F5;color:#1D2129;}
.row-firing{background:#FFF7F7;}
.row-resolved{background:#F7FFF9;}
.storm{color:#F53F3F;font-weight:500;}
.pagination{display:flex;justify-content:space-between;align-items:center;margin-top:16px;flex-wrap:wrap;gap:12px;}
.pag-btn{height:32px;padding:0 12px;border:1px solid #DCDFE6;background:#fff;border-radius:6px;cursor:pointer;font-size:14px;}
.empty-box{padding:60px;text-align:center;color:#86909C;}
.tip-text{font-size:13px;color:#86909C;margin-left:8px;}
.shortcut-tip{text-align:center;color:#86909C;font-size:13px;margin-top:12px;}
</style>
</head>
<body>
<div class="container">
    <div class="header-bar">
        <div class="nav-group">
            <a href="dashboard.php" class="back-link"><i class="fa fa-arrow-left"></i> 返回监控大盘</a>
            <a href="alert_subscribe.php" class="btn btn-outline"><i class="fa fa-bell"></i> 告警订阅管理</a>
        </div>
        <div class="user-info"><i class="fa fa-user"></i> <?php echo $userName; ?></div>
    </div>

    <!-- 筛选区域 -->
    <div class="card">
        <div class="filter-row filter-full">
            <input type="text" id="globalSearch" placeholder="全局检索(告警/实例/级别)" style="width:100%;">
        </div>
        <div class="filter-row">
            <div class="filter-item">
                <label>起始日期</label>
                <input type="date" id="startDate" value="<?php echo $today; ?>">
            </div>
            <div class="filter-item">
                <label>结束日期</label>
                <input type="date" id="endDate" value="<?php echo $today; ?>">
            </div>
            <div class="filter-item">
                <label>实例模糊匹配</label>
                <input type="text" id="filterInstance" placeholder="10.150.10.82">
            </div>
            <div class="filter-item">
                <label>告警级别</label>
                <div class="check-group">
                    <label><input type="checkbox" name="sev" value="critical"> Critical</label>
                    <label><input type="checkbox" name="sev" value="warning"> Warning</label>
                    <label><input type="checkbox" name="sev" value="info"> Info</label>
                </div>
            </div>
            <div class="filter-item">
                <label>告警状态</label>
                <div class="check-group">
                    <label><input type="checkbox" name="sta" value="firing"> Firing</label>
                    <label><input type="checkbox" name="sta" value="resolved"> Resolved</label>
                </div>
            </div>
        </div>
        <div class="filter-row">
            <button class="btn btn-primary" id="btnSearch"><i class="fa fa-search"></i> 查询</button>
            <button class="btn btn-outline" id="btnReset"><i class="fa fa-refresh"></i> 重置筛选</button>
            <button class="btn btn-warning" id="btnToggleMode"><i class="fa fa-list"></i> 切换详细模式</button>
            <span class="tip-text" id="modeTip">当前：去重汇总模式</span>
            <button class="btn btn-outline" id="btnExport"><i class="fa fa-file-excel-o"></i> 导出CSV报表</button>
            <label style="display:flex;align-items:center;gap:6px;">
                <input type="checkbox" id="autoRefresh"> 60秒自动刷新
            </label>
        </div>
    </div>

    <!-- 统计图表 -->
    <div class="card" id="statCard" style="display:none;">
        <div class="stat-row">
            <div class="stat-card stat-1">
                <div class="stat-label">告警种类</div>
                <div class="stat-num" id="statTotal">0</div>
            </div>
            <div class="stat-card stat-2">
                <div class="stat-label">触发中</div>
                <div class="stat-num" id="statFiring">0</div>
            </div>
            <div class="stat-card stat-3">
                <div class="stat-label">已恢复</div>
                <div class="stat-num" id="statResolved">0</div>
            </div>
            <div class="stat-card stat-4">
                <div class="stat-label">严重告警</div>
                <div class="stat-num" id="statCritical">0</div>
            </div>
        </div>
        <div class="chart-row">
            <div>
                <h4 class="card-title">24小时告警触发趋势</h4>
                <div class="chart-box">
                    <canvas id="hourChart"></canvas>
                </div>
            </div>
            <div>
                <h4 class="card-title">告警级别分布占比</h4>
                <div class="chart-box">
                    <canvas id="pieChart"></canvas>
                </div>
            </div>
        </div>
    </div>

    <!-- 告警表格 -->
    <div class="card">
        <div class="table-wrap">
            <table>
                <thead id="tableHead"></thead>
                <tbody id="tableBody">
                    <tr><td colspan="6" class="empty-box">数据加载中...</td></tr>
                </tbody>
            </table>
        </div>
        <div class="pagination">
            <div class="pag-info">总告警条数：<span id="pageTotal">0</span></div>
            <div style="display:flex;gap:8px;align-items:center;">
                <span>每页展示</span>
                <select id="pageSizeSel" class="pag-btn">
                    <option value="10">10</option>
                    <option value="20" selected>20</option>
                    <option value="50">50</option>
                </select>
                <button class="pag-btn" id="pageFirst">首页</button>
                <button class="pag-btn" id="pagePrev">上一页</button>
                <span id="pageInfo">1 / 1</span>
                <button class="pag-btn" id="pageNext">下一页</button>
                <button class="pag-btn" id="pageLast">末页</button>
            </div>
        </div>
    </div>
    <div class="shortcut-tip">快捷键：Enter快速查询 | ESC关闭弹窗 | Ctrl+F全局搜索</div>
</div>
<script>
// 原有告警查询、图表、分页、导出逻辑不变
const grafanaBase = "<?php echo $grafanaUrl; ?>";
let page = 1;
let pageSize = 20;
let total = 0;
let distinctMode = 1;
let autoRefreshTimer = null;
let hourChart = null;
let pieChart = null;
const stormThreshold = 1000;
const t = {
    col_state:"状态",col_alert:"告警名称",col_instance:"实例",
    col_severity:"级别",col_count:"触发次数",col_time:"最新时间",
    empty_tip:"暂无匹配告警数据，请调整筛选条件",storm_tip:"风暴告警"
};
function saveFilter(){
    const d={start:$("#startDate").val(),end:$("#endDate").val(),instance:$("#filterInstance").val(),global:$("#globalSearch").val(),sev:$("input[name=sev]:checked").map((i,e)=>e.value).get(),sta:$("input[name=sta]:checked").map((i,e)=>e.value).get(),distinct:distinctMode,pageSize:pageSize};
    localStorage.setItem("alertFilter",JSON.stringify(d));
}
function loadFilter(){
    const s=localStorage.getItem("alertFilter");if(!s)return;
    const d=JSON.parse(s);
    $("#startDate").val(d.start);$("#endDate").val(d.end);$("#filterInstance").val(d.instance);$("#globalSearch").val(d.global);
    pageSize=d.pageSize;$("#pageSizeSel").val(pageSize);distinctMode=d.distinct;
    $("#modeTip").text(distinctMode===1?"当前：去重汇总模式":"当前：逐条时序模式");
    $("input[name=sev]").prop("checked",false);d.sev.forEach(v=>$(`input[name=sev][value="${v}"]`).prop("checked",true));
    $("input[name=sta]").prop("checked",false);d.sta.forEach(v=>$(`input[name=sta][value="${v}"]`).prop("checked",true));
}
function renderHead(){
    let h="";
    if(distinctMode===1){
        h=`<tr><th>${t.col_state}</th><th>${t.col_alert}</th><th>${t.col_instance}</th><th>${t.col_severity}</th><th>${t.col_count}</th><th>${t.col_time}</th><th>操作</th></tr>`;
    }else{
        h=`<tr><th>${t.col_state}</th><th>${t.col_alert}</th><th>${t.col_instance}</th><th>${t.col_severity}</th><th>${t.col_time}</th><th>操作</th></tr>`;
    }
    $("#tableHead").html(h);
}
function drawChart(stat){
    $("#statCard").show();
    $("#statTotal").text(stat.total_all);$("#statFiring").text(stat.total_firing);
    $("#statResolved").text(stat.total_resolved);$("#statCritical").text(stat.total_critical);
    const hourData=stat.hour_data,hourLabels=[],hourVals=[];
    for(let i=0;i<24;i++){hourLabels.push(i+":00");hourVals.push(hourData[i]);}
    if(hourChart) hourChart.destroy();
    const hCtx=document.getElementById("hourChart").getContext("2d");
    hourChart=new Chart(hCtx,{type:"line",data:{labels:hourLabels,datasets:[{label:"触发量",data:hourVals,borderColor:"#165DFF",backgroundColor:"rgba(22,93,255,0.08)",fill:true,tension:0.2,pointRadius:2}]},
    options:{responsive:true,maintainAspectRatio:false,plugins:{legend:{position:"top",labels:{boxWidth:12,font:{size:12}}}},scales:{x:{grid:{display:false}},y:{grid:{color:"#F2F3F5"}}}}});
    if(pieChart) pieChart.destroy();
    const pCtx=document.getElementById("pieChart").getContext("2d");
    let c=0,w=0,i=0;$("#tableBody tr").each((idx,tr)=>{const s=$(tr).find("td:nth-child(4)").text();if(s.includes("critical"))c++;else if(s.includes("warning"))w++;else i++;});
    pieChart=new Chart(pCtx,{type:"doughnut",data:{labels:["Critical","Warning","Info"],datasets:[{data:[c,w,i],backgroundColor:["#F53F3F","#FF7D00","#165DFF"],borderWidth:0}]},
    options:{responsive:true,maintainAspectRatio:false,plugins:{legend:{position:"bottom"}},cutout:"60%"}});
}
function loadData(){
    saveFilter();renderHead();
    $("#tableBody").html(`<tr><td colspan="${distinctMode===1?7:6}" class="empty-box">数据加载中...</td></tr>`);
    const sevArr=$("input[name=sev]:checked").map((i,e)=>e.value).get();
    const staArr=$("input[name=sta]:checked").map((i,e)=>e.value).get();
    const params=new URLSearchParams();
    params.append("page",page);params.append("page_size",pageSize);
    params.append("start_date",$("#startDate").val());params.append("end_date",$("#endDate").val());
    params.append("instance",$("#filterInstance").val());params.append("global",$("#globalSearch").val());
    params.append("distinct",distinctMode);
    sevArr.forEach(v=>params.append("severity[]",v));staArr.forEach(v=>params.append("status[]",v));
    fetch(`./api/api_alert_list.php?${params.toString()}`).then(r=>r.json()).then(res=>{
        if(res.code!==0){$("#tableBody").html(`<tr><td colspan="${distinctMode===1?7:6}" class="empty-box" style="color:#F53F3F;">${res.msg}</td></tr>`);$("#statCard").hide();return;}
        total=res.total;$("#pageTotal").text(total);const tp=Math.ceil(total/pageSize)||1;$("#pageInfo").text(`${page} / ${tp}`);
        if(res.stat.total_all>0) drawChart(res.stat);else $("#statCard").hide();
        const list=res.list;if(list.length===0){$("#tableBody").html(`<tr><td colspan="${distinctMode===1?7:6}" class="empty-box">${t.empty_tip}</td></tr>`);return;}
        let html="";
        list.forEach(row=>{
            const cls=row.state==="firing"?"row-firing":"row-resolved";
            const tagText=row.state==="firing"?"Firing":"Resolved";
            let sevCls="";if(row.severity==="critical")sevCls="color:#F53F3F";else if(row.severity==="warning")sevCls="color:#FF7D00";else sevCls="color:#165DFF";
            let storm="";if(distinctMode===1&&row.total_count>stormThreshold)storm=`<span class="storm">${t.storm_tip}</span>`;
            if(distinctMode===1){
                html+=`<tr class="${cls}" data-row='${JSON.stringify(row)}'>
                    <td>${tagText}</td><td>${row.metric}</td><td>${row.instance}</td>
                    <td style="${sevCls}">${row.severity}</td><td>${row.total_count} ${storm}</td><td>${row.time}</td>
                    <td><button class="btn btn-sm btn-outline copy-name" data-name="${row.metric}">复制告警</button></td>
                </tr>`;
            }else{
                html+=`<tr class="${cls}" data-row='${JSON.stringify(row)}'>
                    <td>${tagText}</td><td>${row.metric}</td><td>${row.instance}</td>
                    <td style="${sevCls}">${row.severity}</td><td>${row.time}</td>
                    <td><button class="btn btn-sm btn-outline copy-name" data-name="${row.metric}">复制告警</button></td>
                </tr>`;
            }
        });
        $("#tableBody").html(html);
    }).catch(()=>{$("#tableBody").html(`<tr><td colspan="${distinctMode===1?7:6}" class="empty-box" style="color:#F53F3F;">接口请求失败</td></tr>`);$("#statCard").hide();});
}
function exportExcel(){
    const sevArr=$("input[name=sev]:checked").map((i,e)=>e.value).get();
    const staArr=$("input[name=sta]").map((i,e)=>e.value).get();
    const params=new URLSearchParams();
    params.append("export",1);params.append("page_size",9999);
    params.append("start_date",$("#startDate").val());params.append("end_date",$("#endDate").val());
    params.append("instance",$("#filterInstance").val());params.append("global",$("#globalSearch").val());
    params.append("distinct",distinctMode);
    sevArr.forEach(v=>params.append("severity[]",v));staArr.forEach(v=>params.append("status[]",v));
    fetch(`./api/api_alert_list.php?${params.toString()}`).then(r=>r.json()).then(res=>{
        if(res.code!==0) return alert(res.msg);
        let csv="";
        if(distinctMode===1) csv="状态,告警名称,实例,级别,触发次数,最新时间\n";
        else csv="状态,告警名称,实例,级别,触发时间\n";
        res.list.forEach(r=>{
            if(distinctMode===1) csv+=`${r.state},${r.metric},${r.instance},${r.severity},${r.total_count},${r.time}\n`;
            else csv+=`${r.state},${r.metric},${r.instance},${r.severity},${r.time}\n`;
        });
        const blob=new Blob([csv],{type:"text/csv;charset=utf-8"});
        const a=document.createElement("a");a.href=URL.createObjectURL(blob);a.download=`告警报表_${new Date().getTime()}.csv`;a.click();
    });
}
function toggleAutoRefresh(){
    if($("#autoRefresh").is(":checked")) autoRefreshTimer=setInterval(()=>loadData(),60000);
    else clearInterval(autoRefreshTimer);
}
$(function(){
    loadFilter();loadData();
    $("#btnSearch").click(()=>{page=1;loadData();});
    $("#btnReset").click(()=>{
        const today=new Date().toISOString().split('T')[0];
        $("#startDate").val(today);$("#endDate").val(today);$("#filterInstance").val("");$("#globalSearch").val("");
        $("input[name=sev]").prop("checked",false);$("input[name=sta]").prop("checked",false);
        distinctMode=1;$("#modeTip").text("当前：去重汇总模式");page=1;loadData();
    });
    $("#btnToggleMode").click(()=>{distinctMode=distinctMode===1?0:1;$("#modeTip").text(distinctMode===1?"当前：去重汇总模式":"当前：逐条时序模式");page=1;loadData();});
    $("#btnExport").click(exportExcel);
    $("#autoRefresh").change(toggleAutoRefresh);
    $("#pageSizeSel").change(function(){pageSize=parseInt($(this).val());page=1;loadData();});
    $("#pageFirst").click(()=>{page=1;loadData();});
    $("#pagePrev").click(()=>{if(page>1){page--;loadData();}});
    $("#pageNext").click(()=>{const tp=Math.ceil(total/pageSize);if(page<tp){page++;loadData();}});
    $("#pageLast").click(()=>{page=Math.ceil(total/pageSize);loadData();});
    $(document).on("click",".copy-name",function(){
        const name=$(this).data("name");
        navigator.clipboard.writeText(name).then(()=>alert("已复制告警名称："+name));
    });
    $(document).keydown(function(e){
        if(e.key==="Enter"){e.preventDefault();page=1;loadData();}
        if(e.ctrlKey&&e.key.toLowerCase()==="f"){e.preventDefault();$("#globalSearch").focus();}
    });
})
</script>
</body>
</html>
