Files
micro_servers/static/public/mgmt/features/process.html
T
qing 34cd295005 feat(core): mgmt 接入 core 进程管理 + 管理员认证
- gateway 新增 POST /admin/verify 验签接口,供内部服务校验管理员 Token
- core 的 /list /exec /kill 接入管理员认证(调用 gateway 验签,fail-closed)
- gateway 代理 opened 白名单加入 core:5200
- mgmt 管理页显示当前用户与角色,进程页接入 core 进程管理接口
2026-08-04 20:00:24 +08:00

179 lines
6.1 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="icon" href="data:;base64,=">
<link rel="stylesheet" href="process.css">
</head>
<body>
<!-- stop, new flush -->
<button class="newBtn" onclick="newBtn()">新建</button>
<button class="flushBtn" onclick="flushBtn()">刷新</button>
<table border="1">
<thead>
<tr>
<th class="title">PID</th>
<th class="title">状态</th>
<th class="title">命令</th>
<th class="title">操作</th>
</tr>
</thead>
<tbody id="tBody"></tbody>
</table>
<div id="inProgressText"></div>
<div class="modal-con" id="modal-con">
<div class="window">
<div class="top-bar">
<div class="close-btn" onclick="closeModal()">X</div>
</div>
<div class="input">
<div class="prompt">输入命令:</div>
<input id="input-area" class="input-area" type="text">
</div>
<button class="create-btn" onclick="createProcess()">创建</button>
</div>
</div>
<script>
// core 进程管理接口经 gateway 代理(Target-Url 指向 core:5200)
const CORE_TARGET = "http://127.0.0.1:5200";
function handleUnauthorized(res) {
if (res.status === 401) {
alert("未授权或管理员 Token 已失效,请重新登录");
setTimeout(() => { window.location.href = "../index.html"; }, 800);
return true;
}
return false;
}
async function api(path, body) {
const res = await fetch(path, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Target-Url': CORE_TARGET
},
body: body ? JSON.stringify(body) : '{}'
});
if (handleUnauthorized(res)) return null;
const text = await res.text();
let result;
try {
result = JSON.parse(text);
} catch (e) {
console.error('接口返回非 JSON:', text);
throw new Error('服务器响应格式异常 (HTTP ' + res.status + ')');
}
if (!res.ok || !result.success) {
throw new Error(result.message || '请求失败 (HTTP ' + res.status + ')');
}
return result;
}
// 列表接口返回的 data,可能是数组,也可能是 ptree 序列化后的
// {"": {...}, "": {...}} 对象(boost property_tree 对数组的表示)
function toProcessArray(data) {
if (Array.isArray(data)) return data;
if (data && typeof data === "object") {
return Object.values(data);
}
return [];
}
async function loadProcesses() {
const tbody = document.getElementById("tBody");
const progress = document.getElementById("inProgressText");
tbody.innerHTML = "";
progress.innerText = "加载中...";
try {
const result = await api('/list');
const list = toProcessArray(result.data);
tbody.innerHTML = "";
for (let i = 0; i < list.length; i++) {
const p = list[i];
const tr = document.createElement("tr");
const pid = p.pid;
const status = p.status === true ? "运行中" : (p.status === false ? "已停止" : (p.status || "未知"));
tr.innerHTML = `
<td>${pid}</td>
<td>${status}</td>
<td>${p.command || p.target || "-"}</td>
<td><button class="stopBtn" onclick="stopBtn(${pid})">停止</button></td>
`;
tbody.appendChild(tr);
}
progress.innerText = "";
} catch (err) {
progress.innerText = "";
tbody.innerHTML = "";
alert(err.message || '加载进程列表失败');
}
}
function newBtn() {
const modal = document.getElementById("modal-con")
modal.style.display = "flex"
}
async function createProcess() {
const moduleName = document.getElementById("input-area").value.trim()
if (!moduleName) {
alert("请输入要执行的命令");
return;
}
const progress = document.getElementById("inProgressText");
progress.innerText = "启动中...";
try {
await api('/exec', { command: moduleName });
alert("启动成功");
closeModal();
await loadProcesses();
} catch (err) {
progress.innerText = "";
alert(err.message || '启动失败');
}
}
function flushBtn() {
loadProcesses();
}
async function stopBtn(pid) {
if (!confirm("确认停止该服务?")) {
return
}
const progress = document.getElementById("inProgressText");
progress.innerText = "停止中...";
try {
await api('/kill', { pid: pid });
alert("已停止");
await loadProcesses();
} catch (err) {
progress.innerText = "";
alert(err.message || '停止失败');
}
}
function closeModal() {
const modal = document.getElementById("modal-con")
const input = document.getElementById("input-area")
input.value = ""
modal.style.display = "none"
}
// 页面加载时自动拉取进程列表
window.onload = () => {
loadProcesses();
};
</script>
</body>
</html>