feat(router): v0.2.4 阶段二 管理入口迁移与前端同步

管理入口从 /admin 迁至 /dashboard:
- /dashboard、/dashboard/voices、/dashboard/settings 为新入口
- 原挂在 /dashboard 上的服务状态预览页(health.html)迁至 /dashboard/status,
  侧边栏新增「观测 → 详细状态」入口
- /admin 及子路径 301 永久重定向到对应新路径(页面用 301 是正确的)
- 静态资源同时注册 /dashboard/ 与 /admin/ 两套路径,
  避免过渡期出现"页面能开但丢样式"

前端同步:
- admin-shell.js:侧边栏导航、登出、登录跳转改指 /dashboard/*
- admin.html / admin-login.html / admin-voices.html / admin-settings.html:
  静态资源引用与登录跳转改指 /dashboard/*
- health.html:改用 admin-shell 的 http 实例并改调 /admin/health、/admin/metrics
  (该实例自动附加 Authorization: Bearer;原实现用裸 axios,不带凭证),
  并加登录校验与「返回控制台」入口
- setup.html:安装完成跳转目标改为 /dashboard,页面内 /admin 文案同步更新
- 各页面的 API 调用路径无需修改:axios baseURL 为 /api,
  故 /voices、/admin/overview 等自动落成 /api/admin/*

controller/setup.go:安装成功响应的 redirect 字段由 /admin 改为 /dashboard。

验证:go build / go vet / go test ./... -count=1 全绿;
另用真实服务器端到端验证:旧入口 301 全部正确、静态资源新旧路径均 200、
管理页面内容协商(html 200 / 非 html 401)、登录页公开、
各页面引用的静态资源均为新路径且无残留旧路径。
This commit is contained in:
sun
2026-10-04 01:17:26 +08:00
parent 1e2e37ae97
commit 5113941f44
8 changed files with 41 additions and 28 deletions
+10 -3
View File
@@ -6,6 +6,7 @@
<title>TTS 服务监控</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/3.4.21/vue.global.prod.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/1.6.7/axios.min.js"></script>
<link rel="stylesheet" href="/dashboard/admin.css">
<style>
:root {
--bg: #0b0f1a;
@@ -148,6 +149,7 @@
</div>
</div>
<div class="row-flex">
<a class="btn" href="/dashboard" style="text-decoration:none;">← 返回控制台</a>
<span class="status-badge" :class="health.status === 'ok' ? 'ok' : 'error'">
<span class="status-dot" :class="{ live: health.status === 'ok' }"></span>
{{ health.status === 'ok' ? '运行中' : (health.status || '加载中') }}
@@ -377,8 +379,11 @@
</div>
</div>
<script src="/dashboard/admin-shell.js"></script>
<script>
const { createApp, ref, computed, onMounted } = Vue;
// v0.3.0:/health 与 /metrics 已收口到鉴权接口,统一走带凭证头的 /api/admin/*
const { http, getKey } = window.admin;
function parseProm(text) {
const out = {};
@@ -597,16 +602,16 @@
const fetchHealth = async () => {
try {
const r = await axios.get("/health");
const r = await http.get("/admin/health");
health.value = r.data;
} catch (e) {
error.value = "无法获取健康状态: " + (e.message || "未知错误");
error.value = "无法获取健康状态: " + (e.response?.data?.error?.message || e.message || "未知错误");
}
};
const fetchMetrics = async () => {
try {
const r = await axios.get("/metrics");
const r = await http.get("/admin/metrics");
metrics.value = parseProm(r.data);
} catch (e) {
// 不覆盖 error,让 health 错误更显眼
@@ -650,6 +655,8 @@
};
onMounted(() => {
// v0.3.0:本页已收口到管理鉴权,未登录先回登录页
if (!getKey()) { location.href = '/dashboard/login'; return; }
refresh();
setInterval(refresh, 10000);
});