321 lines
13 KiB
HTML
321 lines
13 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<title>ServiceManager 测试</title>
|
||
<style>
|
||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||
body { font-family: Consolas, monospace; background: #1a1a2e; color: #eee; padding: 20px; }
|
||
h1 { color: #00d4ff; margin-bottom: 20px; text-align: center; }
|
||
.panel { background: #16213e; border-radius: 8px; padding: 15px; margin-bottom: 15px; }
|
||
.panel-title { color: #00d4ff; font-size: 14px; margin-bottom: 10px; }
|
||
.row { display: flex; gap: 10px; align-items: center; margin-bottom: 10px; flex-wrap: wrap; }
|
||
label { color: #888; min-width: 80px; }
|
||
input { background: #0f3460; border: 1px solid #00d4ff; color: #fff; padding: 8px; border-radius: 4px; }
|
||
input[type="text"] { width: 300px; }
|
||
input[type="number"] { width: 100px; }
|
||
button { padding: 8px 16px; border: none; border-radius: 4px; cursor: pointer; font-family: inherit; }
|
||
.btn-primary { background: #00d4ff; color: #1a1a2e; }
|
||
.btn-success { background: #28a745; color: #fff; }
|
||
.btn-danger { background: #dc3545; color: #fff; }
|
||
.btn-warning { background: #ffc107; color: #1a1a2e; }
|
||
.btn-purple { background: #9b59b6; color: #fff; }
|
||
button:disabled { opacity: 0.5; cursor: not-allowed; }
|
||
button:hover:not(:disabled) { opacity: 0.85; }
|
||
.log-box { background: #0d1b2a; border-radius: 4px; padding: 10px; height: 280px; overflow-y: auto; font-size: 12px; }
|
||
.log-entry { padding: 4px 0; border-bottom: 1px solid #1a1a2e; }
|
||
.log-entry:first-child { border-top: 1px solid #1a1a2e; }
|
||
.log-info .lv { color: #3498db; }
|
||
.log-success .lv { color: #27ae60; }
|
||
.log-error .lv { color: #e74c3c; }
|
||
.log-warn .lv { color: #f39c12; }
|
||
.log-debug .lv { color: #9b59b6; }
|
||
.log-data { background: #1a1a2e; padding: 4px; border-radius: 3px; margin-top: 3px; font-size: 11px; white-space: pre-wrap; word-break: break-all; color: #888; }
|
||
.info { color: #888; font-size: 12px; }
|
||
.status-card { background: #1a1a2e; padding: 15px; border-radius: 8px; text-align: center; margin: 10px 0; }
|
||
.status-card.running { border-left: 4px solid #27ae60; }
|
||
.status-card.stopped { border-left: 4px solid #e74c3c; }
|
||
.status-name { font-size: 18px; font-weight: bold; margin-bottom: 10px; }
|
||
.status-pid { color: #888; font-size: 14px; }
|
||
.big-btn { padding: 12px 30px; font-size: 14px; }
|
||
.console-hint { background: #0d1b2a; padding: 8px; border-radius: 4px; margin-top: 10px; font-size: 11px; color: #888; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<h1>🔧 ServiceManager 测试</h1>
|
||
|
||
<!-- DEBUG 控制 -->
|
||
<div class="panel">
|
||
<div class="panel-title">🔧 DEBUG 控制</div>
|
||
<div class="row">
|
||
<button class="btn-purple" id="btnDebugOn">开启 DEBUG</button>
|
||
<button class="btn-purple" id="btnDebugOff">关闭 DEBUG</button>
|
||
<span class="info" id="debugStatus">DEBUG: 关闭</span>
|
||
</div>
|
||
<div class="console-hint">
|
||
💡 开启DEBUG后,打开浏览器控制台(F12)可看到详细的请求/响应调试信息
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 配置 -->
|
||
<div class="panel">
|
||
<div class="panel-title">⚙️ 配置</div>
|
||
<div class="row">
|
||
<label>API 地址:</label>
|
||
<input type="text" id="apiUrl" value="http://127.0.0.1:5000">
|
||
</div>
|
||
<div class="row">
|
||
<label>轮询间隔:</label>
|
||
<input type="number" id="pollMs" value="3000">
|
||
<span class="info">ms</span>
|
||
</div>
|
||
<div class="row">
|
||
<button class="btn-primary" id="btnCreate">创建实例</button>
|
||
<button class="btn-danger" id="btnDestroy" disabled>销毁实例</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 操作 -->
|
||
<div class="panel">
|
||
<div class="panel-title">🎮 操作</div>
|
||
<div class="row">
|
||
<button class="btn-success" id="btnGetStatus" disabled>查询状态</button>
|
||
<button class="btn-success big-btn" id="btnStart" disabled>启动</button>
|
||
<button class="btn-danger big-btn" id="btnStop" disabled>停止</button>
|
||
</div>
|
||
<div class="row">
|
||
<button class="btn-primary" id="btnAutoOn" disabled>开启自动刷新</button>
|
||
<button class="btn-warning" id="btnAutoOff" disabled>停止自动刷新</button>
|
||
</div>
|
||
<div class="info" id="autoInfo">自动刷新: 未启动</div>
|
||
</div>
|
||
|
||
<!-- 状态显示 -->
|
||
<div class="panel">
|
||
<div class="panel-title">📊 服务状态</div>
|
||
<div class="status-card stopped" id="statusCard">
|
||
<div class="status-name" id="statusName">未连接</div>
|
||
<div class="status-pid" id="statusPid">-</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 日志 -->
|
||
<div class="panel">
|
||
<div class="panel-title">📋 运行日志 <span id="logCount" style="color:#888;font-weight:normal">(0条)</span></div>
|
||
<div class="log-box" id="logBox"></div>
|
||
</div>
|
||
|
||
<!-- 引入编译后的类 -->
|
||
<script type="module">
|
||
import { ServiceManager } from './dist/ServiceManager.js';
|
||
|
||
// 全局变量
|
||
let sm = null;
|
||
|
||
// DOM 元素
|
||
const $ = id => document.getElementById(id);
|
||
const logBox = $('logBox');
|
||
const logCount = $('logCount');
|
||
const statusCard = $('statusCard');
|
||
const statusName = $('statusName');
|
||
const statusPid = $('statusPid');
|
||
const autoInfo = $('autoInfo');
|
||
const debugStatus = $('debugStatus');
|
||
|
||
// 日志显示
|
||
function addLog(entry) {
|
||
const div = document.createElement('div');
|
||
div.className = `log-entry log-${entry.level}`;
|
||
div.innerHTML = `
|
||
<span style="color:#666">${entry.time}</span>
|
||
<span class="lv">[${entry.level.toUpperCase()}]</span>
|
||
${entry.message}
|
||
`;
|
||
if (entry.data !== undefined) {
|
||
const data = document.createElement('div');
|
||
data.className = 'log-data';
|
||
data.textContent = typeof entry.data === 'object' ? JSON.stringify(entry.data, null, 2) : entry.data;
|
||
div.appendChild(data);
|
||
}
|
||
logBox.appendChild(div);
|
||
logBox.scrollTop = logBox.scrollHeight;
|
||
logCount.textContent = `(${logBox.children.length}条)`;
|
||
}
|
||
|
||
// 更新UI
|
||
function updateUI(service) {
|
||
if (!service) {
|
||
statusCard.className = 'status-card stopped';
|
||
statusName.textContent = '未连接';
|
||
statusPid.textContent = '-';
|
||
return;
|
||
}
|
||
|
||
statusCard.className = `status-card ${service.status}`;
|
||
statusName.textContent = service.status === 'running' ? '🟢 运行中' : '🔴 已停止';
|
||
statusPid.textContent = service.pid ? `PID: ${service.pid}` : 'PID: 无';
|
||
}
|
||
|
||
// 更新按钮状态
|
||
function updateBtns() {
|
||
const hasSm = sm !== null;
|
||
const autoOn = hasSm && sm.isAutoRefreshRunning();
|
||
|
||
$('btnDestroy').disabled = !hasSm;
|
||
$('btnGetStatus').disabled = !hasSm;
|
||
$('btnStart').disabled = !hasSm;
|
||
$('btnStop').disabled = !hasSm;
|
||
$('btnAutoOn').disabled = !hasSm || autoOn;
|
||
$('btnAutoOff').disabled = !hasSm || !autoOn;
|
||
|
||
autoInfo.textContent = `自动刷新: ${autoOn ? '开启 🟢' : '关闭'}`;
|
||
debugStatus.textContent = `DEBUG: ${ServiceManager.isDebugEnabled() ? '开启 🟢' : '关闭'}`;
|
||
}
|
||
|
||
// DEBUG 开关
|
||
$('btnDebugOn').onclick = () => {
|
||
ServiceManager.enableDebug();
|
||
debugStatus.textContent = 'DEBUG: 开启 🟢';
|
||
addLog({ time: new Date().toLocaleTimeString(), level: 'info', message: 'DEBUG 模式已开启,请在浏览器控制台查看详细日志' });
|
||
};
|
||
|
||
$('btnDebugOff').onclick = () => {
|
||
ServiceManager.disableDebug();
|
||
debugStatus.textContent = 'DEBUG: 关闭';
|
||
addLog({ time: new Date().toLocaleTimeString(), level: 'info', message: 'DEBUG 模式已关闭' });
|
||
};
|
||
|
||
// 创建实例
|
||
$('btnCreate').onclick = () => {
|
||
// 销毁旧实例
|
||
if (sm) {
|
||
sm.destroy();
|
||
sm = null;
|
||
}
|
||
|
||
const apiUrl = $('apiUrl').value;
|
||
const pollMs = parseInt($('pollMs').value) || 3000;
|
||
|
||
sm = new ServiceManager(apiUrl);
|
||
sm.setPollInterval(pollMs);
|
||
|
||
// 设置状态变化回调
|
||
sm.setOnStatusChange((service) => {
|
||
updateUI(service);
|
||
addLog({
|
||
time: new Date().toLocaleTimeString(),
|
||
level: service.running ? 'success' : 'warn',
|
||
message: `状态变化: ${service.name} → ${service.running ? '运行中' : '已停止'}`
|
||
});
|
||
});
|
||
|
||
addLog({ time: new Date().toLocaleTimeString(), level: 'success', message: `实例已创建 | API: ${apiUrl} | 轮询: ${pollMs}ms` });
|
||
updateBtns();
|
||
};
|
||
|
||
// 销毁实例
|
||
$('btnDestroy').onclick = () => {
|
||
if (sm) {
|
||
sm.destroy();
|
||
sm = null;
|
||
addLog({ time: new Date().toLocaleTimeString(), level: 'warn', message: '实例已销毁' });
|
||
updateUI(null);
|
||
updateBtns();
|
||
}
|
||
};
|
||
|
||
// 查询状态
|
||
$('btnGetStatus').onclick = async () => {
|
||
if (!sm) return;
|
||
|
||
addLog({ time: new Date().toLocaleTimeString(), level: 'info', message: '--- 查询状态 ---' });
|
||
|
||
// 打印所有日志
|
||
const logs1 = sm.getLogs();
|
||
logs1.forEach(log => addLog(log));
|
||
|
||
const services = await sm.getServicesStatus();
|
||
const logs2 = sm.getLogs();
|
||
// 只显示新的日志
|
||
logs2.slice(logs1.length).forEach(log => addLog(log));
|
||
|
||
if (services.length > 0) {
|
||
updateUI(services[0]);
|
||
}
|
||
};
|
||
|
||
// 启动
|
||
$('btnStart').onclick = async () => {
|
||
if (!sm) return;
|
||
|
||
addLog({ time: new Date().toLocaleTimeString(), level: 'info', message: '--- 启动服务 ---' });
|
||
const before = sm.getLogs().length;
|
||
|
||
await sm.startService('watchdog');
|
||
|
||
const logs = sm.getLogs();
|
||
logs.slice(before).forEach(log => addLog(log));
|
||
|
||
// 延迟刷新状态
|
||
setTimeout(async () => {
|
||
const before2 = sm.getLogs().length;
|
||
const services = await sm.getServicesStatus();
|
||
sm.getLogs().slice(before2).forEach(log => addLog(log));
|
||
updateUI(services[0]);
|
||
}, 1000);
|
||
};
|
||
|
||
// 停止
|
||
$('btnStop').onclick = async () => {
|
||
if (!sm) return;
|
||
|
||
addLog({ time: new Date().toLocaleTimeString(), level: 'info', message: '--- 停止服务 ---' });
|
||
const before = sm.getLogs().length;
|
||
|
||
await sm.stopService('watchdog');
|
||
|
||
const logs = sm.getLogs();
|
||
logs.slice(before).forEach(log => addLog(log));
|
||
|
||
// 延迟刷新状态
|
||
setTimeout(async () => {
|
||
const before2 = sm.getLogs().length;
|
||
const services = await sm.getServicesStatus();
|
||
sm.getLogs().slice(before2).forEach(log => addLog(log));
|
||
updateUI(services[0]);
|
||
}, 500);
|
||
};
|
||
|
||
// 开启自动刷新
|
||
$('btnAutoOn').onclick = () => {
|
||
if (!sm) return;
|
||
|
||
addLog({ time: new Date().toLocaleTimeString(), level: 'info', message: '--- 开启自动刷新 ---' });
|
||
|
||
sm.startAutoRefresh((services) => {
|
||
updateUI(services[0]);
|
||
const logs = sm.getLogs();
|
||
if (logs.length > 0) {
|
||
addLog(logs[logs.length - 1]);
|
||
}
|
||
});
|
||
|
||
updateBtns();
|
||
};
|
||
|
||
// 停止自动刷新
|
||
$('btnAutoOff').onclick = () => {
|
||
if (!sm) return;
|
||
|
||
addLog({ time: new Date().toLocaleTimeString(), level: 'warn', message: '--- 停止自动刷新 ---' });
|
||
sm.stopAutoRefresh();
|
||
updateBtns();
|
||
};
|
||
|
||
// 初始化提示
|
||
addLog({ time: new Date().toLocaleTimeString(), level: 'info', message: 'ServiceManager 测试页 | 点击"开启 DEBUG"查看详细日志' });
|
||
addLog({ time: new Date().toLocaleTimeString(), level: 'info', message: '请先开启 DEBUG 模式,然后点击"创建实例"' });
|
||
</script>
|
||
</body>
|
||
</html>
|