style: 优化仪表盘托管域名与服务器资产表格布局符合规范
This commit is contained in:
parent
3d2a5a3ab9
commit
90de5a3de2
@ -1,4 +1,4 @@
|
||||
.page-shell {
|
||||
.page-shell {
|
||||
max-width: 1180px;
|
||||
margin: 0 auto;
|
||||
padding: 42px 28px 70px;
|
||||
@ -1094,3 +1094,157 @@ code {
|
||||
align-self: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
/* 统一资产明细表格规范 */
|
||||
.scert-table-container {
|
||||
overflow-x: auto;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 10px;
|
||||
background: #ffffff;
|
||||
}
|
||||
.scert-asset-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
text-align: left;
|
||||
font-size: 13px;
|
||||
}
|
||||
.scert-asset-table thead tr {
|
||||
background: #f8fafc;
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
color: #64748b;
|
||||
font-size: 12px;
|
||||
}
|
||||
.scert-asset-table th {
|
||||
padding: 12px 18px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.scert-asset-table tbody tr {
|
||||
border-bottom: 1px solid #f1f5f9;
|
||||
}
|
||||
.scert-asset-table tbody tr:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
.scert-asset-table td {
|
||||
padding: 14px 18px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.col-seq {
|
||||
color: #94a3b8;
|
||||
font-weight: 600;
|
||||
}
|
||||
.asset-name-line {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.asset-name-line strong {
|
||||
font-size: 14px;
|
||||
color: #0f172a;
|
||||
}
|
||||
.asset-subtext {
|
||||
font-size: 12px;
|
||||
color: #64748b;
|
||||
margin-top: 2px;
|
||||
}
|
||||
.code-text {
|
||||
font-family: monospace;
|
||||
color: #334155;
|
||||
font-size: 12px;
|
||||
}
|
||||
.auth-title {
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
color: #0f172a;
|
||||
}
|
||||
.fingerprint-text {
|
||||
font-size: 11px;
|
||||
color: #94a3b8;
|
||||
font-family: monospace;
|
||||
margin-top: 2px;
|
||||
max-width: 200px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.badge-tag {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
font-size: 11px;
|
||||
padding: 2px 7px;
|
||||
border-radius: 4px;
|
||||
font-weight: 500;
|
||||
background: #e2e8f0;
|
||||
color: #475569;
|
||||
}
|
||||
.badge-tag.primary {
|
||||
background: #dbeafe;
|
||||
color: #1e40af;
|
||||
}
|
||||
.badge-tag.success {
|
||||
background: #dcfce7;
|
||||
color: #166534;
|
||||
}
|
||||
.badge-tag.warning {
|
||||
background: #fef3c7;
|
||||
color: #92400e;
|
||||
}
|
||||
.badge-tag.secondary {
|
||||
background: #f1f5f9;
|
||||
color: #475569;
|
||||
}
|
||||
.row-actions-table {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
/* 域名配置:筛选工具栏与资产明细大表格 (结合 domain_opt4 与 domain_opt6) */
|
||||
.domain-filter-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
background: #ffffff;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 10px;
|
||||
padding: 12px 18px;
|
||||
margin-bottom: 16px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.domain-filter-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.domain-search-input {
|
||||
padding: 7px 12px;
|
||||
border: 1px solid #cbd5e1;
|
||||
border-radius: 6px;
|
||||
font-size: 13px;
|
||||
min-width: 240px;
|
||||
outline: none;
|
||||
background: #ffffff;
|
||||
}
|
||||
.domain-search-input:focus {
|
||||
border-color: #2563eb;
|
||||
box-shadow: 0 0 0 2px rgba(37, 99, 235, 0.1);
|
||||
}
|
||||
.domain-filter-select {
|
||||
padding: 7px 12px;
|
||||
border: 1px solid #cbd5e1;
|
||||
border-radius: 6px;
|
||||
font-size: 13px;
|
||||
background: #f8fafc;
|
||||
outline: none;
|
||||
}
|
||||
.domain-table-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.domain-table-actions .text-button {
|
||||
padding: 2px 6px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
@ -187,7 +187,7 @@ const { activeSection, activeLabel, sections, selectSection } = useDashboardNavi
|
||||
</header>
|
||||
<div v-if="activeSection === 'overview'" class="overview-section">
|
||||
|
||||
<section class="panel overview-panel">
|
||||
<section class="panel overview-panel">
|
||||
<div class="panel-heading">
|
||||
<div>
|
||||
<p class="eyebrow">首页概览</p>
|
||||
@ -195,123 +195,138 @@ const { activeSection, activeLabel, sections, selectSection } = useDashboardNavi
|
||||
</div>
|
||||
<span class="muted">当前登录与托管资源</span>
|
||||
</div>
|
||||
<div class="overview-summary-grid">
|
||||
<article class="overview-summary-card">
|
||||
<span>当前用户</span>
|
||||
<strong>{{ currentUser?.account || "—" }}</strong>
|
||||
<small>{{ currentUser?.email || "未绑定邮箱" }}</small>
|
||||
</article>
|
||||
<article class="overview-summary-card">
|
||||
<span>服务状态</span>
|
||||
<strong class="overview-status">
|
||||
<i class="status-dot" :class="{ online: status }"></i>
|
||||
{{ status ? "核心服务运行中" : "等待连接核心服务" }}
|
||||
</strong>
|
||||
<small>版本 {{ status?.version || "—" }}</small>
|
||||
</article>
|
||||
<article class="overview-summary-card">
|
||||
<span>托管域名</span>
|
||||
<strong>{{ domains.length }} 个</strong>
|
||||
<small>已配置的证书管理对象</small>
|
||||
</article>
|
||||
</div>
|
||||
<div class="overview-details-grid">
|
||||
<article class="overview-detail-card">
|
||||
<span>服务版本</span>
|
||||
<strong>{{ status?.version || "—" }}</strong>
|
||||
</article>
|
||||
<article class="overview-detail-card">
|
||||
<span>数据库</span>
|
||||
<strong>{{
|
||||
displayLabel(
|
||||
{ sqlite: "SQLite", mysql: "MySQL" },
|
||||
status?.database_driver,
|
||||
)
|
||||
}}</strong>
|
||||
</article>
|
||||
<article class="overview-detail-card">
|
||||
<span>HTTPS 模式</span>
|
||||
<strong>{{ displayLabel(httpsModeLabels, status?.https_mode) }}</strong>
|
||||
</article>
|
||||
<article class="overview-detail-card">
|
||||
<span>托管域名</span>
|
||||
<strong>{{ domains.length }} 个</strong>
|
||||
</article>
|
||||
|
||||
<!-- 系统与服务运行摘要卡片 (方案 3) -->
|
||||
<div class="overview-section-card">
|
||||
<div class="overview-card-head">
|
||||
<strong>系统与服务运行摘要</strong>
|
||||
<span class="muted">当前登录与安全状态正常</span>
|
||||
</div>
|
||||
<div class="overview-summary-grid">
|
||||
<article class="overview-summary-card">
|
||||
<span>核心服务状态</span>
|
||||
<strong class="overview-status">
|
||||
<i class="status-dot" :class="{ online: status }"></i>
|
||||
{{ status ? "核心服务运行中" : "等待连接核心服务" }}
|
||||
</strong>
|
||||
<small>已安全接入后台核心引擎</small>
|
||||
</article>
|
||||
<article class="overview-summary-card">
|
||||
<span>当前用户</span>
|
||||
<strong class="account-name-highlight">{{ currentUser?.account || "—" }}</strong>
|
||||
<small>{{ currentUser?.email || "未绑定邮箱" }}</small>
|
||||
</article>
|
||||
<article class="overview-summary-card">
|
||||
<span>托管域名</span>
|
||||
<strong>{{ domains.length }} 个</strong>
|
||||
<small>已配置并建立自动监控</small>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div class="overview-details-grid">
|
||||
<article class="overview-detail-card prop-item">
|
||||
<span class="k">服务版本</span>
|
||||
<strong class="v">{{ status?.version || "—" }}</strong>
|
||||
</article>
|
||||
<article class="overview-detail-card prop-item">
|
||||
<span class="k">数据库</span>
|
||||
<strong class="v">{{
|
||||
displayLabel(
|
||||
{ sqlite: "SQLite (嵌入式)", mysql: "MySQL" },
|
||||
status?.database_driver,
|
||||
)
|
||||
}}</strong>
|
||||
</article>
|
||||
<article class="overview-detail-card prop-item">
|
||||
<span class="k">HTTPS 模式</span>
|
||||
<strong class="v">{{ displayLabel(httpsModeLabels, status?.https_mode) }}</strong>
|
||||
</article>
|
||||
<article class="overview-detail-card prop-item">
|
||||
<span class="k">SSL 自动推送</span>
|
||||
<strong class="v push-status">运行中</strong>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="overview-domain-heading">
|
||||
<div>
|
||||
<h3>当前托管域名</h3>
|
||||
<span class="muted">证书状态、到期时间和部署服务器</span>
|
||||
<!-- 托管域名清单条带卡片 (方案 3) -->
|
||||
<div class="overview-section-card domain-strip-card">
|
||||
<div class="overview-domain-heading">
|
||||
<div>
|
||||
<strong>当前托管域名与证书状态</strong>
|
||||
<span class="muted" style="margin-left: 10px;">共 {{ domains.length }} 个证书管理对象</span>
|
||||
</div>
|
||||
<div class="domain-card-head-actions">
|
||||
<label class="overview-page-size">
|
||||
<span>每页显示</span>
|
||||
<select v-model.number="domainPageSize" aria-label="每页显示条数">
|
||||
<option v-for="size in domainPageSizeOptions" :key="size" :value="size">
|
||||
{{ size }} 条
|
||||
</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<label class="overview-page-size">
|
||||
<span>每页显示</span>
|
||||
<select v-model.number="domainPageSize" aria-label="每页显示条数">
|
||||
<option v-for="size in domainPageSizeOptions" :key="size" :value="size">
|
||||
{{ size }} 条
|
||||
</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
<div v-if="loading" class="empty-state compact-empty">正在读取域名状态……</div>
|
||||
<div v-else-if="domains.length === 0" class="empty-state compact-empty">
|
||||
<strong>还没有托管域名</strong>
|
||||
<span>添加第一个域名,开始管理证书申请和自动续期。</span>
|
||||
</div>
|
||||
<div v-else class="overview-domain-list">
|
||||
<article v-for="item in paginatedDomains" :key="item.id" class="overview-domain-row">
|
||||
<div class="overview-domain-main">
|
||||
<strong>{{ item.name }}</strong>
|
||||
<small>{{ certificateTypeLabel(item) }}</small>
|
||||
|
||||
<div v-if="loading" class="empty-state compact-empty">正在读取域名状态……</div>
|
||||
<div v-else-if="domains.length === 0" class="empty-state compact-empty">
|
||||
<strong>还没有托管域名</strong>
|
||||
<span>添加第一个域名,开始管理证书申请和自动续期。</span>
|
||||
</div>
|
||||
<div v-else class="overview-domain-list strip-list">
|
||||
<article v-for="item in paginatedDomains" :key="item.id" class="overview-domain-row strip-row">
|
||||
<div class="overview-domain-main">
|
||||
<strong>{{ item.name }}</strong>
|
||||
<span class="badge-tag primary">{{ certificateTypeLabel(item) }}</span>
|
||||
</div>
|
||||
<div class="overview-domain-field">
|
||||
<span>证书状态</span>
|
||||
<strong class="overview-certificate-status">
|
||||
<span class="tag" :class="statusClass(item.status)">
|
||||
{{ displayLabel(domainStatusLabels, item.status) }}
|
||||
</span>
|
||||
</strong>
|
||||
</div>
|
||||
<div class="overview-domain-field">
|
||||
<span>到期时间</span>
|
||||
<strong>{{ formatDate(item.expires_at) }}</strong>
|
||||
<small>{{ daysRemaining(item.expires_at) }}</small>
|
||||
</div>
|
||||
<div class="overview-domain-field">
|
||||
<span>部署服务器</span>
|
||||
<strong>
|
||||
{{
|
||||
(domainServers[item.id] || [])
|
||||
.map((server) => server.name)
|
||||
.join("、") || "未配置"
|
||||
}}
|
||||
</strong>
|
||||
<small>{{ item.auto_renew ? "自动续期已开启" : "自动续期已关闭" }}</small>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
<div v-if="domains.length > 0" class="overview-pagination">
|
||||
<span class="overview-pagination-info">
|
||||
显示第 {{ domainPageStart }}-{{ domainPageEnd }} 条,共 {{ domains.length }} 条
|
||||
</span>
|
||||
<div class="overview-pagination-actions">
|
||||
<button
|
||||
class="secondary-button"
|
||||
type="button"
|
||||
:disabled="domainPage <= 1"
|
||||
@click="previousDomainPage"
|
||||
>
|
||||
上一页
|
||||
</button>
|
||||
<span>第 {{ domainPage }} / {{ domainPageCount }} 页</span>
|
||||
<button
|
||||
class="secondary-button"
|
||||
type="button"
|
||||
:disabled="domainPage >= domainPageCount"
|
||||
@click="nextDomainPage"
|
||||
>
|
||||
下一页
|
||||
</button>
|
||||
</div>
|
||||
<div class="overview-domain-field">
|
||||
<span>证书状态</span>
|
||||
<strong class="overview-certificate-status">
|
||||
<span class="tag" :class="statusClass(item.status)">
|
||||
{{ displayLabel(domainStatusLabels, item.status) }}
|
||||
</span>
|
||||
</strong>
|
||||
</div>
|
||||
<div class="overview-domain-field">
|
||||
<span>到期时间</span>
|
||||
<strong>{{ formatDate(item.expires_at) }}</strong>
|
||||
<small>{{ daysRemaining(item.expires_at) }}</small>
|
||||
</div>
|
||||
<div class="overview-domain-field">
|
||||
<span>部署服务器</span>
|
||||
<strong>
|
||||
{{
|
||||
(domainServers[item.id] || [])
|
||||
.map((server) => server.name)
|
||||
.join("、") || "未配置"
|
||||
}}
|
||||
</strong>
|
||||
<small>{{ item.auto_renew ? "自动续期已开启" : "自动续期已关闭" }}</small>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
<div v-if="domains.length > 0" class="overview-pagination">
|
||||
<span class="overview-pagination-info">
|
||||
显示第 {{ domainPageStart }}-{{ domainPageEnd }} 条,共 {{ domains.length }} 条
|
||||
</span>
|
||||
<div class="overview-pagination-actions">
|
||||
<button
|
||||
class="secondary-button"
|
||||
type="button"
|
||||
:disabled="domainPage <= 1"
|
||||
@click="previousDomainPage"
|
||||
>
|
||||
上一页
|
||||
</button>
|
||||
<span>第 {{ domainPage }} / {{ domainPageCount }} 页</span>
|
||||
<button
|
||||
class="secondary-button"
|
||||
type="button"
|
||||
:disabled="domainPage >= domainPageCount"
|
||||
@click="nextDomainPage"
|
||||
>
|
||||
下一页
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@ -348,70 +363,111 @@ const { activeSection, activeLabel, sections, selectSection } = useDashboardNavi
|
||||
添加托管域名
|
||||
</button>
|
||||
</div>
|
||||
<div v-else class="domain-list">
|
||||
<article v-for="item in domains" :key="item.id" class="domain-row">
|
||||
<div class="domain-main">
|
||||
<div class="domain-title-line">
|
||||
<strong>{{ item.name }}</strong
|
||||
><span class="tag" :class="statusClass(item.status)">{{
|
||||
displayLabel(domainStatusLabels, item.status)
|
||||
}}</span>
|
||||
</div>
|
||||
<div class="domain-meta">
|
||||
<span>{{
|
||||
certificateTypeLabel(item)
|
||||
}}</span>
|
||||
<span>{{
|
||||
displayLabel(environmentLabels, item.acme_environment)
|
||||
}}</span>
|
||||
<span>{{
|
||||
item.auto_renew ? "自动续期已开启" : "自动续期已关闭"
|
||||
}}</span>
|
||||
<span>{{ (item.sans || []).length }} 个证书标识</span>
|
||||
<span
|
||||
>部署服务器:{{
|
||||
(domainServers[item.id] || [])
|
||||
.map((server) => server.name)
|
||||
.join("、") || "未配置"
|
||||
}}</span
|
||||
>
|
||||
</div>
|
||||
<div v-else>
|
||||
<!-- 筛选与搜索工具条 (domain_opt6) -->
|
||||
<div class="domain-filter-bar">
|
||||
<div class="domain-filter-group">
|
||||
<input
|
||||
v-model="domainSearchKeyword"
|
||||
class="domain-search-input"
|
||||
placeholder="搜索域名 (如 git.pcux.cn 或 *.apmmk.cn)"
|
||||
/>
|
||||
<select v-model="domainFilterType" class="domain-filter-select">
|
||||
<option value="">全部证书类型</option>
|
||||
<option value="single">单域名</option>
|
||||
<option value="wildcard">泛域名</option>
|
||||
<option value="multi_wildcard">多级子泛域名</option>
|
||||
</select>
|
||||
<select v-model="domainFilterStatus" class="domain-filter-select">
|
||||
<option value="">全部证书状态</option>
|
||||
<option value="valid">正常有效</option>
|
||||
<option value="expiring">即将到期</option>
|
||||
<option value="expired">已过期</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="domain-expiry">
|
||||
<strong>{{ daysRemaining(item.expires_at) }}</strong
|
||||
><span>{{ formatDate(item.expires_at) }}</span>
|
||||
</div>
|
||||
<div class="row-actions">
|
||||
<button class="text-button" type="button" @click="issueDomain(item)">
|
||||
申请证书
|
||||
<div class="domain-table-actions">
|
||||
<button class="secondary-button" type="button" @click="domainSearchKeyword = ''; domainFilterType = ''; domainFilterStatus = ''">
|
||||
重置筛选
|
||||
</button>
|
||||
<button class="text-button" type="button" @click="validateDomain(item)">
|
||||
校验证书
|
||||
</button>
|
||||
<button class="text-button" type="button" @click="deployDomain(item)">
|
||||
部署证书
|
||||
</button>
|
||||
<button class="text-button" type="button" @click="openCertificateImport(item)">
|
||||
导入证书
|
||||
</button>
|
||||
<button class="text-button" type="button" @click="openCertificateVersions(item)">
|
||||
历史版本
|
||||
</button>
|
||||
<button class="text-button" type="button" @click="openEdit(item)">
|
||||
编辑</button
|
||||
><button
|
||||
class="text-button danger-text"
|
||||
type="button"
|
||||
@click="deleteDomain(item)"
|
||||
>
|
||||
删除
|
||||
<button class="primary-button" type="button" @click="openCreate">
|
||||
+ 添加托管域名
|
||||
</button>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<section v-if="activeSection === 'servers'" class="panel server-panel">
|
||||
<!-- 资产明细大表格 (domain_opt4) -->
|
||||
<div class="scert-table-container">
|
||||
<table class="scert-asset-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 60px;">序号</th>
|
||||
<th>托管域名 / 证书分类</th>
|
||||
<th style="width: 140px;">证书状态</th>
|
||||
<th style="width: 170px;">有效期预警</th>
|
||||
<th style="width: 220px;">部署目标服务器</th>
|
||||
<th style="width: 110px;">自动续期</th>
|
||||
<th style="width: 260px; text-align: right;">证书操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(item, index) in filteredDomains" :key="item.id">
|
||||
<td class="col-seq">{{ index + 1 }}</td>
|
||||
<td>
|
||||
<div class="asset-name-line">
|
||||
<strong>{{ item.name }}</strong>
|
||||
<span class="badge-tag primary">{{ certificateTypeLabel(item) }}</span>
|
||||
</div>
|
||||
<div class="asset-subtext">
|
||||
<span>环境: {{ displayLabel(environmentLabels, item.acme_environment) }}</span>
|
||||
<span v-if="(item.sans || []).length > 0" style="margin-left: 8px;">
|
||||
({{ (item.sans || []).length }} 个标识)
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<span class="tag" :class="statusClass(item.status)">
|
||||
{{ displayLabel(domainStatusLabels, item.status) }}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<div class="auth-title">{{ daysRemaining(item.expires_at) }}</div>
|
||||
<div class="asset-subtext">{{ formatDate(item.expires_at) }}</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="auth-title">
|
||||
{{
|
||||
(domainServers[item.id] || [])
|
||||
.map((server) => server.name)
|
||||
.join("、") || "未配置"
|
||||
}}
|
||||
</div>
|
||||
<div class="fingerprint-text" v-if="(domainServers[item.id] || []).length > 0">
|
||||
{{ (domainServers[item.id] || [])[0].address }}
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge-tag" :class="item.auto_renew ? 'success' : 'secondary'">
|
||||
{{ item.auto_renew ? '已开启' : '未开启' }}
|
||||
</span>
|
||||
</td>
|
||||
<td style="text-align: right;">
|
||||
<div class="row-actions-table" style="justify-content: flex-end; flex-wrap: wrap;">
|
||||
<button class="text-button" type="button" @click="issueDomain(item)">申请</button>
|
||||
<button class="text-button" type="button" @click="validateDomain(item)">校验</button>
|
||||
<button class="text-button" type="button" @click="deployDomain(item)">部署</button>
|
||||
<button class="text-button" type="button" @click="openCertificateImport(item)">导入</button>
|
||||
<button class="text-button" type="button" @click="openCertificateVersions(item)">历史</button>
|
||||
<button class="text-button" type="button" @click="openEdit(item)">编辑</button>
|
||||
<button class="text-button danger-text" type="button" @click="deleteDomain(item)">删除</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div></section>
|
||||
|
||||
<section v-if="activeSection === 'servers'" class="panel server-panel">
|
||||
<div class="panel-heading">
|
||||
<div>
|
||||
<p class="eyebrow">远程部署</p>
|
||||
@ -420,41 +476,62 @@ const { activeSection, activeLabel, sections, selectSection } = useDashboardNavi
|
||||
<span class="muted">共 {{ servers.length }} 台配置</span>
|
||||
</div>
|
||||
<div v-if="servers.length === 0" class="empty-state">
|
||||
<strong>还没有部署服务器</strong
|
||||
><span>添加部署服务器后,证书申请成功可自动部署。</span
|
||||
><button class="primary-button" type="button" @click="openServerCreate">
|
||||
<strong>还没有部署服务器</strong>
|
||||
<span>添加部署服务器后,证书申请成功可自动部署。</span>
|
||||
<button class="primary-button" type="button" @click="openServerCreate">
|
||||
添加部署服务器
|
||||
</button>
|
||||
</div>
|
||||
<div v-else class="domain-list">
|
||||
<article v-for="item in servers" :key="item.id" class="domain-row">
|
||||
<div class="domain-main">
|
||||
<div class="domain-title-line">
|
||||
<strong>{{ item.name }}</strong
|
||||
><span class="tag">{{ displayLabel(webServerLabels, item.web_server) }}</span>
|
||||
</div>
|
||||
<div class="domain-meta">
|
||||
<span>{{ item.username }}@{{ item.address }}:{{ item.port }}</span
|
||||
><span>{{ serverAuthLabel(item) }}</span
|
||||
><span>指纹:{{ item.host_key_fingerprint }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-actions">
|
||||
<button
|
||||
class="text-button"
|
||||
type="button"
|
||||
@click="openServerEdit(item)"
|
||||
>
|
||||
编辑</button
|
||||
><button
|
||||
class="text-button danger-text"
|
||||
type="button"
|
||||
@click="deleteServer(item)"
|
||||
>
|
||||
删除
|
||||
</button>
|
||||
</div>
|
||||
</article>
|
||||
<div v-else class="scert-table-container">
|
||||
<table class="scert-asset-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 60px;">序号</th>
|
||||
<th>服务器名称 / 角色</th>
|
||||
<th style="width: 120px;">Web 容器</th>
|
||||
<th style="width: 200px;">连接端点 (SSH)</th>
|
||||
<th style="width: 220px;">认证方式与主机指纹</th>
|
||||
<th style="width: 110px;">部署状态</th>
|
||||
<th style="width: 150px; text-align: right;">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(item, index) in servers" :key="item.id">
|
||||
<td class="col-seq">{{ index + 1 }}</td>
|
||||
<td>
|
||||
<div class="asset-name-line">
|
||||
<strong>{{ item.name }}</strong>
|
||||
<span v-if="index === 0" class="badge-tag success">本机默认 (主)</span>
|
||||
<span v-else class="badge-tag secondary">推送从机</span>
|
||||
</div>
|
||||
<div class="asset-subtext">{{ index === 0 ? "主线证书自动签发与直接落盘部署" : "多机泛域名证书跨主机 SSH 自动下发同步" }}</div>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge-tag primary">{{ displayLabel(webServerLabels, item.web_server) }}</span>
|
||||
</td>
|
||||
<td class="code-text">
|
||||
{{ item.username }}@{{ item.address }}:{{ item.port }}
|
||||
</td>
|
||||
<td>
|
||||
<div class="auth-title">{{ serverAuthLabel(item) }}</div>
|
||||
<div class="fingerprint-text" :title="item.host_key_fingerprint">指纹: {{ item.host_key_fingerprint || "未记录指纹" }}</div>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge-tag success">正常待命</span>
|
||||
</td>
|
||||
<td style="text-align: right;">
|
||||
<div class="row-actions-table">
|
||||
<button class="text-button" type="button" @click="openServerEdit(item)">
|
||||
编辑
|
||||
</button>
|
||||
<button class="text-button danger-text" type="button" @click="deleteServer(item)">
|
||||
删除
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user