feat: DevTools 仪表盘新增自重启功能
- 新增 POST /api/devtools/restart 端点(spawn 新进程 + exit 旧进程) - 仪表盘服务状态卡片新增「🔁 重启 DevTools」按钮 - 重启流程:确认 → API 调用 → 2s 后自动刷新页面 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -1213,6 +1213,7 @@ async function renderDashboard() {
|
|||||||
'<button class="btn btn-sm btn-accent" onclick="svcAction(\'start-all\')">▶ 一键启动</button>' +
|
'<button class="btn btn-sm btn-accent" onclick="svcAction(\'start-all\')">▶ 一键启动</button>' +
|
||||||
'<button class="btn btn-sm" onclick="svcAction(\'start-all-fresh\')">🔄 强制重启全部</button>' +
|
'<button class="btn btn-sm" onclick="svcAction(\'start-all-fresh\')">🔄 强制重启全部</button>' +
|
||||||
'<button class="btn btn-sm btn-red" onclick="svcAction(\'stop-all\')">⏹ 全部停止</button>' +
|
'<button class="btn btn-sm btn-red" onclick="svcAction(\'stop-all\')">⏹ 全部停止</button>' +
|
||||||
|
'<button class="btn btn-sm" onclick="restartDevTools()" style="margin-left:8px;border-color:var(--accent);color:var(--accent)" title="重启 DevTools 自身以应用更新">🔁 重启 DevTools</button>' +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
'<div class="cards-grid cards-4" id="dashboard-svc-cards"></div>' +
|
'<div class="cards-grid cards-4" id="dashboard-svc-cards"></div>' +
|
||||||
@@ -2341,6 +2342,20 @@ async function clearSvcLogs() {
|
|||||||
renderServiceLog();
|
renderServiceLog();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---- DevTools 自重启 ----
|
||||||
|
async function restartDevTools() {
|
||||||
|
if (!confirm('确定要重启 DevTools 吗?\n\n页面将在几秒后自动刷新。')) return;
|
||||||
|
try {
|
||||||
|
await api('/api/devtools/restart', { method: 'POST' });
|
||||||
|
} catch (e) {
|
||||||
|
// 请求可能在收到响应前就中断(因为服务已退出),这是正常的
|
||||||
|
}
|
||||||
|
// 等待新进程就绪后刷新
|
||||||
|
setTimeout(function() {
|
||||||
|
location.reload();
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
|
||||||
// ---- 服务操作 ----
|
// ---- 服务操作 ----
|
||||||
async function svcAction(cmd, serviceId) {
|
async function svcAction(cmd, serviceId) {
|
||||||
var actionLabels = { start: "启动", stop: "停止", restart: "重启", build: "编译", "start-all": "一键启动", "start-all-fresh": "强制重启全部", "stop-all": "全部停止" };
|
var actionLabels = { start: "启动", stop: "停止", restart: "重启", build: "编译", "start-all": "一键启动", "start-all-fresh": "强制重启全部", "stop-all": "全部停止" };
|
||||||
|
|||||||
@@ -215,6 +215,23 @@ app.get('/api/health', (_req, res) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ---- DevTools 自重启 ----
|
||||||
|
app.post('/api/devtools/restart', (_req, res) => {
|
||||||
|
res.json({ success: true, message: 'DevTools 正在重启...' });
|
||||||
|
|
||||||
|
// 延迟 500ms 确保响应已发送,然后 spawn 新进程并退出
|
||||||
|
setTimeout(() => {
|
||||||
|
const scriptPath = path.join(__dirname, 'index.js');
|
||||||
|
const child = spawn(process.execPath, [scriptPath, ...process.argv.slice(2)], {
|
||||||
|
cwd: ROOT,
|
||||||
|
detached: true,
|
||||||
|
stdio: 'inherit',
|
||||||
|
});
|
||||||
|
child.unref();
|
||||||
|
process.exit(0);
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
|
||||||
// ---- 仪表盘数据 (必须在 /api/services/:id 之前以避免路由冲突) ----
|
// ---- 仪表盘数据 (必须在 /api/services/:id 之前以避免路由冲突) ----
|
||||||
app.get('/api/dashboard', async (_req, res) => {
|
app.get('/api/dashboard', async (_req, res) => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
Reference in New Issue
Block a user