<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5">
    <title>巡检执行 - 服务监测</title>
    <style>
        :root {
            --primary:#2563eb; --primary-hover:#1d4ed8;
            --green:#16a34a; --yellow:#d97706; --red:#dc2626;
            --gray-50:#f9fafb; --gray-100:#f3f4f6; --gray-200:#e5e7eb;
            --gray-400:#9ca3af; --gray-500:#6b7280; --gray-700:#374151; --gray-900:#111827;
        }
        * { box-sizing:border-box; margin:0; padding:0; }
        body { font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Microsoft YaHei",sans-serif; background:#f3f4f6; min-height:100vh; }
        .navbar { background:linear-gradient(135deg,#667eea 0%,#764ba2 100%); padding:14px 24px; display:flex; align-items:center; justify-content:space-between; }
        .navbar-left { display:flex; align-items:center; gap:14px; }
        .navbar-brand { color:#fff; font-size:18px; font-weight:700; text-decoration:none; }
        .navbar-module { color:rgba(255,255,255,.7); font-size:14px; }
        .navbar-home { background:rgba(255,255,255,.2); color:#fff; border:1px solid rgba(255,255,255,.35); padding:6px 14px; border-radius:8px; font-size:13px; font-weight:600; text-decoration:none; }
        .navbar-user { color:#fff; font-size:14px; }

        .container { max-width:720px; margin:0 auto; padding:28px 24px; }
        .run-card { background:#fff; border-radius:14px; box-shadow:0 2px 8px rgba(0,0,0,.06); border:1px solid var(--gray-200); padding:26px; }

        .run-head { display:flex; align-items:center; justify-content:space-between; margin-bottom:20px; }
        .run-title { font-size:18px; font-weight:700; color:var(--gray-900); }
        .run-title .suite-tag { font-size:13px; font-weight:600; padding:3px 10px; border-radius:6px; margin-left:8px; background:#eef2ff; color:var(--primary); }
        .btn-cancel { background:#fee2e2; color:var(--red); border:none; padding:8px 16px; border-radius:8px; font-size:14px; font-weight:600; cursor:pointer; }
        .btn-cancel:disabled { opacity:.4; cursor:not-allowed; }

        /* 进度条 */
        .progress-wrap { margin-bottom:6px; }
        .progress-bar { height:12px; background:var(--gray-100); border-radius:6px; overflow:hidden; }
        .progress-fill { height:100%; background:linear-gradient(90deg,var(--primary),#60a5fa); width:0%; transition:width .3s; }
        .progress-text { display:flex; justify-content:space-between; font-size:13px; color:var(--gray-500); margin-top:8px; }

        /* 模块清单 */
        .module-list { margin-top:20px; }
        .module-item { display:flex; align-items:center; gap:12px; padding:12px 0; border-bottom:1px solid var(--gray-100); }
        .module-item:last-child { border-bottom:none; }
        .module-status { font-size:18px; width:24px; text-align:center; }
        .module-name { flex:1; font-size:15px; color:var(--gray-700); }
        .module-info { font-size:13px; color:var(--gray-500); }
        .st-pending .module-name { color:var(--gray-400); }
        .st-running .module-name { color:var(--primary); font-weight:600; }
        .st-done .module-name { color:var(--gray-900); }
        .sm-ok { color:var(--green); } .sm-warn { color:var(--yellow); } .sm-crit { color:var(--red); }

        .spinner { display:inline-block; width:16px; height:16px; border:2px solid var(--gray-200); border-top-color:var(--primary); border-radius:50%; animation:spin .8s linear infinite; }
        @keyframes spin { to { transform:rotate(360deg); } }

        .done-banner { display:none; text-align:center; padding:20px; margin-top:10px; border-radius:10px; }
        .done-banner.show { display:block; }
        .done-ok { background:#dcfce7; color:#15803d; }
        .done-err { background:#fee2e2; color:var(--red); }
        .btn-report { display:inline-block; margin-top:12px; background:var(--primary); color:#fff; padding:9px 22px; border-radius:8px; font-size:14px; font-weight:600; text-decoration:none; }

        @media screen and (max-width:768px) {
            .container { padding:20px 14px; }
            .navbar-module { display:none; }
        }
    </style>
</head>
<body>
    <div class="navbar">
        <div class="navbar-left">
            <a href="/" class="navbar-brand">🛠️ 运行维护平台</a>
            <span class="navbar-module">/ 服务监测 / 巡检执行</span>
            <a href="/service-monitor" class="navbar-home">← 返回</a>
        </div>
        <div class="navbar-user">{{ user.username }}（管理员）</div>
    </div>

    <div class="container">
        <div class="run-card">
            <div class="run-head">
                <div class="run-title">
                    {{ '🖥️' if target.type == 'local' else '🌐' }} {{ target.name }}
                    <span class="suite-tag">{{ '⚡ 快速巡检' if suite == 'quick' else '🔍 全量巡检' }}</span>
                </div>
                <button class="btn-cancel" id="btn-cancel" onclick="cancelRun()">取消</button>
            </div>

            <div class="progress-wrap">
                <div class="progress-bar"><div class="progress-fill" id="progress-fill"></div></div>
                <div class="progress-text">
                    <span id="progress-current">准备中...</span>
                    <span id="progress-count">0 / 0</span>
                </div>
            </div>

            <div class="module-list" id="module-list"></div>

            <div class="done-banner" id="done-banner">
                <div id="done-text"></div>
                <a href="#" class="btn-report" id="btn-report" style="display:none;">查看报告 →</a>
            </div>
        </div>
    </div>

    <script>
        const TARGET_ID = "{{ target.id }}";
        const SUITE = "{{ suite }}";
        let currentRunId = null;
        let evtSource = null;
        const moduleEls = {};

        function statusIcon(st) {
            if (st === 'done') return '✓';
            if (st === 'running') return '<span class="spinner"></span>';
            return '○';
        }

        function ensureModuleEl(name) {
            if (moduleEls[name]) return moduleEls[name];
            const div = document.createElement('div');
            div.className = 'module-item st-pending';
            div.innerHTML = `<span class="module-status">○</span><span class="module-name">${name}</span><span class="module-info"></span>`;
            document.getElementById('module-list').appendChild(div);
            moduleEls[name] = div;
            return div;
        }

        function setModuleStatus(name, st, info) {
            const el = ensureModuleEl(name);
            el.className = 'module-item st-' + st;
            el.querySelector('.module-status').innerHTML = statusIcon(st);
            if (info !== undefined) el.querySelector('.module-info').innerHTML = info;
        }

        function startInspection() {
            const url = `/api/service-monitor/run/stream?target_id=${encodeURIComponent(TARGET_ID)}&suite=${encodeURIComponent(SUITE)}`;
            evtSource = new EventSource(url);

            evtSource.onmessage = (e) => {
                let evt;
                try { evt = JSON.parse(e.data); } catch(_) { return; }
                if (evt.run_id) currentRunId = evt.run_id;

                if (evt.event === 'progress') {
                    document.getElementById('progress-current').textContent = evt.current || '巡检中...';
                    if (evt.total) {
                        const pct = Math.round((evt.done / evt.total) * 100);
                        document.getElementById('progress-fill').style.width = pct + '%';
                        document.getElementById('progress-count').textContent = `${evt.done} / ${evt.total}`;
                    }
                    if (evt.current && !evt.current.includes('...') && !evt.current.includes('测试') && !evt.current.includes('上传')) {
                        setModuleStatus(evt.current, 'running');
                    }
                } else if (evt.event === 'module_done') {
                    const s = evt.summary || {};
                    let info = `${evt.items_count}项`;
                    const parts = [];
                    if (s['正常']) parts.push(`<span class="sm-ok">✓${s['正常']}</span>`);
                    if (s['警告']) parts.push(`<span class="sm-warn">⚠${s['警告']}</span>`);
                    if (s['严重']) parts.push(`<span class="sm-crit">✗${s['严重']}</span>`);
                    info += ' ' + parts.join(' ');
                    setModuleStatus(evt.module, 'done', info);
                } else if (evt.event === 'finished') {
                    finishRun(true, evt.report_id, evt.summary);
                } else if (evt.event === 'error') {
                    finishRun(false, null, null, evt.message);
                } else if (evt.event === 'cancelled') {
                    finishRun(false, null, null, '巡检已取消');
                }
            };

            evtSource.onerror = () => {
                if (evtSource) { evtSource.close(); evtSource = null; }
            };
        }

        function finishRun(ok, reportId, summary, errMsg) {
            if (evtSource) { evtSource.close(); evtSource = null; }
            document.getElementById('btn-cancel').disabled = true;
            const banner = document.getElementById('done-banner');
            const text = document.getElementById('done-text');
            banner.classList.add('show');
            if (ok) {
                document.getElementById('progress-fill').style.width = '100%';
                document.getElementById('progress-current').textContent = '巡检完成';
                banner.className = 'done-banner show done-ok';
                const s = summary || {};
                text.innerHTML = `✅ 巡检完成：正常 ${s['正常']||0}，警告 ${s['警告']||0}，严重 ${s['严重']||0}`;
                if (reportId) {
                    const btn = document.getElementById('btn-report');
                    btn.href = '/service-monitor/report/' + reportId;
                    btn.style.display = 'inline-block';
                    setTimeout(() => { window.location.href = btn.href; }, 1500);
                }
            } else {
                banner.className = 'done-banner show done-err';
                text.textContent = '❌ ' + (errMsg || '巡检失败');
            }
        }

        async function cancelRun() {
            if (currentRunId) {
                try { await fetch(`/api/service-monitor/run/${currentRunId}/cancel`, {method:'POST', credentials:'include'}); } catch(e) {}
            }
            if (evtSource) { evtSource.close(); evtSource = null; }
            finishRun(false, null, null, '巡检已取消');
        }

        window.addEventListener('DOMContentLoaded', startInspection);
    </script>
</body>
</html>
