2026-08-29 21:53:19 +08:00
|
|
|
<!DOCTYPE html>
|
|
|
|
|
<html lang="zh-CN">
|
|
|
|
|
<head>
|
|
|
|
|
<meta charset="UTF-8">
|
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
2026-09-21 23:20:59 +08:00
|
|
|
<title>火山 TTS · 仪表盘</title>
|
2026-08-29 21:53:19 +08:00
|
|
|
<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>
|
2026-09-21 23:20:59 +08:00
|
|
|
<link rel="stylesheet" href="/admin/admin.css">
|
2026-08-29 21:53:19 +08:00
|
|
|
</head>
|
|
|
|
|
<body>
|
|
|
|
|
<div id="app">
|
2026-09-21 23:20:59 +08:00
|
|
|
<div class="app-shell">
|
|
|
|
|
<aside id="admin-sidebar"></aside>
|
2026-08-29 21:53:19 +08:00
|
|
|
|
2026-08-30 00:51:23 +08:00
|
|
|
<main class="main">
|
|
|
|
|
<header class="page-head">
|
|
|
|
|
<div>
|
2026-09-21 23:20:59 +08:00
|
|
|
<h1 class="page-title">仪表盘</h1>
|
|
|
|
|
<p class="page-sub">运行状态、版本与资源总览</p>
|
2026-08-29 21:53:19 +08:00
|
|
|
</div>
|
2026-08-30 00:51:23 +08:00
|
|
|
</header>
|
|
|
|
|
|
2026-09-21 23:20:59 +08:00
|
|
|
<div class="stat-grid">
|
|
|
|
|
<div class="stat-card">
|
|
|
|
|
<div class="stat-top">
|
|
|
|
|
<span class="stat-label">运行模式</span>
|
|
|
|
|
<span class="pill" :class="overview.installed ? 'pill-success' : 'pill-accent'">
|
|
|
|
|
<span class="pill-dot"></span>
|
|
|
|
|
{{ overview.installed ? '已就绪' : '待配置' }}
|
|
|
|
|
</span>
|
2026-08-30 00:51:23 +08:00
|
|
|
</div>
|
2026-09-21 23:20:59 +08:00
|
|
|
<div class="stat-value" :class="overview.installed ? 'text-success' : 'text-accent'">{{ overview.mode || '—' }}</div>
|
2026-08-29 21:53:19 +08:00
|
|
|
</div>
|
2026-09-21 23:20:59 +08:00
|
|
|
<div class="stat-card">
|
|
|
|
|
<div class="stat-top"><span class="stat-label">音色</span></div>
|
|
|
|
|
<div class="stat-value">{{ overview.voice_count ?? 0 }}<span class="stat-unit">条</span></div>
|
|
|
|
|
<div class="stat-foot">
|
|
|
|
|
<span class="text-success">{{ overview.voice_enabled_count ?? 0 }}</span> 启用 ·
|
|
|
|
|
<span class="text-dim">{{ (overview.voice_count ?? 0) - (overview.voice_enabled_count ?? 0) }}</span> 停用
|
2026-08-30 00:51:23 +08:00
|
|
|
</div>
|
2026-08-29 21:53:19 +08:00
|
|
|
</div>
|
2026-09-21 23:20:59 +08:00
|
|
|
<div class="stat-card">
|
|
|
|
|
<div class="stat-top"><span class="stat-label">运行时间</span></div>
|
|
|
|
|
<div class="stat-value">{{ formatUptime(overview.uptime_seconds) }}</div>
|
|
|
|
|
<div class="stat-foot text-dim">{{ formatStart(overview.start_time) }}</div>
|
2026-08-29 23:18:51 +08:00
|
|
|
</div>
|
2026-09-21 23:20:59 +08:00
|
|
|
<div class="stat-card">
|
|
|
|
|
<div class="stat-top"><span class="stat-label">数据库</span></div>
|
|
|
|
|
<div class="stat-value mono" style="font-size: 15px; word-break: break-all;">{{ shortPath(overview.db_path) || '—' }}</div>
|
|
|
|
|
<div class="stat-foot text-dim mono" style="font-size: 10px; word-break: break-all;">{{ overview.db_path || '' }}</div>
|
2026-08-30 00:08:14 +08:00
|
|
|
</div>
|
2026-09-21 23:20:59 +08:00
|
|
|
</div>
|
2026-08-29 22:40:53 +08:00
|
|
|
|
2026-09-21 23:20:59 +08:00
|
|
|
<div class="card">
|
|
|
|
|
<div class="card-head">
|
|
|
|
|
<div>
|
|
|
|
|
<div class="card-title">系统信息</div>
|
|
|
|
|
<div class="card-sub">运行版本与资源</div>
|
2026-08-30 00:51:23 +08:00
|
|
|
</div>
|
|
|
|
|
</div>
|
2026-09-21 23:20:59 +08:00
|
|
|
<dl class="kv">
|
|
|
|
|
<div class="kv-row"><dt>Commit</dt><dd class="mono">{{ overview.commit || 'dev' }}</dd></div>
|
|
|
|
|
<div class="kv-row"><dt>版本</dt><dd class="mono">{{ overview.version || '—' }}</dd></div>
|
|
|
|
|
<div class="kv-row"><dt>运行模式</dt><dd>{{ overview.mode || '—' }}</dd></div>
|
|
|
|
|
<div class="kv-row"><dt>数据库路径</dt><dd class="mono text-dim">{{ overview.db_path || '—' }}</dd></div>
|
|
|
|
|
<div class="kv-row"><dt>锁文件</dt><dd class="mono text-dim">{{ overview.lock_path || '—' }}</dd></div>
|
|
|
|
|
<div class="kv-row">
|
|
|
|
|
<dt>内存</dt>
|
|
|
|
|
<dd class="mono text-dim">
|
|
|
|
|
goroutines {{ overview.memory?.goroutines ?? '—' }} · heap {{ formatBytes(overview.memory?.heap_alloc) }}
|
|
|
|
|
</dd>
|
|
|
|
|
</div>
|
|
|
|
|
</dl>
|
|
|
|
|
</div>
|
2026-08-30 00:51:23 +08:00
|
|
|
</main>
|
2026-08-29 21:53:19 +08:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
2026-09-21 23:20:59 +08:00
|
|
|
<script src="/admin/admin-shell.js"></script>
|
2026-08-29 21:53:19 +08:00
|
|
|
<script>
|
2026-09-21 23:20:59 +08:00
|
|
|
const { createApp, ref, onMounted } = Vue;
|
|
|
|
|
const { http, getKey, formatUptime, shortPath, formatBytes, formatStart, mountShell } = window.admin;
|
2026-08-29 21:53:19 +08:00
|
|
|
createApp({
|
|
|
|
|
setup() {
|
|
|
|
|
const overview = ref({});
|
|
|
|
|
|
|
|
|
|
const loadOverview = async () => {
|
|
|
|
|
try { overview.value = (await http.get('/admin/overview')).data; }
|
2026-09-21 23:20:59 +08:00
|
|
|
catch (e) {
|
|
|
|
|
window.admin.toast('err', '加载概览失败: ' + e.message);
|
2026-08-29 22:40:53 +08:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2026-09-21 23:20:59 +08:00
|
|
|
onMounted(() => {
|
|
|
|
|
if (!getKey()) { location.href = '/admin/login'; return; }
|
|
|
|
|
mountShell({ activeNav: 'dashboard', overview: overview.value, voiceCount: overview.value.voice_count, onReload: loadOverview });
|
|
|
|
|
loadOverview();
|
|
|
|
|
});
|
2026-08-29 21:53:19 +08:00
|
|
|
|
2026-09-21 23:20:59 +08:00
|
|
|
return { overview, formatUptime, shortPath, formatBytes, formatStart, loadOverview };
|
2026-08-29 21:53:19 +08:00
|
|
|
},
|
|
|
|
|
}).mount('#app');
|
|
|
|
|
</script>
|
|
|
|
|
</body>
|
|
|
|
|
</html>
|