From 475058ed4b84fafc4d6dbaac5532e3ce30a8a582 Mon Sep 17 00:00:00 2001 From: xuans Date: Fri, 25 Sep 2026 11:40:29 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=A6=96=E9=A1=B5=E5=9F=BA?= =?UTF-8?q?=E6=9C=AC=E4=BF=A1=E6=81=AF=E5=B8=83=E5=B1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 移除首页宣传横幅,新增用户、域名、状态、到期时间和部署服务器概览,并补充布局回归测试。 --- frontend/src/views/Dashboard/Dashboard.css | 116 ++++++++++++------ frontend/src/views/Dashboard/Dashboard.js | 8 +- .../src/views/Dashboard/Dashboard.test.js | 15 ++- frontend/src/views/Dashboard/Dashboard.vue | 78 +++++++++--- 4 files changed, 162 insertions(+), 55 deletions(-) diff --git a/frontend/src/views/Dashboard/Dashboard.css b/frontend/src/views/Dashboard/Dashboard.css index 38855b0..d1bc60b 100644 --- a/frontend/src/views/Dashboard/Dashboard.css +++ b/frontend/src/views/Dashboard/Dashboard.css @@ -65,28 +65,6 @@ h2 { cursor: wait; opacity: 0.6; } -.hero-card { - display: flex; - align-items: center; - justify-content: space-between; - min-height: 250px; - margin: 36px 0 18px; - padding: 36px 42px; - border-radius: 28px; - color: #fff; - background: linear-gradient(120deg, #182b5b, #315aaa); - box-shadow: 0 20px 45px rgba(42, 75, 145, 0.2); -} -.hero-card p { - max-width: 650px; - margin-bottom: 0; - color: #d5e1ff; - line-height: 1.8; -} -.status-label { - font-size: 13px; - font-weight: 800; -} .status-dot { display: inline-block; width: 9px; @@ -99,13 +77,6 @@ h2 { background: #5ee0a0; box-shadow: 0 0 0 5px rgba(94, 224, 160, 0.15); } -.hero-mark { - display: block; - width: 138px; - height: 138px; - object-fit: contain; - filter: drop-shadow(0 16px 24px rgba(0, 0, 0, 0.18)); -} .error-banner, .notice-banner { margin: 18px 0; @@ -122,6 +93,84 @@ h2 { color: #24734b; background: #effbf4; } +.overview-panel { + margin: 28px 0 18px; +} +.overview-summary-grid { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 12px; + margin-bottom: 16px; +} +.overview-summary-card, +.overview-domain-row { + border: 1px solid #e2e8f2; + border-radius: 14px; + background: #fbfcfe; +} +.overview-summary-card { + display: grid; + gap: 7px; + min-width: 0; + padding: 16px; +} +.overview-summary-card > span, +.overview-domain-field > span, +.overview-summary-card small, +.overview-domain-field small { + color: #7a879d; + font-size: 12px; +} +.overview-summary-card strong { + min-width: 0; + overflow-wrap: anywhere; + font-size: 20px; +} +.overview-summary-card small, +.overview-domain-field small { + line-height: 1.45; +} +.overview-status { + display: flex; + align-items: center; + gap: 7px; + white-space: nowrap; + font-size: 17px !important; +} +.overview-status .status-dot { + flex: 0 0 auto; + margin-right: 0; +} +.overview-domain-list { + display: grid; + gap: 10px; +} +.overview-domain-row { + display: grid; + grid-template-columns: minmax(0, 1.3fr) minmax(130px, 0.8fr) minmax(180px, 1fr); + align-items: center; + gap: 18px; + padding: 15px 16px; +} +.overview-domain-main, +.overview-domain-field { + display: grid; + gap: 6px; + min-width: 0; +} +.overview-domain-main { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: 9px; +} +.overview-domain-main strong, +.overview-domain-field strong { + overflow-wrap: anywhere; +} +.overview-domain-field strong { + font-size: 14px; +} .metrics-grid { display: grid; grid-template-columns: repeat(4, 1fr); @@ -562,12 +611,9 @@ code { .topbar-actions button { flex: 1 1 calc(50% - 10px); } - .hero-card { - align-items: flex-start; - padding: 28px; - } - .hero-mark { - display: none; + .overview-summary-grid, + .overview-domain-row { + grid-template-columns: 1fr; } .metrics-grid { grid-template-columns: repeat(2, 1fr); diff --git a/frontend/src/views/Dashboard/Dashboard.js b/frontend/src/views/Dashboard/Dashboard.js index 4e075d3..6862b4c 100644 --- a/frontend/src/views/Dashboard/Dashboard.js +++ b/frontend/src/views/Dashboard/Dashboard.js @@ -11,9 +11,8 @@ function dnsVerificationTimeoutFor(providerID) { } export function useDashboard() { - const scertLogo = "/Scert.png"; - const status = ref(null); + const currentUser = ref(null); const domains = ref([]); const servers = ref([]); const sshKeys = ref([]); @@ -1079,6 +1078,7 @@ export function useDashboard() { try { const [ statusResponse, + authResponse, domainResponse, serverResponse, sshKeyResponse, @@ -1089,6 +1089,7 @@ export function useDashboard() { dnsProviderResponse, ] = await Promise.all([ fetchAdmin("/api/v1/status"), + fetchAdmin("/api/v1/auth/session"), fetchAdmin("/api/v1/domains"), fetchAdmin("/api/v1/servers"), fetchAdmin("/api/v1/ssh-keys"), @@ -1113,6 +1114,7 @@ export function useDashboard() { throw new Error(await responseError(failedResponse, "读取管理数据失败")); } status.value = await statusResponse.json(); + currentUser.value = await authResponse.json(); domains.value = (await domainResponse.json()).items || []; servers.value = (await serverResponse.json()).items || []; sshKeys.value = (await sshKeyResponse.json()).items || []; @@ -1160,8 +1162,8 @@ export function useDashboard() { }); return { - scertLogo, status, + currentUser, domains, servers, sshKeys, diff --git a/frontend/src/views/Dashboard/Dashboard.test.js b/frontend/src/views/Dashboard/Dashboard.test.js index 0902516..794e4ed 100644 --- a/frontend/src/views/Dashboard/Dashboard.test.js +++ b/frontend/src/views/Dashboard/Dashboard.test.js @@ -576,10 +576,23 @@ test("dashboardLayout.keepsActivityListsBoundedAndKeyboardAccessible", async () assert.match(stylesheet, /\.record-list:focus-visible/); }); +test("dashboardLayout.replacesHeroWithBasicInformationSummary", async () => { + const { readFile } = await import("node:fs/promises"); + const template = await readFile(new URL("./Dashboard.vue", import.meta.url), "utf8"); + const stylesheet = await readFile(new URL("./Dashboard.css", import.meta.url), "utf8"); + assert.doesNotMatch(template, /class="hero-card"/); + assert.match(template, /class="panel overview-panel"/); + assert.match(template, /当前用户/); + assert.match(template, /到期时间/); + assert.match(template, /部署服务器/); + assert.match(stylesheet, /\.overview-summary-grid\s*\{[^}]*grid-template-columns: repeat\(3/); + assert.match(stylesheet, /\.overview-domain-row\s*\{[^}]*grid-template-columns:/); +}); + test("dashboardLayout.usesSharedTooltipForUserManagementDescription", async () => { const { readFile } = await import("node:fs/promises"); const template = await readFile(new URL("../UserManagement/UserManagement.vue", import.meta.url), "utf8"); assert.match(template, /import HelpTip from "\.\.\/components\/HelpTip\/HelpTip.vue";/); assert.match(template, /[\s\S]*?<\/HelpTip>/); assert.doesNotMatch(template, /

/); -}); \ No newline at end of file +}); diff --git a/frontend/src/views/Dashboard/Dashboard.vue b/frontend/src/views/Dashboard/Dashboard.vue index 6cc4a46..96e1cfa 100644 --- a/frontend/src/views/Dashboard/Dashboard.vue +++ b/frontend/src/views/Dashboard/Dashboard.vue @@ -9,8 +9,8 @@ import { useDashboard } from "./Dashboard.js"; const dashboard = useDashboard(); const { - scertLogo, status, + currentUser, domains, servers, sshKeys, @@ -153,24 +153,70 @@ const { -

-
- - {{ - status ? "核心服务运行中" : "等待连接核心服务" - }} -

让证书续期和部署变得可追踪

-

- 统一管理单域名、泛域名和 SAN 证书,当前已接入 lego、DNS - 验证、自动续期、远程部署与部署后校验流程。 -

-
- Scert 标志 -
-

{{ error }}

{{ notice }}

+
+
+
+

首页概览

+

基本信息

+
+ 当前登录与托管资源 +
+
+
+ 当前用户 + {{ currentUser?.account || "—" }} + {{ currentUser?.email || "未绑定邮箱" }} +
+
+ 服务状态 + + + {{ status ? "核心服务运行中" : "等待连接核心服务" }} + + 版本 {{ status?.version || "—" }} +
+
+ 托管域名 + {{ domains.length }} 个 + 已配置的证书管理对象 +
+
+
正在读取域名状态……
+
+ 还没有托管域名 + 添加第一个域名,开始管理证书申请和自动续期。 +
+
+
+
+ {{ item.name }} + + {{ displayLabel(domainStatusLabels, item.status) }} + +
+
+ 到期时间 + {{ formatDate(item.expires_at) }} + {{ daysRemaining(item.expires_at) }} +
+
+ 部署服务器 + + {{ + (domainServers[item.id] || []) + .map((server) => server.name) + .join("、") || "未配置" + }} + + {{ item.auto_renew ? "自动续期已开启" : "自动续期已关闭" }} +
+
+
+
+
服务版本{{ status?.version || "—" }}