mirror of
https://github.com/dqzboy/Docker-Proxy.git
synced 2026-01-12 16:25:42 +08:00
4968 lines
163 KiB
HTML
4968 lines
163 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Docker 镜像代理加速 - 管理面板</title>
|
||
<link rel="icon" href="https://cdn.jsdelivr.net/gh/dqzboy/Blog-Image/BlogCourse/docker-proxy.png" type="image/png">
|
||
<!-- 引入前端样式表 -->
|
||
<link rel="stylesheet" href="style.css">
|
||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||
<!-- 引入Bootstrap CSS和JS -->
|
||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css">
|
||
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.6/dist/umd/popper.min.js"></script>
|
||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"></script>
|
||
|
||
<!-- 引入 jQuery (Editor.md 需要) -->
|
||
<script src="https://cdn.bootcss.com/jquery/1.11.3/jquery.min.js"></script>
|
||
|
||
<!-- 引入 Markdown 编辑器 -->
|
||
<script src="https://cdnjs.cloudflare.com/ajax/libs/dompurify/3.0.6/purify.min.js"></script>
|
||
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
||
|
||
<!-- 引入 Editor.md -->
|
||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.0/codemirror.min.css">
|
||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/editor.md@1.5.0/css/editormd.min.css">
|
||
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.0/codemirror.min.js"></script>
|
||
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.0/addon/mode/overlay.min.js"></script>
|
||
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.0/mode/markdown/markdown.min.js"></script>
|
||
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.0/mode/gfm/gfm.min.js"></script>
|
||
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/4.0.2/marked.min.js"></script>
|
||
<script src="https://cdn.jsdelivr.net/npm/editor.md@1.5.0/editormd.min.js"></script>
|
||
|
||
<!-- 自定义样式 -->
|
||
<link rel="stylesheet" href="css/admin.css">
|
||
<style>
|
||
/* 管理面板特定样式 */
|
||
.admin-container {
|
||
display: flex;
|
||
min-height: 100vh;
|
||
background-color: var(--background-color);
|
||
}
|
||
|
||
.sidebar {
|
||
width: 280px;
|
||
background: linear-gradient(180deg, var(--container-bg) 0%, #f8fafc 100%);
|
||
box-shadow: var(--shadow-lg);
|
||
padding: 1.5rem 0;
|
||
z-index: 10;
|
||
transition: all 0.3s ease;
|
||
border-right: 1px solid var(--border-light, #e5e7eb);
|
||
}
|
||
|
||
.sidebar-header {
|
||
text-align: center;
|
||
margin-bottom: 1rem;
|
||
padding: 0 1rem;
|
||
}
|
||
|
||
.sidebar-header h2 {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 0.5rem;
|
||
font-size: 1.25rem;
|
||
font-weight: 700;
|
||
color: var(--primary-color);
|
||
margin: 0;
|
||
}
|
||
|
||
.sidebar-header h2 i {
|
||
font-size: 1.1rem;
|
||
}
|
||
|
||
/* 文档管理新建文档徽章 */
|
||
.new-badge {
|
||
display: inline-block;
|
||
padding: 2px 8px;
|
||
background: linear-gradient(135deg, #10b981, #34d399);
|
||
color: white;
|
||
border-radius: 12px;
|
||
font-size: 0.75rem;
|
||
font-weight: bold;
|
||
box-shadow: 0 2px 5px rgba(16, 185, 129, 0.3);
|
||
}
|
||
|
||
@keyframes pulse {
|
||
0% { opacity: 1; }
|
||
50% { opacity: 0.7; }
|
||
100% { opacity: 1; }
|
||
}
|
||
|
||
/* 用户信息部分样式 */
|
||
.user-profile {
|
||
padding: 1.25rem 1.5rem;
|
||
margin: 0 1rem 1.5rem;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
position: relative;
|
||
background: linear-gradient(135deg, rgba(61, 124, 244, 0.08) 0%, rgba(99, 102, 241, 0.05) 100%);
|
||
border-radius: var(--radius-lg);
|
||
border: 1px solid rgba(61, 124, 244, 0.1);
|
||
}
|
||
|
||
.user-avatar {
|
||
width: 75px;
|
||
height: 75px;
|
||
border-radius: 50%;
|
||
background: linear-gradient(135deg, var(--primary-color), #6366f1);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 2rem;
|
||
color: white;
|
||
margin-bottom: 1rem;
|
||
box-shadow: 0 4px 15px rgba(61, 124, 244, 0.3);
|
||
border: 3px solid white;
|
||
}
|
||
|
||
.user-info {
|
||
text-align: center;
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
|
||
.user-name {
|
||
font-weight: 700;
|
||
font-size: 1.15rem;
|
||
color: var(--text-primary);
|
||
margin-bottom: 0.25rem;
|
||
}
|
||
|
||
.user-role {
|
||
color: var(--text-secondary);
|
||
font-size: 0.85rem;
|
||
margin-bottom: 0.5rem;
|
||
background: rgba(61, 124, 244, 0.1);
|
||
padding: 0.25rem 0.75rem;
|
||
border-radius: 20px;
|
||
display: inline-block;
|
||
}
|
||
|
||
.user-actions {
|
||
display: flex;
|
||
gap: 0.75rem;
|
||
margin-top: 0.75rem;
|
||
}
|
||
|
||
.user-action-btn {
|
||
padding: 0.5rem 1rem;
|
||
font-size: 0.85rem;
|
||
border-radius: var(--radius-md);
|
||
background-color: rgba(61, 124, 244, 0.1);
|
||
color: var(--primary-color);
|
||
cursor: pointer;
|
||
transition: all var(--transition-fast);
|
||
font-weight: 500;
|
||
}
|
||
|
||
.user-action-btn:hover {
|
||
background-color: var(--primary-color);
|
||
color: white;
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 4px 10px rgba(61, 124, 244, 0.25);
|
||
}
|
||
|
||
.user-action-btn.logout {
|
||
background-color: rgba(239, 68, 68, 0.1);
|
||
color: var(--danger-color);
|
||
}
|
||
|
||
.user-action-btn.logout:hover {
|
||
background-color: var(--danger-color);
|
||
color: white;
|
||
box-shadow: 0 4px 10px rgba(239, 68, 68, 0.25);
|
||
}
|
||
|
||
/* 仪表盘卡片样式 */
|
||
.dashboard-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||
gap: 1.5rem;
|
||
margin-bottom: 2rem;
|
||
}
|
||
|
||
.dashboard-card {
|
||
background-color: var(--container-bg);
|
||
border-radius: var(--radius-lg);
|
||
box-shadow: var(--shadow-md);
|
||
padding: 1.75rem;
|
||
transition: all var(--transition-normal);
|
||
border: 1px solid var(--border-light);
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.dashboard-card:hover {
|
||
transform: translateY(-6px);
|
||
box-shadow: 0 12px 25px rgba(0, 0, 0, 0.1);
|
||
border-color: var(--primary-light);
|
||
}
|
||
|
||
.dashboard-card::before {
|
||
content: '';
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 5px;
|
||
height: 100%;
|
||
background: linear-gradient(180deg, var(--primary-color), #6366f1);
|
||
border-radius: 3px 0 0 3px;
|
||
}
|
||
|
||
.dashboard-card::after {
|
||
content: '';
|
||
position: absolute;
|
||
top: 0;
|
||
right: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background: linear-gradient(135deg, transparent 60%, rgba(61, 124, 244, 0.03) 100%);
|
||
pointer-events: none;
|
||
}
|
||
|
||
.card-icon {
|
||
width: 55px;
|
||
height: 55px;
|
||
border-radius: 14px;
|
||
background: linear-gradient(135deg, rgba(61, 124, 244, 0.15), rgba(99, 102, 241, 0.1));
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-bottom: 1.25rem;
|
||
color: var(--primary-color);
|
||
font-size: 1.5rem;
|
||
position: relative;
|
||
z-index: 1;
|
||
}
|
||
|
||
.card-title {
|
||
font-size: 1.15rem;
|
||
font-weight: 600;
|
||
margin-bottom: 0.5rem;
|
||
color: var(--text-primary);
|
||
position: relative;
|
||
z-index: 1;
|
||
}
|
||
|
||
.card-value {
|
||
font-size: 1.8rem;
|
||
font-weight: 700;
|
||
color: var(--text-primary);
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
|
||
.card-description {
|
||
color: var(--text-secondary);
|
||
font-size: 0.9rem;
|
||
margin-bottom: 1rem;
|
||
}
|
||
|
||
.card-footer {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
border-top: 1px solid var(--border-light);
|
||
padding-top: 1rem;
|
||
margin-top: 0.5rem;
|
||
}
|
||
|
||
.trend {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.3rem;
|
||
font-size: 0.9rem;
|
||
}
|
||
|
||
.trend.up {
|
||
color: var(--success-color);
|
||
}
|
||
|
||
.trend.down {
|
||
color: var(--danger-color);
|
||
}
|
||
|
||
.card-action {
|
||
color: var(--primary-color);
|
||
font-size: 0.9rem;
|
||
font-weight: 500;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.welcome-banner {
|
||
background: linear-gradient(135deg, var(--primary-color) 0%, #6366f1 50%, var(--primary-dark) 100%);
|
||
border-radius: var(--radius-lg);
|
||
padding: 2.5rem;
|
||
margin-bottom: 2rem;
|
||
color: white;
|
||
position: relative;
|
||
overflow: hidden;
|
||
box-shadow: 0 10px 40px rgba(61, 124, 244, 0.3);
|
||
}
|
||
|
||
.welcome-content {
|
||
position: relative;
|
||
z-index: 1;
|
||
}
|
||
|
||
.welcome-title {
|
||
font-size: 2rem;
|
||
margin-bottom: 0.75rem;
|
||
font-weight: 700;
|
||
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
.welcome-title span {
|
||
background: linear-gradient(90deg, #fff, #e0e7ff);
|
||
-webkit-background-clip: text;
|
||
-webkit-text-fill-color: transparent;
|
||
background-clip: text;
|
||
}
|
||
|
||
.welcome-subtitle {
|
||
font-size: 1.1rem;
|
||
margin-bottom: 1.5rem;
|
||
opacity: 0.95;
|
||
font-weight: 400;
|
||
}
|
||
|
||
.welcome-action {
|
||
background-color: rgba(255, 255, 255, 0.2);
|
||
backdrop-filter: blur(10px);
|
||
color: white;
|
||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||
padding: 0.85rem 1.75rem;
|
||
border-radius: var(--radius-md);
|
||
font-weight: 500;
|
||
cursor: pointer;
|
||
transition: all var(--transition-fast);
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
font-size: 0.95rem;
|
||
}
|
||
|
||
.welcome-action:hover {
|
||
background-color: rgba(255, 255, 255, 0.35);
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
|
||
}
|
||
|
||
.welcome-action i {
|
||
transition: transform 0.3s ease;
|
||
}
|
||
|
||
.welcome-action:hover i {
|
||
transform: rotate(180deg);
|
||
}
|
||
|
||
.welcome-banner::after {
|
||
content: '';
|
||
position: absolute;
|
||
top: -60%;
|
||
right: -15%;
|
||
width: 350px;
|
||
height: 350px;
|
||
background: rgba(255, 255, 255, 0.08);
|
||
border-radius: 50%;
|
||
animation: pulse-slow 4s ease-in-out infinite;
|
||
}
|
||
|
||
.welcome-banner::before {
|
||
content: '';
|
||
position: absolute;
|
||
bottom: -40%;
|
||
left: -8%;
|
||
width: 250px;
|
||
height: 250px;
|
||
background: rgba(255, 255, 255, 0.06);
|
||
border-radius: 50%;
|
||
animation: pulse-slow 4s ease-in-out infinite 1s;
|
||
}
|
||
|
||
@keyframes pulse-slow {
|
||
0%, 100% { transform: scale(1); opacity: 0.8; }
|
||
50% { transform: scale(1.05); opacity: 1; }
|
||
}
|
||
|
||
/* Docker 状态指示器 */
|
||
.docker-status {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
background: rgba(255, 255, 255, 0.15);
|
||
backdrop-filter: blur(10px);
|
||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||
padding: 0.5rem 1rem;
|
||
border-radius: var(--radius-md);
|
||
font-size: 0.9rem;
|
||
font-weight: 500;
|
||
transition: all var(--transition-fast);
|
||
}
|
||
|
||
.docker-status.docker-running {
|
||
background: rgba(16, 185, 129, 0.2);
|
||
border-color: rgba(16, 185, 129, 0.4);
|
||
}
|
||
|
||
.docker-status.docker-stopped {
|
||
background: rgba(239, 68, 68, 0.2);
|
||
border-color: rgba(239, 68, 68, 0.4);
|
||
}
|
||
|
||
/* 用户中心样式 */
|
||
.user-center-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 2rem;
|
||
}
|
||
|
||
.user-center-title {
|
||
font-size: 1.8rem;
|
||
font-weight: 600;
|
||
color: var(--text-primary);
|
||
}
|
||
|
||
.user-center-subtitle {
|
||
color: var(--text-secondary);
|
||
margin-top: 0.5rem;
|
||
}
|
||
|
||
.user-center-card {
|
||
background-color: var(--container-bg);
|
||
border-radius: var(--radius-lg);
|
||
box-shadow: var(--shadow-md);
|
||
padding: 2rem;
|
||
margin-bottom: 2rem;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.user-center-card:hover {
|
||
transform: translateY(-5px);
|
||
box-shadow: var(--shadow-lg);
|
||
}
|
||
|
||
.user-center-section {
|
||
margin-bottom: 1rem;
|
||
}
|
||
|
||
.user-center-section-title {
|
||
font-size: 1.3rem;
|
||
font-weight: 600;
|
||
margin-bottom: 1.5rem;
|
||
color: var(--text-primary);
|
||
position: relative;
|
||
padding-bottom: 0.75rem;
|
||
}
|
||
|
||
.user-center-section-title::after {
|
||
content: '';
|
||
position: absolute;
|
||
bottom: 0;
|
||
left: 0;
|
||
width: 60px;
|
||
height: 2px;
|
||
background: var(--primary-color);
|
||
border-radius: 2px;
|
||
}
|
||
|
||
.user-stats {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
||
gap: 1.5rem;
|
||
margin-bottom: 1rem;
|
||
}
|
||
|
||
.stat-card {
|
||
background-color: var(--container-bg);
|
||
border-radius: var(--radius-md);
|
||
box-shadow: var(--shadow-sm);
|
||
padding: 1.5rem;
|
||
border: 1px solid var(--border-light);
|
||
text-align: center;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.stat-card:hover {
|
||
border-color: var(--primary-color);
|
||
transform: translateY(-3px);
|
||
box-shadow: var(--shadow-md);
|
||
}
|
||
|
||
.stat-icon {
|
||
font-size: 1.8rem;
|
||
color: var(--primary-color);
|
||
margin-bottom: 0.75rem;
|
||
}
|
||
|
||
.stat-value {
|
||
font-size: 2rem;
|
||
font-weight: 700;
|
||
color: var(--primary-color);
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
|
||
.stat-label {
|
||
color: var(--text-secondary);
|
||
font-size: 0.9rem;
|
||
}
|
||
|
||
/* 新增用户个人资料卡片样式 */
|
||
.user-profile-card {
|
||
display: flex;
|
||
align-items: center;
|
||
background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-dark) 100%);
|
||
color: white;
|
||
border-radius: var(--radius-lg);
|
||
padding: 2rem;
|
||
margin-bottom: 2rem;
|
||
box-shadow: var(--shadow-md);
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.user-profile-card::before {
|
||
content: '';
|
||
position: absolute;
|
||
top: -50px;
|
||
right: -50px;
|
||
width: 200px;
|
||
height: 200px;
|
||
border-radius: 50%;
|
||
background: rgba(255, 255, 255, 0.1);
|
||
z-index: 0;
|
||
}
|
||
|
||
.user-profile-card::after {
|
||
content: '';
|
||
position: absolute;
|
||
bottom: -60px;
|
||
left: 30%;
|
||
width: 150px;
|
||
height: 150px;
|
||
border-radius: 50%;
|
||
background: rgba(255, 255, 255, 0.1);
|
||
z-index: 0;
|
||
}
|
||
|
||
.user-profile-avatar {
|
||
width: 80px;
|
||
height: 80px;
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
background: rgba(255, 255, 255, 0.2);
|
||
font-size: 2.5rem;
|
||
margin-right: 1.5rem;
|
||
z-index: 1;
|
||
}
|
||
|
||
.user-profile-info {
|
||
flex: 1;
|
||
z-index: 1;
|
||
}
|
||
|
||
.user-profile-name {
|
||
font-size: 1.8rem;
|
||
font-weight: 600;
|
||
margin: 0 0 0.3rem 0;
|
||
}
|
||
|
||
.user-profile-role {
|
||
font-size: 1rem;
|
||
opacity: 0.8;
|
||
margin: 0 0 1rem 0;
|
||
}
|
||
|
||
.user-profile-badges {
|
||
display: flex;
|
||
gap: 0.75rem;
|
||
}
|
||
|
||
.user-badge {
|
||
padding: 0.3rem 0.75rem;
|
||
border-radius: 20px;
|
||
font-size: 0.85rem;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.4rem;
|
||
}
|
||
|
||
.user-badge.admin {
|
||
background-color: rgba(255, 193, 7, 0.3);
|
||
}
|
||
|
||
.user-badge.active {
|
||
background-color: rgba(40, 167, 69, 0.3);
|
||
}
|
||
|
||
.user-profile-actions {
|
||
z-index: 1;
|
||
}
|
||
|
||
.btn-outline {
|
||
background-color: transparent;
|
||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||
color: white;
|
||
padding: 0.6rem 1rem;
|
||
border-radius: var(--radius-md);
|
||
cursor: pointer;
|
||
transition: all 0.2s ease;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
}
|
||
|
||
.btn-outline:hover {
|
||
background-color: rgba(255, 255, 255, 0.1);
|
||
border-color: rgba(255, 255, 255, 0.5);
|
||
}
|
||
|
||
.btn-danger-outline {
|
||
background-color: transparent;
|
||
border: 2px solid var(--danger-color);
|
||
color: var(--danger-color);
|
||
padding: 0.6rem 1.2rem;
|
||
border-radius: var(--radius-md);
|
||
cursor: pointer;
|
||
transition: all 0.2s ease;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.btn-danger-outline:hover {
|
||
background-color: var(--danger-color);
|
||
color: white;
|
||
}
|
||
|
||
/* 用户统计行样式 */
|
||
.user-stats-row {
|
||
display: grid;
|
||
grid-template-columns: repeat(4, 1fr);
|
||
gap: 1.5rem;
|
||
margin-bottom: 2rem;
|
||
}
|
||
|
||
@media (max-width: 1200px) {
|
||
.user-stats-row {
|
||
grid-template-columns: repeat(2, 1fr);
|
||
}
|
||
}
|
||
|
||
@media (max-width: 600px) {
|
||
.user-stats-row {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
}
|
||
|
||
.stat-card-enhanced {
|
||
background: var(--container-bg);
|
||
border-radius: var(--radius-lg);
|
||
padding: 1.5rem;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 1rem;
|
||
box-shadow: var(--shadow-sm);
|
||
border: 1px solid var(--border-light);
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.stat-card-enhanced:hover {
|
||
transform: translateY(-3px);
|
||
box-shadow: var(--shadow-md);
|
||
border-color: var(--primary-color);
|
||
}
|
||
|
||
.stat-icon-wrapper {
|
||
width: 56px;
|
||
height: 56px;
|
||
border-radius: 12px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 1.5rem;
|
||
}
|
||
|
||
.stat-icon-wrapper.blue {
|
||
background: linear-gradient(135deg, #3d7cf4 0%, #5e95f7 100%);
|
||
color: white;
|
||
}
|
||
|
||
.stat-icon-wrapper.green {
|
||
background: linear-gradient(135deg, #28a745 0%, #48c764 100%);
|
||
color: white;
|
||
}
|
||
|
||
.stat-icon-wrapper.purple {
|
||
background: linear-gradient(135deg, #6f42c1 0%, #8c68cd 100%);
|
||
color: white;
|
||
}
|
||
|
||
.stat-icon-wrapper.orange {
|
||
background: linear-gradient(135deg, #fd7e14 0%, #fea347 100%);
|
||
color: white;
|
||
}
|
||
|
||
.stat-content {
|
||
flex: 1;
|
||
}
|
||
|
||
.stat-card-enhanced .stat-value {
|
||
font-size: 1.4rem;
|
||
font-weight: 700;
|
||
color: var(--text-primary);
|
||
margin-bottom: 0.25rem;
|
||
}
|
||
|
||
.stat-card-enhanced .stat-label {
|
||
font-size: 0.85rem;
|
||
color: var(--text-secondary);
|
||
}
|
||
|
||
/* 安全设置区域标题 */
|
||
.security-section-header {
|
||
margin-bottom: 1.5rem;
|
||
padding-bottom: 1rem;
|
||
border-bottom: 2px solid var(--border-light);
|
||
}
|
||
|
||
.security-section-header h2 {
|
||
font-size: 1.4rem;
|
||
font-weight: 600;
|
||
color: var(--text-primary);
|
||
margin: 0 0 0.5rem 0;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
}
|
||
|
||
.security-section-header h2 i {
|
||
color: var(--primary-color);
|
||
}
|
||
|
||
.security-section-header p {
|
||
color: var(--text-secondary);
|
||
margin: 0;
|
||
font-size: 0.9rem;
|
||
}
|
||
|
||
/* 安全卡片样式 */
|
||
.security-card {
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.security-card::before {
|
||
content: '';
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 4px;
|
||
height: 100%;
|
||
background: var(--primary-color);
|
||
border-radius: 4px 0 0 4px;
|
||
}
|
||
|
||
.card-icon-header {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 1rem;
|
||
margin-bottom: 1rem;
|
||
}
|
||
|
||
.card-icon {
|
||
width: 48px;
|
||
height: 48px;
|
||
border-radius: 12px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 1.3rem;
|
||
}
|
||
|
||
.card-icon.blue {
|
||
background: rgba(61, 124, 244, 0.1);
|
||
color: #3d7cf4;
|
||
}
|
||
|
||
.card-icon.orange {
|
||
background: rgba(253, 126, 20, 0.1);
|
||
color: #fd7e14;
|
||
}
|
||
|
||
.card-icon-header .user-center-section-title {
|
||
margin: 0;
|
||
padding: 0;
|
||
}
|
||
|
||
.card-icon-header .user-center-section-title::after {
|
||
display: none;
|
||
}
|
||
|
||
.card-description {
|
||
color: var(--text-secondary);
|
||
font-size: 0.9rem;
|
||
margin-bottom: 1.5rem;
|
||
line-height: 1.5;
|
||
}
|
||
|
||
/* 现代表单样式 */
|
||
.modern-form {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 1.25rem;
|
||
}
|
||
|
||
.modern-form .form-group {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 0.5rem;
|
||
}
|
||
|
||
.modern-form label {
|
||
font-weight: 500;
|
||
color: var(--text-primary);
|
||
font-size: 0.9rem;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
}
|
||
|
||
.modern-form label i {
|
||
color: var(--primary-color);
|
||
font-size: 0.85rem;
|
||
}
|
||
|
||
.form-input {
|
||
width: 100%;
|
||
padding: 0.5rem 0.75rem; /* 减小全局输入内边距以降低高度 */
|
||
border: 2px solid var(--border-light);
|
||
border-radius: var(--radius-md);
|
||
font-size: 0.95rem;
|
||
transition: all 0.16s ease;
|
||
background: var(--container-bg);
|
||
box-sizing: border-box;
|
||
line-height: 1.1;
|
||
}
|
||
|
||
.form-input:focus {
|
||
outline: none;
|
||
border-color: var(--primary-color);
|
||
box-shadow: 0 0 0 3px rgba(61, 124, 244, 0.1);
|
||
}
|
||
|
||
.form-input::placeholder {
|
||
color: var(--text-secondary);
|
||
opacity: 0.6;
|
||
}
|
||
|
||
.input-hint {
|
||
font-size: 0.8rem;
|
||
color: var(--text-secondary);
|
||
margin-top: -0.25rem;
|
||
}
|
||
|
||
.password-input-wrapper {
|
||
display: flex;
|
||
align-items: center;
|
||
width: 100%;
|
||
border: 1px solid var(--border-light);
|
||
border-radius: var(--radius-md);
|
||
background: var(--container-bg);
|
||
transition: all 0.15s ease;
|
||
overflow: hidden;
|
||
padding: 0 8px; /* 取消垂直内边距,使用固定输入高度居中 */
|
||
}
|
||
|
||
.password-input-wrapper:focus-within {
|
||
border-color: var(--primary-color);
|
||
box-shadow: 0 0 0 3px rgba(61, 124, 244, 0.08);
|
||
}
|
||
|
||
.password-input-wrapper .form-input {
|
||
flex: 1;
|
||
border: none !important;
|
||
border-radius: 0 !important;
|
||
background: transparent !important;
|
||
box-shadow: none !important;
|
||
padding: 0 12px !important; /* 横向内边距 */
|
||
height: 28px !important; /* 固定高度,保持不变 */
|
||
line-height: 28px !important; /* 与高度相同,垂直居中占位文本与输入文本 */
|
||
font-size: 14px !important;
|
||
box-sizing: border-box !important;
|
||
vertical-align: middle;
|
||
}
|
||
|
||
.password-input-wrapper .form-input::placeholder {
|
||
/* 有时浏览器对 placeholder 的居中不同,确保其 padding 一致 */
|
||
color: var(--text-secondary);
|
||
opacity: 0.6;
|
||
}
|
||
|
||
.password-input-wrapper .form-input:focus {
|
||
border: none !important;
|
||
box-shadow: none !important;
|
||
}
|
||
|
||
.password-input-wrapper .toggle-password {
|
||
width: 32px;
|
||
height: 32px;
|
||
background: #3b82f6;
|
||
border: none;
|
||
border-radius: 6px;
|
||
color: white;
|
||
cursor: pointer;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
transition: all 0.15s ease;
|
||
font-size: 13px;
|
||
padding: 0;
|
||
margin-left: 8px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.password-input-wrapper .toggle-password:hover {
|
||
background: #2563eb;
|
||
}
|
||
|
||
.password-input-wrapper .toggle-password i {
|
||
pointer-events: none;
|
||
}
|
||
|
||
/* 密码强度条 */
|
||
.password-strength-bar {
|
||
height: 4px;
|
||
background: var(--border-light);
|
||
border-radius: 2px;
|
||
overflow: hidden;
|
||
margin-top: 0.5rem;
|
||
}
|
||
|
||
.strength-indicator {
|
||
height: 100%;
|
||
width: 0;
|
||
border-radius: 2px;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.strength-indicator.weak {
|
||
width: 33%;
|
||
background: #dc3545;
|
||
}
|
||
|
||
.strength-indicator.medium {
|
||
width: 66%;
|
||
background: #ffc107;
|
||
}
|
||
|
||
.strength-indicator.strong {
|
||
width: 100%;
|
||
background: #28a745;
|
||
}
|
||
|
||
.password-strength-text {
|
||
font-size: 0.8rem;
|
||
margin-top: 0.5rem;
|
||
}
|
||
|
||
.password-strength-text.weak {
|
||
color: #dc3545;
|
||
}
|
||
|
||
.password-strength-text.medium {
|
||
color: #ffc107;
|
||
}
|
||
|
||
.password-strength-text.strong {
|
||
color: #28a745;
|
||
}
|
||
|
||
.btn-block {
|
||
width: 100%;
|
||
justify-content: center;
|
||
padding: 0.875rem 1.5rem;
|
||
font-size: 1rem;
|
||
margin-top: 0.5rem;
|
||
}
|
||
|
||
.form-actions {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 0.5rem;
|
||
}
|
||
|
||
/* 安全提示样式 */
|
||
.security-tips {
|
||
background: linear-gradient(135deg, rgba(61, 124, 244, 0.05) 0%, rgba(61, 124, 244, 0.1) 100%);
|
||
border: 1px solid rgba(61, 124, 244, 0.2);
|
||
border-radius: var(--radius-lg);
|
||
padding: 1.5rem;
|
||
margin-top: 2rem;
|
||
}
|
||
|
||
.tip-header {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.75rem;
|
||
margin-bottom: 1rem;
|
||
font-weight: 600;
|
||
color: var(--primary-color);
|
||
font-size: 1.1rem;
|
||
}
|
||
|
||
.tip-header i {
|
||
font-size: 1.3rem;
|
||
}
|
||
|
||
.tip-list {
|
||
list-style: none;
|
||
padding: 0;
|
||
margin: 0;
|
||
display: grid;
|
||
grid-template-columns: repeat(2, 1fr);
|
||
gap: 0.75rem;
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.tip-list {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
}
|
||
|
||
.tip-list li {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
gap: 0.5rem;
|
||
color: var(--text-secondary);
|
||
font-size: 0.9rem;
|
||
line-height: 1.4;
|
||
}
|
||
|
||
.tip-list li i {
|
||
color: #28a745;
|
||
margin-top: 0.2rem;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
/* 用户信息网格布局 */
|
||
.user-dashboard-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fill, minmax(min(100%, 450px), 1fr));
|
||
gap: 2rem;
|
||
}
|
||
|
||
/* 系统使用情况样式 */
|
||
.system-usage-stats {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 1.25rem;
|
||
}
|
||
|
||
.usage-stat {
|
||
width: 100%;
|
||
}
|
||
|
||
.usage-label {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
margin-bottom: 0.6rem;
|
||
color: var(--text-secondary);
|
||
font-size: 0.9rem;
|
||
}
|
||
|
||
.usage-label i {
|
||
color: var(--primary-color);
|
||
margin-right: 0.5rem;
|
||
}
|
||
|
||
.usage-value {
|
||
font-weight: 600;
|
||
color: var(--text-primary);
|
||
}
|
||
|
||
.progress-bar-container {
|
||
height: 8px;
|
||
background-color: rgba(0, 0, 0, 0.05);
|
||
border-radius: 4px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.progress-bar {
|
||
height: 100%;
|
||
background: linear-gradient(90deg, var(--primary-color) 0%, var(--primary-light) 100%);
|
||
border-radius: 4px;
|
||
}
|
||
|
||
/* 密码表单样式 */
|
||
.password-form {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 1.5rem;
|
||
}
|
||
|
||
.form-group {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 0.5rem;
|
||
}
|
||
|
||
.password-input-group {
|
||
display: flex;
|
||
position: relative;
|
||
}
|
||
|
||
.password-input {
|
||
flex: 1;
|
||
padding: 0.9rem 1rem;
|
||
border: 1px solid var(--border-color);
|
||
border-radius: var(--radius-md);
|
||
color: var(--text-primary);
|
||
background-color: var(--container-bg);
|
||
padding-right: 40px;
|
||
}
|
||
|
||
.password-toggle-btn {
|
||
position: absolute;
|
||
right: 10px;
|
||
top: 50%;
|
||
transform: translateY(-50%);
|
||
background: none;
|
||
border: none;
|
||
color: var(--text-secondary);
|
||
cursor: pointer;
|
||
transition: color 0.2s;
|
||
}
|
||
|
||
.password-toggle-btn:hover {
|
||
color: var(--primary-color);
|
||
}
|
||
|
||
.password-hint {
|
||
font-size: 0.8rem;
|
||
color: var(--text-secondary);
|
||
line-height: 1.3;
|
||
}
|
||
|
||
.password-strength-meter {
|
||
margin-top: 0.75rem;
|
||
}
|
||
|
||
.strength-bar {
|
||
height: 6px;
|
||
background-color: #f0f0f0;
|
||
border-radius: 3px;
|
||
margin-bottom: 0.4rem;
|
||
position: relative;
|
||
}
|
||
|
||
.strength-bar::before {
|
||
content: '';
|
||
position: absolute;
|
||
left: 0;
|
||
top: 0;
|
||
height: 100%;
|
||
border-radius: 3px;
|
||
width: 0;
|
||
transition: width 0.3s, background-color 0.3s;
|
||
}
|
||
|
||
.strength-text {
|
||
font-size: 0.8rem;
|
||
}
|
||
|
||
.password-submit-btn {
|
||
align-self: flex-start;
|
||
margin-top: 0.5rem;
|
||
}
|
||
|
||
/* 活动列表样式 */
|
||
.activity-list {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 1.25rem;
|
||
}
|
||
|
||
.activity-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 1rem;
|
||
padding-bottom: 1.25rem;
|
||
border-bottom: 1px solid var(--border-light);
|
||
}
|
||
|
||
.activity-item:last-child {
|
||
border-bottom: none;
|
||
padding-bottom: 0;
|
||
}
|
||
|
||
.activity-icon {
|
||
width: 40px;
|
||
height: 40px;
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: white;
|
||
font-size: 1rem;
|
||
}
|
||
|
||
.activity-icon.login {
|
||
background-color: #4361ee;
|
||
}
|
||
|
||
.activity-icon.container {
|
||
background-color: #3a86ff;
|
||
}
|
||
|
||
.activity-icon.password {
|
||
background-color: #f72585;
|
||
}
|
||
|
||
.activity-content {
|
||
flex: 1;
|
||
}
|
||
|
||
.activity-title {
|
||
font-weight: 500;
|
||
color: var(--text-primary);
|
||
margin-bottom: 0.25rem;
|
||
}
|
||
|
||
.activity-time {
|
||
font-size: 0.8rem;
|
||
color: var(--text-secondary);
|
||
}
|
||
|
||
.sidebar h2 {
|
||
color: var(--text-primary);
|
||
padding: 0 1.5rem;
|
||
margin-bottom: 2rem;
|
||
font-size: 1.3rem;
|
||
font-weight: 600;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.75rem;
|
||
position: relative;
|
||
}
|
||
|
||
.sidebar h2::after {
|
||
content: '';
|
||
position: absolute;
|
||
bottom: -10px;
|
||
left: 1.5rem;
|
||
right: 1.5rem;
|
||
height: 1px;
|
||
background: linear-gradient(to right, var(--primary-light), transparent);
|
||
}
|
||
|
||
.sidebar h2 i {
|
||
color: var(--primary-color);
|
||
font-size: 1.5rem;
|
||
}
|
||
|
||
.sidebar ul {
|
||
list-style: none;
|
||
padding: 0 0.75rem;
|
||
margin: 0;
|
||
}
|
||
|
||
.sidebar li {
|
||
padding: 0.9rem 1.25rem;
|
||
cursor: pointer;
|
||
transition: all var(--transition-fast);
|
||
color: var(--text-secondary);
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.9rem;
|
||
font-weight: 500;
|
||
margin: 0.35rem 0;
|
||
border-radius: var(--radius-md);
|
||
border-left: none;
|
||
position: relative;
|
||
}
|
||
|
||
.sidebar li:hover {
|
||
background: linear-gradient(90deg, rgba(61, 124, 244, 0.1), rgba(99, 102, 241, 0.05));
|
||
color: var(--primary-color);
|
||
transform: translateX(3px);
|
||
}
|
||
|
||
.sidebar li.active {
|
||
background: linear-gradient(90deg, var(--primary-color), #6366f1);
|
||
color: white;
|
||
font-weight: 600;
|
||
box-shadow: 0 4px 15px rgba(61, 124, 244, 0.3);
|
||
}
|
||
|
||
.sidebar li.active::before {
|
||
content: '';
|
||
position: absolute;
|
||
left: 0;
|
||
top: 50%;
|
||
transform: translateY(-50%);
|
||
width: 4px;
|
||
height: 60%;
|
||
background: white;
|
||
border-radius: 0 3px 3px 0;
|
||
}
|
||
|
||
.sidebar li i {
|
||
font-size: 1.15rem;
|
||
width: 1.5rem;
|
||
text-align: center;
|
||
transition: transform var(--transition-fast);
|
||
}
|
||
|
||
.sidebar li:hover i {
|
||
transform: scale(1.1);
|
||
}
|
||
|
||
.sidebar li.active i {
|
||
color: white;
|
||
}
|
||
|
||
.content-area {
|
||
flex: 1;
|
||
padding: 2rem;
|
||
overflow-y: auto;
|
||
background: linear-gradient(135deg, var(--background-color) 0%, rgba(247, 250, 255, 0.8) 100%);
|
||
}
|
||
|
||
.content-section {
|
||
background-color: var(--container-bg);
|
||
border-radius: var(--radius-lg);
|
||
box-shadow: var(--shadow-md);
|
||
padding: 2rem;
|
||
margin-bottom: 1.5rem;
|
||
display: none;
|
||
transform: translateY(10px);
|
||
opacity: 0;
|
||
transition: transform 0.3s ease, opacity 0.3s ease;
|
||
}
|
||
|
||
.content-section.active {
|
||
display: block;
|
||
transform: translateY(0);
|
||
opacity: 1;
|
||
}
|
||
|
||
.admin-title {
|
||
color: var(--text-primary);
|
||
font-size: 1.6rem;
|
||
font-weight: 600;
|
||
margin-bottom: 2rem;
|
||
padding-bottom: 1rem;
|
||
border-bottom: 1px solid var(--border-light);
|
||
position: relative;
|
||
}
|
||
|
||
.admin-title::after {
|
||
content: '';
|
||
position: absolute;
|
||
bottom: -1px;
|
||
left: 0;
|
||
width: 80px;
|
||
height: 3px;
|
||
background: var(--primary-color);
|
||
border-radius: 2px;
|
||
}
|
||
|
||
.menu-label {
|
||
color: var(--text-primary);
|
||
font-size: 1.4rem;
|
||
font-weight: 600;
|
||
margin-bottom: 1.5rem;
|
||
position: relative;
|
||
padding-bottom: 0.5rem;
|
||
}
|
||
|
||
.menu-label::after {
|
||
content: '';
|
||
position: absolute;
|
||
bottom: 0;
|
||
left: 0;
|
||
width: 60px;
|
||
height: 2px;
|
||
background: var(--primary-color);
|
||
border-radius: 2px;
|
||
}
|
||
|
||
/* 表单元素样式 */
|
||
.content-section input[type="text"],
|
||
.content-section input[type="url"],
|
||
.content-section input[type="password"],
|
||
.content-section input[type="number"],
|
||
.content-section select {
|
||
width: 100%;
|
||
max-width: 500px;
|
||
padding: 0.9rem 1rem;
|
||
border: 1px solid var(--border-color);
|
||
border-radius: var(--radius-md);
|
||
background-color: var(--container-bg);
|
||
color: var(--text-primary);
|
||
font-size: 0.95rem;
|
||
margin-bottom: 1.2rem;
|
||
transition: all var(--transition-fast);
|
||
box-shadow: var(--shadow-sm);
|
||
}
|
||
|
||
.content-section input:focus,
|
||
.content-section select:focus {
|
||
border-color: var(--primary-color);
|
||
box-shadow: 0 0 0 3px rgba(61, 124, 244, 0.2);
|
||
outline: none;
|
||
}
|
||
|
||
.content-section button {
|
||
background-color: var(--primary-color);
|
||
color: white;
|
||
border: none;
|
||
padding: 0.9rem 1.4rem;
|
||
border-radius: var(--radius-md);
|
||
cursor: pointer;
|
||
font-size: 0.95rem;
|
||
font-weight: 500;
|
||
transition: all var(--transition-fast);
|
||
margin-top: 0.5rem;
|
||
margin-right: 0.5rem;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
}
|
||
|
||
.content-section button:hover {
|
||
background-color: var(--primary-dark);
|
||
transform: translateY(-2px);
|
||
box-shadow: var(--shadow-md);
|
||
}
|
||
|
||
.content-section button:active {
|
||
transform: translateY(0);
|
||
}
|
||
|
||
.content-section label {
|
||
display: block;
|
||
margin-bottom: 0.5rem;
|
||
color: var(--text-primary);
|
||
font-weight: 500;
|
||
font-size: 1rem;
|
||
}
|
||
|
||
/* 表格样式 - 增强 Excel 效果 */
|
||
.content-section table {
|
||
width: 100%;
|
||
border-collapse: collapse; /* 合并边框 */
|
||
border-spacing: 0;
|
||
margin-top: 1.5rem;
|
||
margin-bottom: 2rem;
|
||
border: 1px solid #ccc; /* 表格外边框 */
|
||
font-size: 0.9rem; /* 稍微减小字体 */
|
||
box-shadow: 0 2px 5px rgba(0,0,0,0.1); /* 轻微阴影 */
|
||
}
|
||
|
||
.content-section th {
|
||
background-color: #f2f2f2; /* Excel 灰色表头背景 */
|
||
color: #333;
|
||
font-weight: bold; /* 加粗 */
|
||
text-align: left;
|
||
padding: 0.6rem 0.8rem; /* 调整内边距 */
|
||
border: 1px solid #ccc; /* 单元格边框 */
|
||
}
|
||
|
||
.content-section td {
|
||
padding: 0.6rem 0.8rem; /* 调整内边距 */
|
||
border: 1px solid #ddd; /* 单元格边框,比表头稍浅 */
|
||
vertical-align: middle;
|
||
background-color: #ffffff;
|
||
color: #444; /* 单元格文字颜色 */
|
||
word-break: break-word; /* 防止长 ID 撑开单元格 */
|
||
}
|
||
|
||
/* 可选:添加斑马纹效果 */
|
||
/*
|
||
.content-section tr:nth-child(even) td {
|
||
background-color: #f9f9f9;
|
||
}
|
||
*/
|
||
|
||
.content-section tr:hover td {
|
||
background-color: #e9f5ff; /* 鼠标悬停高亮 */
|
||
}
|
||
|
||
/* 表格头部悬停效果 */
|
||
.content-section th:hover {
|
||
background-color: #e8e8e8;
|
||
}
|
||
|
||
/* Excel风格的表格滚动条 */
|
||
.table-container {
|
||
overflow-x: auto;
|
||
max-width: 100%;
|
||
margin-bottom: 1.5rem;
|
||
border: 1px solid #e0e0e0;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
/* 操作列样式 */
|
||
.action-cell {
|
||
text-align: center;
|
||
min-width: 120px;
|
||
}
|
||
|
||
/* 状态列样式 */
|
||
.status-running {
|
||
background-color: #28a745;
|
||
color: white;
|
||
padding: 0.3rem 0.6rem;
|
||
border-radius: 4px;
|
||
font-size: 0.8rem;
|
||
display: inline-block;
|
||
text-align: center;
|
||
}
|
||
|
||
.status-stopped, .status-exited {
|
||
background-color: #dc3545;
|
||
color: white;
|
||
padding: 0.3rem 0.6rem;
|
||
border-radius: 4px;
|
||
font-size: 0.8rem;
|
||
display: inline-block;
|
||
text-align: center;
|
||
}
|
||
|
||
.status-created {
|
||
background-color: #17a2b8;
|
||
color: white;
|
||
padding: 0.3rem 0.6rem;
|
||
border-radius: 4px;
|
||
font-size: 0.8rem;
|
||
display: inline-block;
|
||
text-align: center;
|
||
}
|
||
|
||
.status-paused {
|
||
background-color: #ffc107;
|
||
color: #212529;
|
||
padding: 0.3rem 0.6rem;
|
||
border-radius: 4px;
|
||
font-size: 0.8rem;
|
||
display: inline-block;
|
||
text-align: center;
|
||
}
|
||
|
||
.status-unknown {
|
||
background-color: #6c757d;
|
||
color: white;
|
||
padding: 0.3rem 0.6rem;
|
||
border-radius: 4px;
|
||
font-size: 0.8rem;
|
||
display: inline-block;
|
||
text-align: center;
|
||
}
|
||
|
||
/* 下拉菜单样式 */
|
||
.action-dropdown .dropdown-toggle {
|
||
border-color: #d0d0d0;
|
||
background-color: #fff;
|
||
color: #333;
|
||
font-size: 0.9rem;
|
||
padding: 0.4rem 0.8rem;
|
||
}
|
||
|
||
.action-dropdown .dropdown-toggle:hover,
|
||
.action-dropdown .dropdown-toggle:focus {
|
||
background-color: #f0f0f0;
|
||
box-shadow: none;
|
||
}
|
||
|
||
.action-dropdown .dropdown-menu {
|
||
min-width: 150px;
|
||
padding: 0.3rem 0;
|
||
border: 1px solid #d0d0d0;
|
||
border-radius: 4px;
|
||
box-shadow: 0 3px 6px rgba(0,0,0,0.1);
|
||
font-size: 0.9rem;
|
||
}
|
||
|
||
.action-dropdown .dropdown-item {
|
||
padding: 0.5rem 1rem;
|
||
color: #333;
|
||
}
|
||
|
||
.action-dropdown .dropdown-item:hover {
|
||
background-color: #f0f7ff;
|
||
}
|
||
|
||
.action-dropdown .dropdown-item i {
|
||
width: 1rem;
|
||
text-align: center;
|
||
margin-right: 0.5rem;
|
||
}
|
||
|
||
.action-dropdown .text-danger {
|
||
color: #dc3545 !important;
|
||
}
|
||
|
||
.action-dropdown .dropdown-divider {
|
||
margin: 0.3rem 0;
|
||
}
|
||
|
||
/* 登录模态框 */
|
||
.login-modal {
|
||
display: flex;
|
||
position: fixed;
|
||
z-index: 1000;
|
||
left: 0;
|
||
top: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
overflow: auto;
|
||
background: url('/images/login-bg.jpg') center/cover no-repeat;
|
||
justify-content: center;
|
||
align-items: center;
|
||
animation: fadeIn 0.5s ease-in-out;
|
||
}
|
||
|
||
.login-modal::before {
|
||
content: '';
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background: linear-gradient(135deg, rgba(26, 35, 126, 0.9) 0%, rgba(61, 124, 244, 0.85) 50%, rgba(99, 102, 241, 0.85) 100%);
|
||
backdrop-filter: blur(8px);
|
||
}
|
||
|
||
.login-content {
|
||
background: linear-gradient(180deg, rgba(255, 255, 255, 0.98), rgba(255, 255, 255, 0.95));
|
||
padding: 2.75rem;
|
||
border-radius: var(--radius-lg);
|
||
width: 400px;
|
||
box-shadow: 0 25px 50px rgba(0, 0, 0, 0.25);
|
||
position: relative;
|
||
animation: slideUp 0.5s ease-out;
|
||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||
}
|
||
|
||
@keyframes fadeIn {
|
||
from { opacity: 0; }
|
||
to { opacity: 1; }
|
||
}
|
||
|
||
@keyframes slideUp {
|
||
from { transform: translateY(30px); opacity: 0; }
|
||
to { transform: translateY(0); opacity: 1; }
|
||
}
|
||
|
||
.login-header h2 {
|
||
color: var(--text-primary);
|
||
font-size: 1.9rem;
|
||
margin-bottom: 2rem;
|
||
text-align: center;
|
||
font-weight: 700;
|
||
position: relative;
|
||
padding-bottom: 1rem;
|
||
}
|
||
|
||
.login-header h2::after {
|
||
content: '';
|
||
position: absolute;
|
||
bottom: 0;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
width: 60px;
|
||
height: 3px;
|
||
background: linear-gradient(90deg, var(--primary-color), #6366f1);
|
||
border-radius: 2px;
|
||
}
|
||
|
||
.login-form input[type="text"],
|
||
.login-form input[type="password"] {
|
||
width: 100%;
|
||
padding: 1rem 1.25rem;
|
||
margin: 0.75rem 0;
|
||
border: 1px solid var(--border-color);
|
||
border-radius: var(--radius-md);
|
||
box-sizing: border-box;
|
||
font-size: 1rem;
|
||
background-color: #fafbfc;
|
||
color: var(--text-primary);
|
||
transition: all var(--transition-fast);
|
||
box-shadow: var(--shadow-sm);
|
||
}
|
||
|
||
.login-form input:focus {
|
||
border-color: var(--primary-color);
|
||
box-shadow: 0 0 0 4px rgba(61, 124, 244, 0.15);
|
||
outline: none;
|
||
background-color: white;
|
||
}
|
||
|
||
.login-form button {
|
||
width: 100%;
|
||
padding: 1rem;
|
||
background: linear-gradient(135deg, var(--primary-color), #6366f1);
|
||
color: white;
|
||
border: none;
|
||
border-radius: var(--radius-md);
|
||
cursor: pointer;
|
||
font-size: 1.1rem;
|
||
font-weight: 600;
|
||
margin-top: 1.8rem;
|
||
transition: all var(--transition-fast);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 0.5rem;
|
||
box-shadow: 0 4px 15px rgba(61, 124, 244, 0.35);
|
||
}
|
||
|
||
.login-form button:hover {
|
||
background: linear-gradient(135deg, #5084f5, #7c7ff7);
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 6px 20px rgba(61, 124, 244, 0.4);
|
||
}
|
||
|
||
.login-form button:active {
|
||
transform: translateY(0);
|
||
}
|
||
|
||
.login-form button:before {
|
||
content: "\f2f6";
|
||
font-family: "Font Awesome 6 Free";
|
||
font-weight: 900;
|
||
}
|
||
|
||
.captcha-container {
|
||
display: flex;
|
||
align-items: center;
|
||
margin: 0.75rem 0;
|
||
gap: 0.75rem;
|
||
}
|
||
|
||
.captcha-container input {
|
||
flex: 1;
|
||
}
|
||
|
||
.captcha-container span {
|
||
padding: 0.85rem 1rem;
|
||
background: linear-gradient(135deg, #f0f4ff, #f7f8fc);
|
||
border: 1px solid var(--border-color);
|
||
border-radius: var(--radius-md);
|
||
cursor: pointer;
|
||
font-size: 0.95rem;
|
||
color: var(--text-secondary);
|
||
transition: all var(--transition-fast);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.captcha-container span:hover {
|
||
background: linear-gradient(135deg, #e8eeff, #f0f4ff);
|
||
color: var(--primary-color);
|
||
border-color: var(--primary-color);
|
||
}
|
||
|
||
/* 加载指示器 */
|
||
.loading-spinner {
|
||
position: fixed;
|
||
top: 50%;
|
||
left: 50%;
|
||
transform: translate(-50%, -50%);
|
||
width: 50px;
|
||
height: 50px;
|
||
border: 5px solid rgba(61, 124, 244, 0.1);
|
||
border-top: 5px solid var(--primary-color);
|
||
border-radius: 50%;
|
||
animation: spin 1s linear infinite;
|
||
z-index: 9999;
|
||
}
|
||
|
||
@keyframes spin {
|
||
0% { transform: translate(-50%, -50%) rotate(0deg); }
|
||
100% { transform: translate(-50%, -50%) rotate(360deg); }
|
||
}
|
||
|
||
#loadingIndicator {
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
height: 100vh;
|
||
background-color: var(--background-color);
|
||
color: var(--text-secondary);
|
||
font-size: 1.1rem;
|
||
}
|
||
|
||
/* 状态指示样式 */
|
||
.disabled {
|
||
opacity: 0.5;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.status-cell {
|
||
position: relative;
|
||
min-height: 24px;
|
||
}
|
||
|
||
.status-content {
|
||
position: absolute;
|
||
top: 50%;
|
||
left: 50%;
|
||
transform: translate(-50%, -50%);
|
||
width: 100%;
|
||
text-align: center;
|
||
}
|
||
|
||
.loading-container {
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
}
|
||
|
||
.loading {
|
||
display: inline-block;
|
||
width: 20px;
|
||
height: 20px;
|
||
border: 3px solid rgba(61, 124, 244, 0.1);
|
||
border-radius: 50%;
|
||
border-top: 3px solid var(--primary-color);
|
||
animation: spin 1s linear infinite;
|
||
}
|
||
|
||
/* 监控配置部分 */
|
||
.monitoring-status {
|
||
margin-bottom: 1.5rem;
|
||
font-size: 1rem;
|
||
color: var(--text-secondary);
|
||
background-color: rgba(61, 124, 244, 0.05);
|
||
padding: 1rem 1.5rem;
|
||
border-radius: var(--radius-md);
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.75rem;
|
||
}
|
||
|
||
.monitoring-status:before {
|
||
content: "\f021";
|
||
font-family: "Font Awesome 6 Free";
|
||
font-weight: 900;
|
||
color: var(--primary-color);
|
||
}
|
||
|
||
.status-indicator {
|
||
font-weight: 600;
|
||
}
|
||
|
||
.config-form {
|
||
background-color: var (--container-bg);
|
||
padding: 1.8rem;
|
||
border-radius: var(--radius-md);
|
||
margin-bottom: 1.5rem;
|
||
border: 1px solid var(--border-light);
|
||
box-shadow: var(--shadow-sm);
|
||
}
|
||
|
||
.form-group {
|
||
margin-bottom: 1.2rem;
|
||
}
|
||
|
||
.form-control {
|
||
width: 100%;
|
||
padding: 0.9rem 1rem;
|
||
border: 1px solid var(--border-color);
|
||
border-radius: var(--radius-md);
|
||
color: var(--text-primary);
|
||
background-color: var(--container-bg);
|
||
}
|
||
|
||
.button-group {
|
||
display: flex;
|
||
gap: 0.75rem;
|
||
flex-wrap: wrap;
|
||
margin-top: 1.5rem;
|
||
}
|
||
|
||
.btn {
|
||
padding: 0.8rem 1.2rem;
|
||
border: none;
|
||
border-radius: var(--radius-md);
|
||
cursor: pointer;
|
||
transition: all var(--transition-fast);
|
||
font-size: 0.95rem;
|
||
font-weight: 500;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
}
|
||
|
||
.btn-primary {
|
||
background-color: var(--primary-color);
|
||
color: white;
|
||
}
|
||
|
||
/* Fix 4: Remove icon from user center buttons */
|
||
.user-center-header .btn-primary,
|
||
.user-center-section .btn-primary {
|
||
background-color: var(--primary-color);
|
||
color: white;
|
||
padding: 0.8rem 1.2rem;
|
||
border-radius: var(--radius-md);
|
||
cursor: pointer;
|
||
transition: all var(--transition-fast);
|
||
font-size: 0.95rem;
|
||
font-weight: 500;
|
||
display: inline-block; /* Change to inline-block */
|
||
}
|
||
|
||
/* Remove the :before pseudo-element for these specific buttons */
|
||
.user-center-header .btn-primary:before,
|
||
.user-center-section .btn-primary:before {
|
||
display: none;
|
||
}
|
||
|
||
.btn-secondary {
|
||
background-color: var(--text-secondary);
|
||
color: white;
|
||
}
|
||
|
||
.btn:hover {
|
||
transform: translateY(-2px);
|
||
box-shadow: var(--shadow-sm);
|
||
}
|
||
|
||
.btn:active {
|
||
transform: translateY(0);
|
||
}
|
||
|
||
.section-title {
|
||
color: var(--text-primary);
|
||
font-size: 1.3rem;
|
||
font-weight: 600;
|
||
margin: 2rem 0 1.2rem;
|
||
position: relative;
|
||
padding-left: 1rem;
|
||
border-left: 3px solid var(--primary-color);
|
||
}
|
||
|
||
.container-table {
|
||
width: 100%;
|
||
border-collapse: separate;
|
||
border-spacing: 0;
|
||
margin-bottom: 1.5rem;
|
||
border-radius: var(--radius-md);
|
||
overflow: hidden;
|
||
box-shadow: var(--shadow-sm);
|
||
}
|
||
|
||
.container-table th {
|
||
background-color: var(--primary-color);
|
||
color: white;
|
||
padding: 0.9rem 1rem;
|
||
text-align: left;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.container-table td {
|
||
padding: 0.9rem 1rem;
|
||
border-bottom: 1px solid var(--border-light);
|
||
}
|
||
|
||
.container-table tr:last-child td {
|
||
border-bottom: none;
|
||
}
|
||
|
||
.error-message {
|
||
color: var(--danger-color);
|
||
margin-top: 0.75rem;
|
||
padding: 0.75rem;
|
||
border-radius: var (--radius-md);;
|
||
background-color: rgba(255, 82, 82, 0.1);
|
||
font-size: 0.9rem;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
}
|
||
|
||
.error-message:before {
|
||
content: "\f071";
|
||
font-family: "Font Awesome 6 Free";
|
||
font-weight: 900;
|
||
}
|
||
|
||
.success-message {
|
||
color: var (--success-color);
|
||
margin-top: 0.75rem;
|
||
padding: 0.75rem;
|
||
border-radius: var (--radius-md);
|
||
background-color: rgba(50, 213, 131, 0.1);
|
||
font-size: 0.9rem;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
}
|
||
|
||
.success-message:before {
|
||
content: "\f00c";
|
||
font-family: "Font Awesome 6 Free";
|
||
font-weight: 900;
|
||
}
|
||
|
||
/* 网络测试部分 */
|
||
#network-test .input-group {
|
||
margin-bottom: 1.2rem;
|
||
max-width: 600px;
|
||
background-color: rgba(61, 124, 244, 0.03);
|
||
padding: 1.5rem;
|
||
border-radius: var(--radius-md);
|
||
box-shadow: var(--shadow-sm);
|
||
}
|
||
|
||
#network-test label {
|
||
display: block;
|
||
margin-bottom: 0.5rem;
|
||
color: var(--text-secondary);
|
||
font-weight: 500;
|
||
}
|
||
|
||
#testResults {
|
||
margin-top: 1.5rem;
|
||
padding: 1rem;
|
||
background-color: #1e2532;
|
||
color: #e9ecef;
|
||
border-radius: var(--radius-md);
|
||
white-space: pre-wrap;
|
||
font-family: 'JetBrains Mono', monospace;
|
||
min-height: 300px;
|
||
max-height: 500px;
|
||
overflow-y: auto;
|
||
border: none;
|
||
box-shadow: var(--shadow-md);
|
||
position: relative;
|
||
}
|
||
|
||
/* 文档编辑器部分 */
|
||
#editor #editorContainer {
|
||
margin-top: 2rem;
|
||
border-radius: var(--radius-md);
|
||
background-color: var(--container-bg);
|
||
overflow: hidden;
|
||
box-shadow: var(--shadow-md);
|
||
border: 1px solid var(--border-light);
|
||
}
|
||
|
||
#documentTitle {
|
||
width: 100%;
|
||
padding: 1rem;
|
||
margin-bottom: 0;
|
||
border: 1px solid var(--border-color);
|
||
border-radius: var(--radius-md) var(--radius-md) 0 0;
|
||
font-size: 1.1rem;
|
||
font-weight: 500;
|
||
box-shadow: none;
|
||
background-color: var(--container-bg);
|
||
color: var(--text-primary);
|
||
border-bottom: 1px solid var(--border-light);
|
||
}
|
||
|
||
#documentTitle:focus {
|
||
border-color: var(--primary-color);
|
||
box-shadow: 0 0 0 2px rgba(61, 124, 244, 0.2);
|
||
outline: none;
|
||
}
|
||
|
||
/* Editor.md 样式覆盖 */
|
||
#editor #editorContainer .editormd {
|
||
border: 1px solid var(--border-light) !important;
|
||
border-top: none !important;
|
||
border-radius: 0 0 var(--radius-md) var(--radius-md) !important;
|
||
box-shadow: none !important;
|
||
margin-top: 0 !important;
|
||
width: 100% !important;
|
||
height: auto !important;
|
||
}
|
||
|
||
#editor #editorContainer .editormd-toolbar {
|
||
background-color: var(--container-bg) !important;
|
||
border-bottom: 1px solid var(--border-light) !important;
|
||
padding: 0.5rem !important;
|
||
width: 100% !important;
|
||
box-sizing: border-box !important;
|
||
}
|
||
|
||
#editor #editorContainer .editormd-toolbar button {
|
||
background-color: transparent !important;
|
||
border: 1px solid var(--border-light) !important;
|
||
color: var(--text-primary) !important;
|
||
border-radius: var(--radius-sm) !important;
|
||
margin: 0 2px !important;
|
||
padding: 0.4rem 0.6rem !important;
|
||
transition: all 0.2s ease !important;
|
||
}
|
||
|
||
#editor #editorContainer .editormd-toolbar button:hover {
|
||
background-color: var(--primary-color) !important;
|
||
color: white !important;
|
||
border-color: var(--primary-color) !important;
|
||
}
|
||
|
||
#editor #editorContainer .editormd-toolbar button.active {
|
||
background-color: var(--primary-color) !important;
|
||
color: white !important;
|
||
border-color: var(--primary-color) !important;
|
||
}
|
||
|
||
/* 编辑区域和预览区域等宽等高 */
|
||
#editor #editorContainer .editormd > .editormd-editor {
|
||
width: 50% !important;
|
||
float: left !important;
|
||
box-sizing: border-box !important;
|
||
}
|
||
|
||
#editor #editorContainer .editormd > .editormd-preview {
|
||
width: 50% !important;
|
||
float: right !important;
|
||
box-sizing: border-box !important;
|
||
}
|
||
|
||
#editor #editorContainer .CodeMirror {
|
||
background-color: var(--container-bg) !important;
|
||
color: var(--text-primary) !important;
|
||
border: none !important;
|
||
font-family: 'Monaco', 'Consolas', 'Courier New', monospace !important;
|
||
font-size: 14px !important;
|
||
line-height: 1.6 !important;
|
||
height: 500px !important;
|
||
width: 100% !important;
|
||
box-sizing: border-box !important;
|
||
}
|
||
|
||
#editor #editorContainer .CodeMirror .CodeMirror-cursor {
|
||
border-left: 1px solid var(--text-primary) !important;
|
||
}
|
||
|
||
#editor #editorContainer .CodeMirror .CodeMirror-selected {
|
||
background-color: rgba(61, 124, 244, 0.2) !important;
|
||
}
|
||
|
||
#editor #editorContainer .editormd-preview {
|
||
background-color: var(--container-bg) !important;
|
||
color: var(--text-primary) !important;
|
||
border-left: 1px solid var(--border-light) !important;
|
||
padding: 1rem !important;
|
||
height: 500px !important;
|
||
overflow-y: auto !important;
|
||
box-sizing: border-box !important;
|
||
}
|
||
|
||
/* 确保容器清除浮动 */
|
||
#editor #editorContainer .editormd::after {
|
||
content: "" !important;
|
||
display: table !important;
|
||
clear: both !important;
|
||
}
|
||
|
||
#editor #editorContainer .editormd-preview h1,
|
||
#editor #editorContainer .editormd-preview h2,
|
||
#editor #editorContainer .editormd-preview h3,
|
||
#editor #editorContainer .editormd-preview h4,
|
||
#editor #editorContainer .editormd-preview h5,
|
||
#editor #editorContainer .editormd-preview h6 {
|
||
color: var(--text-primary) !important;
|
||
border-bottom: 1px solid var(--border-light) !important;
|
||
padding-bottom: 0.5rem !important;
|
||
margin-bottom: 1rem !important;
|
||
}
|
||
|
||
#editor #editorContainer .editormd-preview pre {
|
||
background-color: rgba(0, 0, 0, 0.05) !important;
|
||
border: 1px solid var(--border-light) !important;
|
||
border-radius: var(--radius-sm) !important;
|
||
padding: 1rem !important;
|
||
overflow-x: auto !important;
|
||
}
|
||
|
||
#editor #editorContainer .editormd-preview blockquote {
|
||
border-left: 4px solid var(--primary-color) !important;
|
||
background-color: rgba(61, 124, 244, 0.05) !important;
|
||
margin: 1rem 0 !important;
|
||
padding: 0.5rem 1rem !important;
|
||
}
|
||
|
||
#editor #editorContainer .editormd-preview table {
|
||
border-collapse: collapse !important;
|
||
width: 100% !important;
|
||
margin: 1rem 0 !important;
|
||
}
|
||
|
||
#editor #editorContainer .editormd-preview table th,
|
||
#editor #editorContainer .editormd-preview table td {
|
||
border: 1px solid var(--border-light) !important;
|
||
padding: 0.5rem 1rem !important;
|
||
text-align: left !important;
|
||
}
|
||
|
||
#editor #editorContainer .editormd-preview table th {
|
||
background-color: rgba(61, 124, 244, 0.1) !important;
|
||
font-weight: 600 !important;
|
||
}
|
||
|
||
/* 编辑器操作按钮样式 */
|
||
.editor-actions {
|
||
padding: 1rem !important;
|
||
background-color: var(--container-bg) !important;
|
||
border-top: 1px solid var(--border-light) !important;
|
||
display: flex !important;
|
||
gap: 0.75rem !important;
|
||
justify-content: flex-end !important;
|
||
}
|
||
|
||
.editor-actions .btn {
|
||
padding: 0.75rem 1.5rem !important;
|
||
border-radius: var(--radius-md) !important;
|
||
font-weight: 500 !important;
|
||
transition: all 0.2s ease !important;
|
||
}
|
||
|
||
.editor-actions .btn-primary {
|
||
background-color: var(--primary-color) !important;
|
||
color: white !important;
|
||
border: 1px solid var(--primary-color) !important;
|
||
}
|
||
|
||
.editor-actions .btn-primary:hover {
|
||
background-color: var(--primary-dark) !important;
|
||
border-color: var(--primary-dark) !important;
|
||
transform: translateY(-2px) !important;
|
||
box-shadow: var(--shadow-md) !important;
|
||
}
|
||
|
||
.editor-actions .btn-secondary {
|
||
background-color: transparent !important;
|
||
color: var(--text-secondary) !important;
|
||
border: 1px solid var(--border-color) !important;
|
||
}
|
||
|
||
.editor-actions .btn-secondary:hover {
|
||
background-color: var(--text-secondary) !important;
|
||
color: white !important;
|
||
transform: translateY(-2px) !important;
|
||
box-shadow: var(--shadow-sm) !important;
|
||
}
|
||
|
||
/* 响应式 Editor.md 样式 */
|
||
@media (max-width: 768px) {
|
||
#editor #editorContainer .editormd {
|
||
height: auto !important;
|
||
}
|
||
|
||
/* 移动端编辑区域和预览区域上下布局 */
|
||
#editor #editorContainer .editormd > .editormd-editor {
|
||
width: 100% !important;
|
||
float: none !important;
|
||
margin-bottom: 1px !important;
|
||
}
|
||
|
||
#editor #editorContainer .editormd > .editormd-preview {
|
||
width: 100% !important;
|
||
float: none !important;
|
||
border-left: none !important;
|
||
border-top: 1px solid var(--border-light) !important;
|
||
}
|
||
|
||
#editor #editorContainer .CodeMirror {
|
||
height: 300px !important;
|
||
}
|
||
|
||
#editor #editorContainer .editormd-preview {
|
||
height: 300px !important;
|
||
}
|
||
|
||
#editor #editorContainer .editormd-toolbar {
|
||
padding: 0.3rem !important;
|
||
flex-wrap: wrap !important;
|
||
}
|
||
|
||
#editor #editorContainer .editormd-toolbar button {
|
||
margin: 1px !important;
|
||
padding: 0.3rem 0.4rem !important;
|
||
font-size: 0.85rem !important;
|
||
}
|
||
|
||
.editor-actions {
|
||
flex-direction: column !important;
|
||
gap: 0.5rem !important;
|
||
}
|
||
|
||
.editor-actions .btn {
|
||
width: 100% !important;
|
||
text-align: center !important;
|
||
}
|
||
}
|
||
|
||
/* 中等屏幕适配 */
|
||
@media (max-width: 1024px) and (min-width: 769px) {
|
||
#editor #editorContainer .CodeMirror {
|
||
height: 450px !important;
|
||
}
|
||
|
||
#editor #editorContainer .editormd-preview {
|
||
height: 450px !important;
|
||
}
|
||
}
|
||
|
||
.password-hint {
|
||
color: var(--text-secondary);
|
||
font-size: 0.9rem;
|
||
margin: 0.5rem 0 1rem;
|
||
display: block;
|
||
background-color: rgba(61, 124, 244, 0.05);
|
||
padding: 0.75rem;
|
||
border-radius: var(--radius-md);
|
||
}
|
||
|
||
#passwordStrength {
|
||
font-size: 0.9rem;
|
||
margin: 0.5rem 0;
|
||
display: block;
|
||
}
|
||
|
||
/* 警告和确认对话框样式 */
|
||
.swal2-popup {
|
||
font-size: 1rem !important;
|
||
border-radius: var(--radius-lg) !important;
|
||
}
|
||
|
||
.swal2-title {
|
||
font-weight: 600 !important;
|
||
color: var(--text-primary) !important;
|
||
}
|
||
|
||
.swal2-styled.swal2-confirm {
|
||
background-color: var(--primary-color) !important;
|
||
border-radius: var(--radius-md) !important;
|
||
}
|
||
|
||
/* 添加条目按钮 */
|
||
.add-btn {
|
||
background-color: var(--success-color);
|
||
color: white;
|
||
padding: 0.8rem 1.2rem;
|
||
border-radius: var (--radius-md);
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
font-weight: 500;
|
||
margin-top: 1rem;
|
||
box-shadow: var(--shadow-sm);
|
||
}
|
||
|
||
.add-btn:before {
|
||
content: "";
|
||
/* 移除 Font Awesome 图标,以避免和 HTML 中的图标重复 */
|
||
}
|
||
|
||
.add-btn:hover {
|
||
background-color: #29b873;
|
||
transform: translateY(-2px);
|
||
box-shadow: var(--shadow-md);
|
||
}
|
||
|
||
/* Docker容器操作按钮样式 */
|
||
.action-cell {
|
||
min-width: 200px;
|
||
}
|
||
|
||
.action-buttons {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 4px;
|
||
}
|
||
|
||
.action-buttons button {
|
||
padding: 3px 8px;
|
||
font-size: 0.8rem;
|
||
margin-right: 3px;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.action-buttons button i {
|
||
margin-right: 3px;
|
||
font-size: 0.75rem;
|
||
}
|
||
|
||
/* 改善按钮在小屏幕上的显示 */
|
||
@media (max-width: 768px) {
|
||
.action-buttons {
|
||
flex-direction: column;
|
||
}
|
||
|
||
.action-buttons button {
|
||
margin-bottom: 3px;
|
||
width: 100%;
|
||
}
|
||
}
|
||
|
||
/* 响应式设计 */
|
||
@media (max-width: 992px) {
|
||
.admin-container {
|
||
flex-direction: column;
|
||
}
|
||
|
||
.sidebar {
|
||
width: 100%;
|
||
padding: 1rem 0;
|
||
}
|
||
|
||
.sidebar ul {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
justify-content: flex-start;
|
||
}
|
||
|
||
.sidebar li {
|
||
padding: 0.5rem 1rem;
|
||
border-left: none;
|
||
border-bottom: 3px solid transparent;
|
||
}
|
||
|
||
.sidebar li.active {
|
||
border-left: none;
|
||
border-bottom: 3px solid var(--primary-color);
|
||
}
|
||
|
||
.content-area {
|
||
padding: 1rem;
|
||
}
|
||
|
||
.content-section {
|
||
padding: 1.5rem;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.content-section th,
|
||
.content-section td {
|
||
padding: 0.75rem 0.5rem;
|
||
font-size: 0.9rem;
|
||
}
|
||
|
||
.button-group {
|
||
flex-direction: column;
|
||
}
|
||
|
||
.btn, .action-btn {
|
||
width: 100%;
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
|
||
.action-buttons {
|
||
flex-direction: column;
|
||
}
|
||
|
||
.action-buttons button {
|
||
margin-bottom: 3px;
|
||
width: 100%;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 480px) {
|
||
.login-content {
|
||
width: 90%;
|
||
padding: 1.5rem;
|
||
}
|
||
}
|
||
|
||
/* Excel风格表格 */
|
||
.excel-table {
|
||
border-collapse: collapse;
|
||
width: 100%;
|
||
font-size: 14px;
|
||
border: 1px solid #ccc;
|
||
}
|
||
.excel-table th {
|
||
background-color: #f2f2f2;
|
||
border: 1px solid #ccc;
|
||
padding: 8px;
|
||
text-align: center;
|
||
position: sticky;
|
||
top: 0;
|
||
z-index: 10;
|
||
}
|
||
.excel-table td {
|
||
border: 1px solid #ccc;
|
||
padding: 6px 8px;
|
||
text-align: left;
|
||
}
|
||
.excel-table tr:nth-child(even) {
|
||
background-color: #f9f9f9;
|
||
}
|
||
.excel-table tr:hover {
|
||
background-color: #f0f7ff;
|
||
}
|
||
|
||
/* 容器更新样式 */
|
||
.update-progress {
|
||
padding: 1rem;
|
||
text-align: center;
|
||
}
|
||
|
||
.update-progress p {
|
||
margin-bottom: 1rem;
|
||
font-size: 1rem;
|
||
}
|
||
|
||
.update-progress strong {
|
||
color: #007bff;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.progress-status {
|
||
margin: 1rem 0;
|
||
font-size: 0.9rem;
|
||
color: #555;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.progress-container {
|
||
width: 100%;
|
||
height: 10px;
|
||
background-color: #f0f0f0;
|
||
border-radius: 5px;
|
||
overflow: hidden;
|
||
margin: 1rem 0;
|
||
}
|
||
|
||
.progress-bar {
|
||
height: 100%;
|
||
background-color: #4CAF50;
|
||
width: 0%;
|
||
transition: width 0.3s ease-in-out;
|
||
border-radius: 5px;
|
||
position: relative;
|
||
}
|
||
|
||
/* 修改SweetAlert样式 */
|
||
.swal2-popup.update-popup {
|
||
border-radius: 10px;
|
||
padding: 1.5rem;
|
||
box-shadow: 0 4px 20px rgba(0,0,0,0.15);
|
||
}
|
||
|
||
.swal2-title.update-title {
|
||
font-size: 1.5rem;
|
||
font-weight: 600;
|
||
color: #333;
|
||
}
|
||
|
||
.swal2-input.update-input {
|
||
box-shadow: none;
|
||
border: 1px solid #ddd;
|
||
border-radius: 5px;
|
||
padding: 0.75rem;
|
||
font-size: 0.95rem;
|
||
}
|
||
|
||
.swal2-input.update-input:focus {
|
||
border-color: #3085d6;
|
||
box-shadow: 0 0 0 3px rgba(48, 133, 214, 0.2);
|
||
}
|
||
|
||
/* 容器日志样式 */
|
||
.container-logs {
|
||
max-height: 70vh;
|
||
overflow-y: auto;
|
||
background: #1e1e1e;
|
||
color: #f0f0f0;
|
||
padding: 1rem;
|
||
border-radius: 5px;
|
||
font-family: 'Courier New', monospace;
|
||
font-size: 0.9rem;
|
||
white-space: pre-wrap;
|
||
word-break: break-all;
|
||
}
|
||
|
||
.swal2-logs-container {
|
||
max-width: 100%;
|
||
padding: 0 !important;
|
||
}
|
||
|
||
.swal2-logs-popup {
|
||
max-width: 80% !important;
|
||
}
|
||
|
||
/* 容器状态标签样式 */
|
||
.badge.status-running {
|
||
background-color: #28a745;
|
||
color: white;
|
||
padding: 5px 8px;
|
||
border-radius: 4px;
|
||
display: inline-block;
|
||
min-width: 70px;
|
||
text-align: center;
|
||
}
|
||
|
||
.badge.status-stopped, .badge.status-exited {
|
||
background-color: #dc3545;
|
||
color: white;
|
||
padding: 5px 8px;
|
||
border-radius: 4px;
|
||
display: inline-block;
|
||
min-width: 70px;
|
||
text-align: center;
|
||
}
|
||
|
||
.badge.status-created {
|
||
background-color: #17a2b8;
|
||
color: white;
|
||
padding: 5px 8px;
|
||
border-radius: 4px;
|
||
display: inline-block;
|
||
min-width: 70px;
|
||
text-align: center;
|
||
}
|
||
|
||
.badge.status-unknown, .badge.status-paused {
|
||
background-color: #6c757d;
|
||
color: white;
|
||
padding: 5px 8px;
|
||
border-radius: 4px;
|
||
display: inline-block;
|
||
min-width: 70px;
|
||
text-align: center;
|
||
}
|
||
|
||
/* 容器表格标题样式 */
|
||
.docker-table-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 15px;
|
||
padding-bottom: 10px;
|
||
border-bottom: 1px solid #eee;
|
||
}
|
||
|
||
.docker-table-title {
|
||
font-size: 18px;
|
||
font-weight: 600;
|
||
color: #333;
|
||
margin: 0;
|
||
}
|
||
|
||
/* 菜单管理 - 新增行样式 */
|
||
#new-menu-item-row input[type="text"],
|
||
#new-menu-item-row select {
|
||
/* 使用 Bootstrap 的 form-control-sm 已经减小了 padding 和 font-size */
|
||
margin-bottom: 0; /* 移除下方外边距,使其在表格行内更紧凑 */
|
||
}
|
||
|
||
#new-menu-item-row .form-control-sm {
|
||
padding: 0.3rem 0.6rem; /* 微调内边距 */
|
||
font-size: 0.875rem; /* 统一字体大小 */
|
||
}
|
||
|
||
#new-menu-item-row .form-select-sm {
|
||
padding: 0.3rem 1.5rem 0.3rem 0.6rem; /* 微调 select 内边距以适应箭头 */
|
||
font-size: 0.875rem;
|
||
}
|
||
|
||
.action-buttons-new-menu .btn {
|
||
margin-right: 5px; /* 按钮间距 */
|
||
min-width: 80px; /* 给按钮一个最小宽度 */
|
||
}
|
||
|
||
.action-buttons-new-menu .btn:last-child {
|
||
margin-right: 0;
|
||
}
|
||
|
||
.action-buttons-new-menu .btn i {
|
||
margin-right: 4px; /* 图标和文字间距 */
|
||
}
|
||
|
||
/* 使新行单元格垂直居中 */
|
||
#new-menu-item-row td {
|
||
vertical-align: middle;
|
||
}
|
||
|
||
/* 直接覆盖#testResults.loading的样式,防止旋转 */
|
||
#network-test #testResults.loading {
|
||
animation: none !important;
|
||
border: none !important;
|
||
display: block !important;
|
||
position: relative !important;
|
||
text-align: center !important;
|
||
padding: 15px !important;
|
||
color: var(--text-secondary, #6c757d) !important;
|
||
font-size: 1rem !important;
|
||
width: auto !important;
|
||
height: auto !important;
|
||
}
|
||
|
||
/* 使用:before添加文本内容 */
|
||
#network-test #testResults.loading:before {
|
||
content: "测试进行中..." !important;
|
||
animation: none !important;
|
||
border: none !important;
|
||
position: absolute !important;
|
||
top: 50% !important;
|
||
left: 50% !important;
|
||
transform: translate(-50%, -50%) !important;
|
||
color: var(--text-light, #e9ecef) !important;
|
||
font-size: 1rem !important;
|
||
font-weight: 500 !important;
|
||
padding: 0 !important;
|
||
background-color: transparent !important;
|
||
z-index: 10 !important;
|
||
text-align: center !important;
|
||
}
|
||
|
||
#network-test .form-row {
|
||
display: flex;
|
||
flex-wrap: wrap; /* 允许换行到小屏幕 */
|
||
gap: 1.5rem; /* 各个元素之间的间距 */
|
||
margin-bottom: 1.5rem;
|
||
align-items: flex-end; /* 使得按钮和选择框底部对齐 */
|
||
}
|
||
|
||
#network-test .form-group {
|
||
flex: 1; /* 让表单组占据可用空间 */
|
||
min-width: 250px; /* 避免在小屏幕上过于挤压 */
|
||
background-color: transparent; /* 移除之前 #network-test .input-group 的背景色 */
|
||
padding: 0; /* 移除内边距 */
|
||
box-shadow: none; /* 移除阴影 */
|
||
border-radius: 0;
|
||
}
|
||
|
||
#network-test label {
|
||
display: block;
|
||
margin-bottom: 0.5rem;
|
||
color: var(--text-primary);
|
||
font-weight: 500;
|
||
font-size: 0.95rem;
|
||
}
|
||
|
||
#network-test .form-control,
|
||
#network-test .form-select {
|
||
width: 100%;
|
||
padding: 0.75rem 1rem;
|
||
border: 1px solid var(--border-color);
|
||
border-radius: var(--radius-md);
|
||
background-color: var(--input-bg, var(--container-bg)); /* 允许自定义输入背景或使用容器背景 */
|
||
color: var(--text-primary);
|
||
font-size: 0.95rem;
|
||
transition: all var(--transition-fast);
|
||
box-shadow: var(--shadow-sm);
|
||
}
|
||
|
||
#network-test .form-control:focus,
|
||
#network-test .form-select:focus {
|
||
border-color: var(--primary-color);
|
||
box-shadow: 0 0 0 3px rgba(var(--primary-rgb, 61, 124, 244), 0.25); /* 使用RGB变量 */
|
||
outline: none;
|
||
}
|
||
|
||
#network-test .test-controls-container {
|
||
/* 这个容器包裹选择器和按钮 */
|
||
display: flex;
|
||
flex-wrap: wrap; /* 允许换行 */
|
||
gap: 1rem; /* 控件之间的间距 */
|
||
align-items: flex-end; /* 使得按钮和选择框底部对齐 */
|
||
margin-bottom: 1.5rem;
|
||
}
|
||
|
||
#network-test .test-controls-container .form-group {
|
||
flex-grow: 1;
|
||
flex-basis: 200px; /* 给每个控件一个基础宽度 */
|
||
}
|
||
|
||
#network-test .start-test-btn {
|
||
padding: 0.75rem 1.5rem;
|
||
font-size: 1rem;
|
||
font-weight: 500;
|
||
white-space: nowrap; /* 防止按钮文字换行 */
|
||
height: fit-content; /* 与调整后的 select 高度匹配 */
|
||
flex-shrink: 0; /* 防止按钮在 flex 布局中被压缩 */
|
||
}
|
||
|
||
#network-test .start-test-btn i {
|
||
margin-right: 0.5rem;
|
||
}
|
||
|
||
.results-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 0.75rem;
|
||
padding: 0.5rem 0;
|
||
border-bottom: 1px solid var(--border-light);
|
||
}
|
||
|
||
.results-header h3 {
|
||
font-size: 1.1rem;
|
||
font-weight: 600;
|
||
color: var(--text-light, #e9ecef); /* Changed to light color for dark background */
|
||
margin: 0;
|
||
}
|
||
|
||
#clearTestResultsBtn {
|
||
font-size: 0.85rem;
|
||
padding: 0.3rem 0.8rem;
|
||
}
|
||
|
||
#testResultsContainer {
|
||
background-color: var(--container-bg-dark, #1e2532); /* 使用变量或默认暗色 */
|
||
border-radius: var(--radius-md);
|
||
box-shadow: var(--shadow-md);
|
||
margin-top: 1rem;
|
||
padding: 0; /* 移除外层padding,让头部和内容区自己控制 */
|
||
position: relative; /* Add this to be a positioning context for absolute children if needed by headers etc. */
|
||
}
|
||
|
||
#testResults {
|
||
padding: 1rem;
|
||
color: var(--text-light, #e9ecef);
|
||
font-family: var(--font-mono, 'JetBrains Mono', monospace);
|
||
font-size: 0.9rem;
|
||
white-space: pre-wrap;
|
||
word-break: break-all;
|
||
min-height: 200px;
|
||
max-height: 400px;
|
||
overflow-y: auto;
|
||
background-color: transparent;
|
||
border-radius: 0 0 var(--radius-md) var(--radius-md);
|
||
box-shadow: none;
|
||
border: none;
|
||
margin-top: 0;
|
||
position: relative;
|
||
}
|
||
|
||
/* Use higher specificity and !important to force override */
|
||
#network-test #testResults.loading::before {
|
||
content: "测试进行中..."; /* Force text content */
|
||
position: absolute;
|
||
top: 50%;
|
||
left: 50%;
|
||
transform: translate(-50%, -50%); /* Center the text block */
|
||
color: var(--text-secondary, #6c757d);
|
||
font-size: 1rem;
|
||
font-weight: 500;
|
||
padding: 0.75rem 1.25rem;
|
||
background-color: transparent !important;
|
||
border: none !important; /* 移除边框 */
|
||
border-radius: var(--radius-md, 0.375rem);
|
||
z-index: 10;
|
||
text-align: center;
|
||
/* Force removal of spinner styles */
|
||
animation: none !important;
|
||
border-top-color: transparent !important; /* Force override any spinner head */
|
||
width: auto !important; /* Force width */
|
||
height: auto !important; /* Force height */
|
||
box-sizing: border-box; /* Ensure padding is included correctly */
|
||
}
|
||
|
||
/* Ensure keyframes for the spinner are removed or commented out */
|
||
/* @keyframes testResultSpinner { to { transform: rotate(360deg); } } */
|
||
|
||
/* Style for the <pre> tag inside #testResults for consistent output formatting */
|
||
#testResults pre {
|
||
margin: 0; /* Remove default pre margin */
|
||
font-family: inherit; /* Inherit from #testResults (monospace) */
|
||
font-size: inherit; /* Inherit from #testResults */
|
||
color: inherit; /* Inherit from #testResults */
|
||
white-space: pre-wrap; /* Ensure wrapping */
|
||
word-break: break-all; /* Ensure long lines break */
|
||
background-color: transparent; /* Ensure no pre background interferes */
|
||
padding: 0; /* No extra padding for pre, parent div handles it */
|
||
}
|
||
|
||
#testResults pre.text-danger {
|
||
color: var(--danger-color, #dc3545); /* Ensure error text is colored */
|
||
}
|
||
|
||
/* Placeholder text styling (if using <p class="text-muted...">) */
|
||
#testResults .text-muted.text-center {
|
||
position: absolute;
|
||
top: 50%;
|
||
left: 50%;
|
||
transform: translate(-50%, -50%);
|
||
width: calc(100% - 2rem); /* Consider padding of #testResults */
|
||
}
|
||
|
||
/* 保持容器监控页面已停止容器列表的表头在鼠标悬停时背景色不变 */
|
||
#docker-monitoring .container-table th:hover {
|
||
background-color: var(--primary-color);
|
||
color: white;
|
||
}
|
||
|
||
/* SweetAlert2 弹窗内容文本居中 */
|
||
#swal2-html-container, /* 使用 ID 提高特异性 */
|
||
.swal2-html-container { /* 保留类选择器作为备用 */
|
||
text-align: center !important;
|
||
}
|
||
|
||
#swal2-html-container p,
|
||
.swal2-html-container p {
|
||
text-align: center !important;
|
||
}
|
||
|
||
#swal2-html-container div,
|
||
.swal2-html-container div {
|
||
text-align: center !important;
|
||
}
|
||
|
||
/* 下拉菜单样式修复 */
|
||
.btn-group {
|
||
position: relative;
|
||
display: inline-flex;
|
||
vertical-align: middle;
|
||
}
|
||
|
||
.dropdown-menu {
|
||
position: absolute;
|
||
z-index: 1050;
|
||
display: none;
|
||
min-width: 180px;
|
||
width: auto;
|
||
padding: 0;
|
||
margin: 0.325rem 0 0;
|
||
font-size: 0.9rem;
|
||
color: var(--text-primary);
|
||
text-align: left;
|
||
list-style: none;
|
||
background-color: #ffffff;
|
||
background-clip: padding-box;
|
||
border: 1px solid rgba(0, 0, 0, 0.08);
|
||
border-radius: 8px;
|
||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||
opacity: 0;
|
||
visibility: hidden;
|
||
transform: translateY(10px) scale(0.98);
|
||
transition: opacity 0.25s ease, transform 0.25s ease, visibility 0.25s ease;
|
||
}
|
||
|
||
.dropdown-menu.show {
|
||
display: block;
|
||
opacity: 1;
|
||
visibility: visible;
|
||
transform: translateY(0) scale(1);
|
||
}
|
||
|
||
/* 当下拉菜单在按钮右侧显示时 */
|
||
.dropdown-menu.dropdown-menu-right {
|
||
transform: translateX(10px) scale(0.98);
|
||
}
|
||
|
||
/* 当下拉菜单在按钮上方显示时 */
|
||
.dropdown-menu.dropdown-menu-top {
|
||
transform: translateY(-10px) scale(0.98);
|
||
}
|
||
|
||
/* 当下拉菜单在按钮右侧且显示时 */
|
||
.dropdown-menu.dropdown-menu-right.show {
|
||
transform: translateX(0) scale(1);
|
||
}
|
||
|
||
/* 当下拉菜单在按钮上方且显示时 */
|
||
.dropdown-menu.dropdown-menu-top.show {
|
||
transform: translateY(0) scale(1);
|
||
}
|
||
|
||
/* 右对齐的下拉菜单 */
|
||
.dropdown-menu-end {
|
||
right: 0;
|
||
left: auto;
|
||
}
|
||
|
||
.dropdown-header {
|
||
display: block;
|
||
padding: 0.5rem 1rem;
|
||
margin-bottom: 0;
|
||
font-size: 0.8rem;
|
||
color: #6c757d;
|
||
white-space: nowrap;
|
||
background-color: #f8f9fa;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.dropdown-menu .dropdown-item {
|
||
display: flex;
|
||
align-items: center;
|
||
width: 100%;
|
||
padding: 0.7rem 1.25rem;
|
||
clear: both;
|
||
font-weight: 400;
|
||
color: #495057;
|
||
text-align: inherit;
|
||
text-decoration: none;
|
||
white-space: nowrap;
|
||
background-color: transparent;
|
||
border: 0;
|
||
transition: all 0.2s ease;
|
||
}
|
||
|
||
.dropdown-menu .dropdown-item i {
|
||
margin-right: 10px;
|
||
width: 18px;
|
||
text-align: center;
|
||
font-size: 0.95rem;
|
||
opacity: 0.8;
|
||
}
|
||
|
||
.dropdown-menu .dropdown-item:hover,
|
||
.dropdown-menu .dropdown-item:focus {
|
||
color: #1e70eb;
|
||
background-color: #f1f7ff;
|
||
text-decoration: none;
|
||
}
|
||
|
||
.dropdown-menu .dropdown-item.active,
|
||
.dropdown-menu .dropdown-item:active {
|
||
background-color: #e8f1ff;
|
||
color: #1e70eb;
|
||
}
|
||
|
||
.dropdown-menu .dropdown-item:hover i,
|
||
.dropdown-menu .dropdown-item:focus i {
|
||
opacity: 1;
|
||
}
|
||
|
||
.dropdown-divider {
|
||
height: 0;
|
||
margin: 0;
|
||
overflow: hidden;
|
||
border-top: 1px solid rgba(0, 0, 0, 0.05);
|
||
}
|
||
|
||
/* 美化操作按钮 */
|
||
.action-cell .btn-group .btn-primary {
|
||
background: linear-gradient(to bottom, #4a7bff, #3d66e3);
|
||
border: none;
|
||
box-shadow: 0 2px 5px rgba(61, 124, 244, 0.2);
|
||
padding: 0.45rem 1rem;
|
||
font-weight: 500;
|
||
transition: all 0.2s ease;
|
||
border-radius: 6px;
|
||
}
|
||
|
||
.action-cell .btn-group .btn-primary:hover {
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 4px 8px rgba(61, 124, 244, 0.3);
|
||
background: linear-gradient(to bottom, #5a88ff, #4a7bff);
|
||
}
|
||
|
||
.action-cell .btn-group .btn-primary:active {
|
||
transform: translateY(0);
|
||
}
|
||
|
||
/* 右对齐的下拉菜单 */
|
||
.dropdown-menu-end {
|
||
right: 0;
|
||
left: auto;
|
||
}
|
||
|
||
/* 美化表格中的操作列,确保有足够空间显示弹出菜单 */
|
||
.action-cell {
|
||
min-width: 120px;
|
||
position: relative;
|
||
}
|
||
|
||
/* 确保菜单项样式美观 */
|
||
.dropdown-item {
|
||
display: flex;
|
||
align-items: center;
|
||
width: 100%;
|
||
padding: 0.7rem 1.25rem;
|
||
clear: both;
|
||
font-weight: 400;
|
||
color: #495057;
|
||
text-align: inherit;
|
||
text-decoration: none;
|
||
white-space: nowrap;
|
||
background-color: transparent;
|
||
border: 0;
|
||
transition: all 0.2s ease;
|
||
}
|
||
|
||
.dropdown-item i {
|
||
margin-right: 10px;
|
||
width: 18px;
|
||
text-align: center;
|
||
font-size: 0.95rem;
|
||
opacity: 0.8;
|
||
}
|
||
|
||
.dropdown-item:hover, .dropdown-item:focus {
|
||
color: #1e70eb;
|
||
background-color: rgba(30, 112, 235, 0.08);
|
||
text-decoration: none;
|
||
}
|
||
|
||
.dropdown-item:hover i, .dropdown-item:focus i {
|
||
opacity: 1;
|
||
}
|
||
|
||
.dropdown-divider {
|
||
height: 0;
|
||
margin: 0.5rem 0;
|
||
overflow: hidden;
|
||
border-top: 1px solid rgba(0, 0, 0, 0.05);
|
||
}
|
||
|
||
/* 菜单项图标美化 */
|
||
.dropdown-item .fa-file-alt {
|
||
color: #17a2b8;
|
||
}
|
||
|
||
.dropdown-item .fa-info-circle {
|
||
color: #6c757d;
|
||
}
|
||
|
||
.dropdown-item .fa-stop {
|
||
color: #dc3545;
|
||
}
|
||
|
||
.dropdown-item .fa-play {
|
||
color: #28a745;
|
||
}
|
||
|
||
.dropdown-item .fa-sync-alt {
|
||
color: #ffc107;
|
||
}
|
||
|
||
.dropdown-item .fa-trash-alt {
|
||
color: #dc3545;
|
||
}
|
||
|
||
.dropdown-item .fa-cloud-download-alt {
|
||
color: #17a2b8;
|
||
}
|
||
|
||
/* 原生select下拉框样式美化 */
|
||
.simple-dropdown {
|
||
appearance: none;
|
||
-webkit-appearance: none;
|
||
-moz-appearance: none;
|
||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23495057' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
|
||
background-repeat: no-repeat;
|
||
background-position: right 0.75rem center;
|
||
background-size: 12px;
|
||
width: 100%;
|
||
padding: 0.45rem 2rem 0.45rem 0.75rem;
|
||
font-size: 0.875rem;
|
||
font-weight: 400;
|
||
color: #495057;
|
||
border: 1px solid #ced4da;
|
||
border-radius: 6px;
|
||
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
||
transition: all 0.2s ease-in-out;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.simple-dropdown:focus {
|
||
border-color: #80bdff;
|
||
outline: 0;
|
||
box-shadow: 0 0 0 0.2rem rgba(0,123,255,0.25);
|
||
}
|
||
|
||
.simple-dropdown:hover {
|
||
border-color: #adb5bd;
|
||
}
|
||
|
||
.simple-dropdown optgroup {
|
||
font-weight: 600;
|
||
color: #343a40;
|
||
background-color: #f8f9fa;
|
||
padding: 5px;
|
||
}
|
||
|
||
.simple-dropdown option {
|
||
font-weight: normal;
|
||
padding: 8px;
|
||
background-color: #fff;
|
||
color: #495057;
|
||
}
|
||
|
||
.simple-dropdown option:hover,
|
||
.simple-dropdown option:focus {
|
||
background-color: #f1f7ff;
|
||
color: #1e70eb;
|
||
}
|
||
|
||
/* Action按钮样式保留,以便保持兼容 */
|
||
.action-cell .btn-group {
|
||
display: inline-block;
|
||
width: 100%;
|
||
}
|
||
|
||
.action-cell .btn-group .btn-primary {
|
||
display: none; /* 隐藏原始按钮,由select替代 */
|
||
}
|
||
|
||
/* ==================== 页面美化样式 ==================== */
|
||
|
||
/* 统一页面头部样式 */
|
||
.page-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: flex-start;
|
||
margin-bottom: 2rem;
|
||
padding-bottom: 1.5rem;
|
||
border-bottom: 2px solid var(--border-light, #e5e7eb);
|
||
}
|
||
|
||
.page-header-content {
|
||
flex: 1;
|
||
text-align: left;
|
||
}
|
||
|
||
.page-title {
|
||
font-size: 1.75rem;
|
||
font-weight: 700;
|
||
color: var(--text-primary);
|
||
margin: 0 0 0.5rem 0;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.75rem;
|
||
}
|
||
|
||
.page-title i {
|
||
font-size: 1.5rem;
|
||
color: var(--primary-color);
|
||
opacity: 0.9;
|
||
}
|
||
|
||
.page-subtitle {
|
||
font-size: 0.95rem;
|
||
color: var(--text-secondary);
|
||
margin: 0;
|
||
text-align: left;
|
||
padding-left: 0;
|
||
}
|
||
|
||
/* 配置卡片网格 */
|
||
.config-cards-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
|
||
gap: 1.5rem;
|
||
}
|
||
|
||
.monitoring-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
|
||
gap: 1.5rem;
|
||
}
|
||
|
||
.config-card {
|
||
background: var(--container-bg);
|
||
border-radius: var(--radius-lg);
|
||
box-shadow: var(--shadow-md);
|
||
overflow: hidden;
|
||
transition: all var(--transition-normal);
|
||
border: 1px solid var(--border-light, #e5e7eb);
|
||
}
|
||
|
||
.config-card:hover {
|
||
box-shadow: var(--shadow-lg);
|
||
transform: translateY(-2px);
|
||
}
|
||
|
||
.config-card.full-width {
|
||
grid-column: 1 / -1;
|
||
}
|
||
|
||
.config-card-header {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 1rem;
|
||
padding: 1.25rem 1.5rem;
|
||
background: linear-gradient(135deg, rgba(61, 124, 244, 0.05) 0%, rgba(61, 124, 244, 0.02) 100%);
|
||
border-bottom: 1px solid var(--border-light, #e5e7eb);
|
||
}
|
||
|
||
.config-card-icon {
|
||
width: 50px;
|
||
height: 50px;
|
||
border-radius: 12px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 1.25rem;
|
||
color: white;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.config-card-icon.purple {
|
||
background: linear-gradient(135deg, #8b5cf6, #a78bfa);
|
||
}
|
||
|
||
.config-card-icon.blue {
|
||
background: linear-gradient(135deg, #3d7cf4, #6366f1);
|
||
}
|
||
|
||
.config-card-icon.green {
|
||
background: linear-gradient(135deg, #10b981, #34d399);
|
||
}
|
||
|
||
.config-card-icon.red {
|
||
background: linear-gradient(135deg, #ef4444, #f87171);
|
||
}
|
||
|
||
.config-card-icon.orange {
|
||
background: linear-gradient(135deg, #f59e0b, #fbbf24);
|
||
}
|
||
|
||
.config-card-title h3 {
|
||
font-size: 1.1rem;
|
||
font-weight: 600;
|
||
color: var(--text-primary);
|
||
margin: 0 0 0.25rem 0;
|
||
}
|
||
|
||
.config-card-title p {
|
||
font-size: 0.85rem;
|
||
color: var(--text-secondary);
|
||
margin: 0;
|
||
}
|
||
|
||
.config-card-body {
|
||
padding: 1.5rem;
|
||
}
|
||
|
||
/* 现代表单样式 */
|
||
.modern-form-group {
|
||
margin-bottom: 1.25rem;
|
||
}
|
||
|
||
.modern-form-group label {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
font-size: 0.9rem;
|
||
font-weight: 500;
|
||
color: var(--text-primary);
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
|
||
.modern-form-group label i {
|
||
font-size: 0.85rem;
|
||
color: var(--primary-color);
|
||
opacity: 0.7;
|
||
}
|
||
|
||
.required-badge {
|
||
font-size: 0.7rem;
|
||
font-weight: 500;
|
||
padding: 0.15rem 0.5rem;
|
||
background: linear-gradient(135deg, #ef4444, #f87171);
|
||
color: white;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
.modern-input {
|
||
width: 100%;
|
||
padding: 0.75rem 1rem;
|
||
border: 1px solid var(--border-color);
|
||
border-radius: var(--radius-md);
|
||
background-color: var(--input-bg, #fff);
|
||
color: var(--text-primary);
|
||
font-size: 0.95rem;
|
||
transition: all var(--transition-fast);
|
||
box-shadow: var(--shadow-sm);
|
||
}
|
||
|
||
.modern-input:focus {
|
||
border-color: var(--primary-color);
|
||
box-shadow: 0 0 0 3px rgba(61, 124, 244, 0.15);
|
||
outline: none;
|
||
}
|
||
|
||
.modern-input::placeholder {
|
||
color: var(--text-secondary);
|
||
opacity: 0.7;
|
||
}
|
||
|
||
.input-hint {
|
||
display: block;
|
||
font-size: 0.8rem;
|
||
color: var(--text-secondary);
|
||
margin-top: 0.5rem;
|
||
}
|
||
|
||
/* 带图标的按钮 */
|
||
.btn-with-icon {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
padding: 0.65rem 1.25rem;
|
||
font-weight: 500;
|
||
border-radius: var(--radius-md);
|
||
transition: all var(--transition-fast);
|
||
}
|
||
|
||
.btn-with-icon i {
|
||
font-size: 0.9rem;
|
||
}
|
||
|
||
/* 按钮组现代样式 */
|
||
.button-group-modern {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 0.75rem;
|
||
margin-top: 1.5rem;
|
||
}
|
||
|
||
/* 表格容器样式 */
|
||
.table-container {
|
||
background: white;
|
||
border-radius: 16px;
|
||
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.03), 0 2px 4px rgba(0, 0, 0, 0.05);
|
||
overflow: hidden;
|
||
margin-top: 1.5rem;
|
||
}
|
||
|
||
.table-container .table-responsive {
|
||
padding: 0;
|
||
}
|
||
|
||
/* 现代表格样式 - 2024主流设计 */
|
||
.modern-table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
border-spacing: 0;
|
||
}
|
||
|
||
.modern-table thead {
|
||
background: transparent;
|
||
}
|
||
|
||
.modern-table th {
|
||
padding: 14px 20px;
|
||
text-align: left;
|
||
font-weight: 500;
|
||
color: #6b7280;
|
||
font-size: 12px;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.5px;
|
||
border-bottom: 1px solid #f3f4f6;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.modern-table th:first-child {
|
||
padding-left: 24px;
|
||
}
|
||
|
||
.modern-table th:last-child {
|
||
padding-right: 24px;
|
||
}
|
||
|
||
.modern-table td {
|
||
padding: 16px 20px;
|
||
vertical-align: middle;
|
||
color: #111827;
|
||
font-size: 14px;
|
||
border-bottom: 1px solid #f9fafb;
|
||
}
|
||
|
||
.modern-table td:first-child {
|
||
padding-left: 24px;
|
||
}
|
||
|
||
.modern-table td:last-child {
|
||
padding-right: 24px;
|
||
}
|
||
|
||
.modern-table tbody tr {
|
||
transition: background-color 0.1s ease;
|
||
}
|
||
|
||
.modern-table tbody tr:hover {
|
||
background-color: #fafbfc;
|
||
}
|
||
|
||
.modern-table tbody tr:last-child td {
|
||
border-bottom: none;
|
||
}
|
||
|
||
/* 表格操作按钮样式 - 现代风格 */
|
||
.modern-table .action-buttons {
|
||
display: flex;
|
||
gap: 8px;
|
||
justify-content: flex-start;
|
||
}
|
||
|
||
.modern-table .action-btn {
|
||
width: 34px;
|
||
height: 34px;
|
||
border-radius: 8px;
|
||
border: none;
|
||
cursor: pointer;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
transition: all 0.15s ease;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.modern-table .action-btn.edit-btn {
|
||
background: #f0f9ff;
|
||
color: #0ea5e9;
|
||
}
|
||
|
||
.modern-table .action-btn.edit-btn:hover {
|
||
background: #0ea5e9;
|
||
color: white;
|
||
}
|
||
|
||
.modern-table .action-btn.delete-btn {
|
||
background: #fef2f2;
|
||
color: #ef4444;
|
||
}
|
||
|
||
.modern-table .action-btn.delete-btn:hover {
|
||
background: #ef4444;
|
||
color: white;
|
||
}
|
||
|
||
.modern-table .action-btn.view-btn {
|
||
background: #f0fdf4;
|
||
color: #22c55e;
|
||
}
|
||
|
||
.modern-table .action-btn.view-btn:hover {
|
||
background: #22c55e;
|
||
color: white;
|
||
}
|
||
|
||
/* 表格序号和链接展示 */
|
||
.table-row-num {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 28px;
|
||
height: 28px;
|
||
background: #f3f4f6;
|
||
color: #6b7280;
|
||
border-radius: 6px;
|
||
font-size: 12px;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.menu-link-display {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
padding: 6px 12px;
|
||
background: #f8fafc;
|
||
border-radius: 6px;
|
||
font-size: 13px;
|
||
color: #475569;
|
||
font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Fira Code', monospace;
|
||
max-width: 200px;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.menu-link-display i {
|
||
color: #94a3b8;
|
||
font-size: 11px;
|
||
}
|
||
|
||
/* 表格空状态 */
|
||
.table-empty-state {
|
||
text-align: center;
|
||
padding: 48px 24px;
|
||
color: #9ca3af;
|
||
}
|
||
|
||
.table-empty-state i {
|
||
font-size: 40px;
|
||
margin-bottom: 16px;
|
||
opacity: 0.5;
|
||
}
|
||
|
||
.table-empty-state p {
|
||
font-size: 14px;
|
||
margin: 0;
|
||
}
|
||
|
||
/* 新增菜单行样式 */
|
||
#new-menu-item-row,
|
||
.new-item-row {
|
||
background: #f0fdf4 !important;
|
||
}
|
||
|
||
#new-menu-item-row td,
|
||
.new-item-row td {
|
||
padding: 14px 20px !important;
|
||
border-bottom: 1px dashed #86efac !important;
|
||
background: transparent !important;
|
||
}
|
||
|
||
#new-menu-item-row input,
|
||
#new-menu-item-row select,
|
||
.new-item-row input,
|
||
.new-item-row select {
|
||
padding: 10px 14px;
|
||
border: 1px solid #e5e7eb;
|
||
border-radius: 8px;
|
||
font-size: 14px;
|
||
transition: all 0.15s ease;
|
||
background: white;
|
||
}
|
||
|
||
#new-menu-item-row input:focus,
|
||
#new-menu-item-row select:focus,
|
||
.new-item-row input:focus,
|
||
.new-item-row select:focus {
|
||
border-color: #22c55e;
|
||
box-shadow: 0 0 0 3px rgba(34, 197, 94, 0.1);
|
||
outline: none;
|
||
}
|
||
|
||
.action-buttons-new-menu {
|
||
display: flex;
|
||
gap: 8px;
|
||
}
|
||
|
||
.action-buttons-new-menu .btn {
|
||
padding: 8px 16px;
|
||
border-radius: 8px;
|
||
font-size: 13px;
|
||
font-weight: 500;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
transition: all 0.15s ease;
|
||
}
|
||
|
||
.save-new-menu-btn {
|
||
background: #22c55e !important;
|
||
border: none !important;
|
||
color: white !important;
|
||
}
|
||
|
||
.save-new-menu-btn:hover {
|
||
background: #16a34a !important;
|
||
}
|
||
|
||
.cancel-new-menu-btn {
|
||
background: #f3f4f6 !important;
|
||
border: 1px solid #e5e7eb !important;
|
||
color: #6b7280 !important;
|
||
}
|
||
|
||
.cancel-new-menu-btn:hover {
|
||
background: #ef4444 !important;
|
||
border-color: transparent !important;
|
||
color: white !important;
|
||
}
|
||
|
||
/* 编辑行样式 */
|
||
.editing-row {
|
||
background: #fffbeb !important;
|
||
}
|
||
|
||
.editing-row td {
|
||
border-bottom: 1px dashed #fbbf24 !important;
|
||
background: transparent !important;
|
||
}
|
||
|
||
.editing-row input,
|
||
.editing-row select {
|
||
padding: 10px 14px;
|
||
border: 1px solid #e5e7eb;
|
||
border-radius: 8px;
|
||
font-size: 14px;
|
||
transition: all 0.15s ease;
|
||
background: white;
|
||
}
|
||
|
||
.editing-row input:focus,
|
||
.editing-row select:focus {
|
||
border-color: #f59e0b;
|
||
box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.1);
|
||
outline: none;
|
||
}
|
||
|
||
/* 表格加载状态 */
|
||
.table-loading {
|
||
text-align: center;
|
||
padding: 32px;
|
||
color: #9ca3af;
|
||
}
|
||
|
||
.table-loading i {
|
||
color: #3b82f6;
|
||
margin-right: 8px;
|
||
}
|
||
|
||
/* 文档管理特殊样式 */
|
||
#documentTable .doc-title {
|
||
font-weight: 500;
|
||
color: #111827;
|
||
}
|
||
|
||
#documentTable .doc-path {
|
||
font-family: 'SF Mono', 'Monaco', 'Inconsolata', monospace;
|
||
font-size: 13px;
|
||
color: #6b7280;
|
||
background: #f3f4f6;
|
||
padding: 5px 10px;
|
||
border-radius: 6px;
|
||
}
|
||
|
||
#documentTable .doc-date,
|
||
.doc-date {
|
||
font-size: 13px;
|
||
color: #6b7280;
|
||
}
|
||
|
||
.doc-title-display {
|
||
font-weight: 500;
|
||
color: #111827;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.doc-status-badge {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 5px 10px;
|
||
border-radius: 20px;
|
||
font-size: 12px;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.doc-status-badge.published {
|
||
background: #dcfce7;
|
||
color: #16a34a;
|
||
}
|
||
|
||
.doc-status-badge.draft {
|
||
background: #fefce8;
|
||
color: #ca8a04;
|
||
}
|
||
|
||
/* 发布/取消发布按钮 */
|
||
.modern-table .action-btn.publish-btn {
|
||
background: #f0fdf4;
|
||
color: #22c55e;
|
||
}
|
||
|
||
.modern-table .action-btn.publish-btn:hover {
|
||
background: #22c55e;
|
||
color: white;
|
||
}
|
||
|
||
.modern-table .action-btn.unpublish-btn {
|
||
background: #fefce8;
|
||
color: #eab308;
|
||
}
|
||
|
||
.modern-table .action-btn.unpublish-btn:hover {
|
||
background: #eab308;
|
||
color: white;
|
||
}
|
||
|
||
/* 菜单管理表格特殊样式 */
|
||
.menu-text-display {
|
||
font-weight: 500;
|
||
color: #111827;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.menu-newtab-badge {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 5px 10px;
|
||
border-radius: 20px;
|
||
font-size: 12px;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.menu-newtab-badge.yes {
|
||
background: #dcfce7;
|
||
color: #16a34a;
|
||
}
|
||
|
||
.menu-newtab-badge.no {
|
||
background: #f3f4f6;
|
||
color: #6b7280;
|
||
}
|
||
|
||
/* 容器表格专用样式 */
|
||
.container-id-cell {
|
||
font-family: 'SF Mono', 'Monaco', 'Inconsolata', monospace;
|
||
font-size: 13px;
|
||
color: #64748b;
|
||
background: #f3f4f6;
|
||
padding: 6px 10px;
|
||
border-radius: 6px;
|
||
display: inline-block;
|
||
}
|
||
|
||
.container-name-cell {
|
||
font-weight: 500;
|
||
color: #111827;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
}
|
||
|
||
.container-name-cell::before {
|
||
content: '';
|
||
width: 6px;
|
||
height: 6px;
|
||
border-radius: 50%;
|
||
background: #ef4444;
|
||
display: inline-block;
|
||
}
|
||
|
||
.container-image-cell {
|
||
font-family: 'SF Mono', 'Monaco', 'Inconsolata', monospace;
|
||
font-size: 13px;
|
||
color: #0284c7;
|
||
background: #f0f9ff;
|
||
padding: 6px 10px;
|
||
border-radius: 6px;
|
||
display: inline-block;
|
||
max-width: 200px;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.container-status-badge {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
padding: 5px 10px;
|
||
border-radius: 20px;
|
||
font-size: 12px;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.container-status-badge.stopped {
|
||
background: #fef2f2;
|
||
color: #dc2626;
|
||
}
|
||
|
||
.container-status-badge.running {
|
||
background: #dcfce7;
|
||
color: #16a34a;
|
||
}
|
||
|
||
.container-status-badge.paused {
|
||
background: #fefce8;
|
||
color: #ca8a04;
|
||
}
|
||
|
||
.container-status-badge i {
|
||
font-size: 8px;
|
||
}
|
||
|
||
/* 空容器状态 */
|
||
.stopped-containers-empty {
|
||
text-align: center;
|
||
padding: 48px 24px;
|
||
background: linear-gradient(135deg, #f0fdf4, #dcfce7);
|
||
border-radius: 0 0 16px 16px;
|
||
}
|
||
|
||
.stopped-containers-empty i {
|
||
font-size: 48px;
|
||
color: #22c55e;
|
||
margin-bottom: 12px;
|
||
display: block;
|
||
}
|
||
|
||
.stopped-containers-empty p {
|
||
color: #16a34a;
|
||
font-weight: 600;
|
||
font-size: 15px;
|
||
margin: 0;
|
||
}
|
||
|
||
/* 测试控制卡片 */
|
||
.test-controls-card {
|
||
background: var(--container-bg);
|
||
border-radius: var(--radius-lg);
|
||
padding: 1.5rem;
|
||
box-shadow: var(--shadow-md);
|
||
border: 1px solid var(--border-light, #e5e7eb);
|
||
margin-bottom: 1.5rem;
|
||
}
|
||
|
||
.test-controls-card .test-controls-container {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 1.25rem;
|
||
align-items: flex-end;
|
||
}
|
||
|
||
.test-controls-card .form-group {
|
||
flex: 1;
|
||
min-width: 200px;
|
||
}
|
||
|
||
.test-controls-card .form-group label {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
font-size: 0.9rem;
|
||
font-weight: 500;
|
||
color: var(--text-primary);
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
|
||
.test-controls-card .form-group label i {
|
||
font-size: 0.85rem;
|
||
color: var(--primary-color);
|
||
opacity: 0.7;
|
||
}
|
||
|
||
.test-controls-card .form-select,
|
||
.test-controls-card .form-control {
|
||
width: 100%;
|
||
padding: 0.75rem 1rem;
|
||
border: 1px solid var(--border-color);
|
||
border-radius: var(--radius-md);
|
||
font-size: 0.95rem;
|
||
transition: all var(--transition-fast);
|
||
background-color: var(--input-bg, #fff);
|
||
}
|
||
|
||
.test-controls-card .form-select:focus,
|
||
.test-controls-card .form-control:focus {
|
||
border-color: var(--primary-color);
|
||
box-shadow: 0 0 0 3px rgba(61, 124, 244, 0.15);
|
||
outline: none;
|
||
}
|
||
|
||
.test-controls-card .start-test-btn {
|
||
flex-shrink: 0;
|
||
padding: 0.75rem 1.5rem;
|
||
font-size: 1rem;
|
||
font-weight: 500;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
}
|
||
|
||
/* 测试结果容器美化 */
|
||
#testResultsContainer {
|
||
background: var(--container-bg-dark, #1e2532);
|
||
border-radius: var(--radius-lg);
|
||
box-shadow: var(--shadow-lg);
|
||
overflow: hidden;
|
||
}
|
||
|
||
#testResultsContainer .results-header {
|
||
background: linear-gradient(135deg, rgba(61, 124, 244, 0.1) 0%, rgba(99, 102, 241, 0.1) 100%);
|
||
padding: 1rem 1.25rem;
|
||
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
#testResultsContainer .results-header h3 {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
color: var(--text-light, #e9ecef);
|
||
}
|
||
|
||
#testResultsContainer .results-header h3 i {
|
||
color: var(--primary-color);
|
||
}
|
||
|
||
/* 监控状态徽章 */
|
||
.monitoring-status-badge {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
background: var(--container-bg);
|
||
padding: 0.5rem 1rem;
|
||
border-radius: var(--radius-md);
|
||
font-size: 0.9rem;
|
||
box-shadow: var(--shadow-sm);
|
||
border: 1px solid var(--border-light, #e5e7eb);
|
||
}
|
||
|
||
.monitoring-status-badge .status-indicator {
|
||
font-weight: 600;
|
||
}
|
||
|
||
.monitoring-status-badge .status-indicator.running {
|
||
color: var(--success-color);
|
||
}
|
||
|
||
.monitoring-status-badge .status-indicator.stopped {
|
||
color: var(--danger-color);
|
||
}
|
||
|
||
/* Docker 监控配置页面样式 */
|
||
.monitoring-config-card {
|
||
margin-bottom: 1.5rem;
|
||
}
|
||
|
||
.monitoring-form-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||
gap: 2rem;
|
||
}
|
||
|
||
.monitoring-form-section {
|
||
padding: 0;
|
||
}
|
||
|
||
.form-section-title {
|
||
font-size: 1rem;
|
||
font-weight: 600;
|
||
color: var(--text-primary);
|
||
margin: 0 0 1.25rem 0;
|
||
padding-bottom: 0.75rem;
|
||
border-bottom: 2px solid var(--border-light, #e5e7eb);
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
}
|
||
|
||
.form-section-title i {
|
||
color: var(--primary-color);
|
||
font-size: 0.9rem;
|
||
}
|
||
|
||
.monitoring-info-box {
|
||
display: flex;
|
||
gap: 1rem;
|
||
background: linear-gradient(135deg, rgba(61, 124, 244, 0.08), rgba(99, 102, 241, 0.05));
|
||
border: 1px solid rgba(61, 124, 244, 0.15);
|
||
border-radius: var(--radius-md);
|
||
padding: 1rem;
|
||
margin-top: 1.25rem;
|
||
}
|
||
|
||
.info-box-icon {
|
||
flex-shrink: 0;
|
||
width: 40px;
|
||
height: 40px;
|
||
border-radius: 10px;
|
||
background: linear-gradient(135deg, var(--primary-color), #6366f1);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: white;
|
||
font-size: 1rem;
|
||
}
|
||
|
||
.info-box-content h5 {
|
||
font-size: 0.9rem;
|
||
font-weight: 600;
|
||
color: var(--text-primary);
|
||
margin: 0 0 0.35rem 0;
|
||
}
|
||
|
||
.info-box-content p {
|
||
font-size: 0.85rem;
|
||
color: var(--text-secondary);
|
||
margin: 0;
|
||
line-height: 1.5;
|
||
}
|
||
|
||
.monitoring-actions {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 0.75rem;
|
||
margin-top: 2rem;
|
||
padding-top: 1.5rem;
|
||
border-top: 1px solid var(--border-light, #e5e7eb);
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.monitoring-form-grid {
|
||
grid-template-columns: 1fr;
|
||
gap: 1.5rem;
|
||
}
|
||
|
||
.monitoring-actions {
|
||
flex-direction: column;
|
||
}
|
||
|
||
.monitoring-actions .btn {
|
||
width: 100%;
|
||
justify-content: center;
|
||
}
|
||
}
|
||
|
||
/* 登录页面表单美化 */
|
||
.forgot-password-link {
|
||
text-align: center;
|
||
margin-top: 1.25rem;
|
||
}
|
||
|
||
.forgot-password-link a {
|
||
color: var(--primary-color);
|
||
text-decoration: none;
|
||
font-size: 0.9rem;
|
||
font-weight: 500;
|
||
transition: all var(--transition-fast);
|
||
}
|
||
|
||
.forgot-password-link a:hover {
|
||
color: var(--primary-dark);
|
||
text-decoration: underline;
|
||
}
|
||
|
||
.form-description {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 0.5rem;
|
||
text-align: center;
|
||
margin-bottom: 1.25rem;
|
||
padding: 1rem;
|
||
background: linear-gradient(135deg, rgba(61, 124, 244, 0.08), rgba(99, 102, 241, 0.05));
|
||
border-radius: var(--radius-md);
|
||
color: var(--text-secondary);
|
||
font-size: 0.9rem;
|
||
border: 1px solid rgba(61, 124, 244, 0.1);
|
||
}
|
||
|
||
.form-description i {
|
||
color: var(--primary-color);
|
||
font-size: 1rem;
|
||
}
|
||
|
||
.token-display {
|
||
background: linear-gradient(135deg, #f0f9ff, #e0f2fe);
|
||
padding: 1rem;
|
||
border-radius: var(--radius-md);
|
||
margin-bottom: 1rem;
|
||
border: 1px solid rgba(61, 124, 244, 0.2);
|
||
display: none;
|
||
}
|
||
|
||
.token-label {
|
||
font-size: 0.8rem;
|
||
font-weight: 600;
|
||
color: var(--primary-color);
|
||
margin-bottom: 0.5rem;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.4rem;
|
||
}
|
||
|
||
.token-value {
|
||
font-family: 'Courier New', monospace;
|
||
font-size: 0.85rem;
|
||
word-break: break-all;
|
||
background: white;
|
||
padding: 0.5rem 0.75rem;
|
||
border-radius: 4px;
|
||
border: 1px solid rgba(61, 124, 244, 0.1);
|
||
}
|
||
|
||
.password-requirements {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
font-size: 0.8rem;
|
||
color: var(--text-secondary);
|
||
margin-bottom: 1rem;
|
||
padding: 0.75rem;
|
||
background: rgba(245, 158, 11, 0.08);
|
||
border-radius: var(--radius-md);
|
||
border: 1px solid rgba(245, 158, 11, 0.15);
|
||
}
|
||
|
||
.password-requirements i {
|
||
color: #f59e0b;
|
||
}
|
||
|
||
.back-to-login {
|
||
text-align: center;
|
||
margin-top: 1.25rem;
|
||
}
|
||
|
||
.back-to-login a {
|
||
color: var(--primary-color);
|
||
text-decoration: none;
|
||
font-size: 0.9rem;
|
||
font-weight: 500;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.4rem;
|
||
transition: all var(--transition-fast);
|
||
}
|
||
|
||
.back-to-login a:hover {
|
||
color: var(--primary-dark);
|
||
}
|
||
|
||
.back-to-login a i {
|
||
transition: transform var(--transition-fast);
|
||
}
|
||
|
||
.back-to-login a:hover i {
|
||
transform: translateX(-3px);
|
||
}
|
||
|
||
/* 响应式调整 */
|
||
@media (max-width: 768px) {
|
||
.page-header {
|
||
flex-direction: column;
|
||
gap: 1rem;
|
||
}
|
||
|
||
.page-header .btn-with-icon {
|
||
width: 100%;
|
||
justify-content: center;
|
||
}
|
||
|
||
.config-cards-grid,
|
||
.monitoring-grid {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.test-controls-card .test-controls-container {
|
||
flex-direction: column;
|
||
}
|
||
|
||
.test-controls-card .form-group {
|
||
width: 100%;
|
||
}
|
||
|
||
.test-controls-card .start-test-btn {
|
||
width: 100%;
|
||
justify-content: center;
|
||
}
|
||
|
||
.button-group-modern {
|
||
flex-direction: column;
|
||
}
|
||
|
||
.button-group-modern .btn-with-icon {
|
||
width: 100%;
|
||
justify-content: center;
|
||
}
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div id="loadingSpinner" class="loading-spinner" style="display: none;"></div>
|
||
<div id="loadingIndicator" style="display: flex; justify-content: center; align-items: center; height: 100vh;">
|
||
<p>加载中...</p>
|
||
</div>
|
||
<div class="admin-container" id="adminContainer" style="display: none;">
|
||
<div class="sidebar">
|
||
<div class="sidebar-header">
|
||
<h2><i class="fas fa-cogs"></i>管理面板</h2>
|
||
</div>
|
||
<div class="user-profile">
|
||
<div class="user-avatar">
|
||
<i class="fas fa-user"></i>
|
||
</div>
|
||
<div class="user-info">
|
||
<div class="user-name" id="currentUsername">管理员</div>
|
||
<div class="user-role">系统管理员</div>
|
||
</div>
|
||
<div class="user-actions">
|
||
<div class="user-action-btn" id="userCenterBtn">个人中心</div>
|
||
<div class="user-action-btn logout" id="logoutBtn">退出登录</div>
|
||
</div>
|
||
</div>
|
||
<ul class="sidebar-nav">
|
||
<li data-section="dashboard" class="active">
|
||
<i class="fas fa-tachometer-alt"></i>控制面板
|
||
</li>
|
||
<li data-section="basic-config">
|
||
<i class="fas fa-wrench"></i>基本配置
|
||
</li>
|
||
<li data-section="menu-management">
|
||
<i class="fas fa-bars"></i>菜单管理
|
||
</li>
|
||
<li data-section="documentation-management">
|
||
<i class="fas fa-file-alt"></i>文档管理
|
||
</li>
|
||
<li data-section="network-test">
|
||
<i class="fas fa-network-wired"></i>网络测试
|
||
</li>
|
||
<li data-section="docker-status">
|
||
<i class="fab fa-docker"></i>容器管理
|
||
</li>
|
||
<li data-section="docker-monitoring">
|
||
<i class="fas fa-chart-line"></i>容器监控
|
||
</li>
|
||
<li data-section="user-center">
|
||
<i class="fas fa-user-cog"></i>用户中心
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
<div class="content-area">
|
||
<div class="container">
|
||
<!-- 控制面板 -->
|
||
<div id="dashboard" class="content-section active">
|
||
<div class="welcome-banner">
|
||
<div class="welcome-content">
|
||
<h1 class="welcome-title">欢迎回来,<span id="welcomeUsername">管理员</span>!</h1>
|
||
<p class="welcome-subtitle">这里是 Docker 镜像代理加速系统控制面板</p>
|
||
<button class="welcome-action" id="refreshSystemBtn">
|
||
<i class="fas fa-sync-alt"></i> 刷新系统状态
|
||
</button>
|
||
</div>
|
||
|
||
<div class="docker-status" id="dockerStatusIndicator" style="position: absolute; top: 10px; right: 10px; padding: 5px 10px; border-radius: 4px; font-size: 0.9rem; color: white;">
|
||
<i class="fab fa-docker"></i>
|
||
<span id="dockerStatusText">正在检查...</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="dashboard-grid">
|
||
<!-- 仪表板卡片将由 systemStatus.initDashboard() 动态生成 -->
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 基本配置 -->
|
||
<div id="basic-config" class="content-section">
|
||
<div class="page-header">
|
||
<div class="page-header-content">
|
||
<h1 class="page-title"><i class="fas fa-cog"></i> 基本配置</h1>
|
||
<p class="page-subtitle">配置系统的基本参数和代理地址</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="config-cards-grid">
|
||
<!-- Logo配置卡片 -->
|
||
<div class="config-card">
|
||
<div class="config-card-header">
|
||
<div class="config-card-icon purple">
|
||
<i class="fas fa-image"></i>
|
||
</div>
|
||
<div class="config-card-title">
|
||
<h3>Logo 设置</h3>
|
||
<p>自定义系统Logo图片</p>
|
||
</div>
|
||
</div>
|
||
<div class="config-card-body">
|
||
<div class="modern-form-group">
|
||
<label for="logoUrl"><i class="fas fa-link"></i> Logo URL</label>
|
||
<input type="url" id="logoUrl" name="logoUrl" class="modern-input" placeholder="请输入Logo图片URL(可选)">
|
||
<span class="input-hint">支持 PNG、JPG、SVG 格式的图片链接</span>
|
||
</div>
|
||
<button type="button" class="btn btn-primary btn-with-icon" onclick="validateAndSaveConfig('logo')">
|
||
<i class="fas fa-save"></i> 保存 Logo
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 代理地址配置卡片 -->
|
||
<div class="config-card">
|
||
<div class="config-card-header">
|
||
<div class="config-card-icon blue">
|
||
<i class="fas fa-server"></i>
|
||
</div>
|
||
<div class="config-card-title">
|
||
<h3>代理地址</h3>
|
||
<p>配置Docker镜像代理服务器</p>
|
||
</div>
|
||
</div>
|
||
<div class="config-card-body">
|
||
<div class="modern-form-group">
|
||
<label for="proxyDomain"><i class="fas fa-globe"></i> 代理地址 <span class="required-badge">必填</span></label>
|
||
<input type="text" id="proxyDomain" name="proxyDomain" class="modern-input" placeholder="例如: proxy.example.com" required>
|
||
<span class="input-hint">填写您的Docker镜像代理服务器地址</span>
|
||
</div>
|
||
<button type="button" class="btn btn-primary btn-with-icon" onclick="validateAndSaveConfig('proxy')">
|
||
<i class="fas fa-save"></i> 保存代理地址
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 菜单管理 -->
|
||
<div id="menu-management" class="content-section">
|
||
<div class="page-header">
|
||
<div class="page-header-content">
|
||
<h1 class="page-title"><i class="fas fa-bars"></i> 菜单管理</h1>
|
||
<p class="page-subtitle">管理前台页面的导航菜单项</p>
|
||
</div>
|
||
<button type="button" class="btn btn-primary btn-with-icon" onclick="menuManager.showNewMenuItemRow()">
|
||
<i class="fas fa-plus"></i> 添加菜单项
|
||
</button>
|
||
</div>
|
||
|
||
<div class="table-container">
|
||
<table id="menuTable" class="modern-table">
|
||
<thead>
|
||
<!-- 表头将由 menuManager.renderMenuItems() 动态生成 -->
|
||
</thead>
|
||
<tbody id="menuTableBody">
|
||
<!-- 菜单项将在这里动态添加 -->
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 文档管理部分 -->
|
||
<div id="documentation-management" class="content-section">
|
||
<div class="page-header">
|
||
<div class="page-header-content">
|
||
<h1 class="page-title"><i class="fas fa-file-alt"></i> 文档管理</h1>
|
||
<p class="page-subtitle">管理系统帮助文档和使用指南</p>
|
||
</div>
|
||
<button type="button" class="btn btn-primary btn-with-icon" onclick="documentManager.newDocument()">
|
||
<i class="fas fa-plus"></i> 新建文档
|
||
</button>
|
||
</div>
|
||
|
||
<div class="table-container">
|
||
<table id="documentTable" class="modern-table">
|
||
<thead>
|
||
<!-- 表头将由 documentManager.renderDocumentList() 动态生成 -->
|
||
</thead>
|
||
<tbody id="documentTableBody">
|
||
<!-- 文档列表将在这里动态添加 -->
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 修改密码部分 - 保留但隐藏,因为用户中心已有此功能 -->
|
||
<div id="password-change" class="content-section" style="display: none;">
|
||
<h2 class="menu-label">修改密码</h2>
|
||
<label for="currentPassword">当前密码</label>
|
||
<input type="password" id="currentPassword" name="currentPassword">
|
||
<label for="newPassword">新密码</label>
|
||
<span class="password-hint" id="passwordHint">密码必须包含至少一个字母、一个数字和一个特殊字符,长度在8到16个字符之间</span>
|
||
<input type="password" id="newPassword" name="newPassword" oninput="userCenter.checkPasswordStrength()">
|
||
<span id="passwordStrength" style="color: red;"></span>
|
||
<button type="button" onclick="userCenter.changePassword()">修改密码</button>
|
||
</div>
|
||
|
||
<!-- 网络测试 -->
|
||
<div id="network-test" class="content-section">
|
||
<div class="page-header">
|
||
<div class="page-header-content">
|
||
<h1 class="page-title"><i class="fas fa-network-wired"></i> 网络测试</h1>
|
||
<p class="page-subtitle">测试与Docker镜像仓库的网络连通性</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="test-controls-card">
|
||
<div class="test-controls-container">
|
||
<div class="form-group">
|
||
<label for="domainSelect"><i class="fas fa-globe"></i> 目标域名</label>
|
||
<select id="domainSelect" class="form-select">
|
||
<!-- 选项将由 networkTest.initNetworkTest() 动态生成 -->
|
||
</select>
|
||
</div>
|
||
<div class="form-group" id="customDomainContainer" style="display: none;">
|
||
<label for="customDomain"><i class="fas fa-edit"></i> 自定义域名</label>
|
||
<input type="text" id="customDomain" class="form-control" placeholder="请输入域名,如 example.com">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="testType"><i class="fas fa-tasks"></i> 测试类型</label>
|
||
<select id="testType" class="form-select">
|
||
<!-- 选项将由 networkTest.initNetworkTest() 动态生成 -->
|
||
</select>
|
||
</div>
|
||
<button id="startTestBtn" class="btn btn-primary start-test-btn">
|
||
<i class="fas fa-play"></i> 开始测试
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="testResultsContainer">
|
||
<div class="results-header">
|
||
<h3><i class="fas fa-terminal"></i> 测试结果</h3>
|
||
<button id="clearTestResultsBtn" class="btn btn-sm btn-outline-secondary">
|
||
<i class="fas fa-times-circle"></i> 清空结果
|
||
</button>
|
||
</div>
|
||
<div id="testResults">
|
||
<!-- 测试结果将显示在这里 -->
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Docker服务状态 -->
|
||
<div id="docker-status" class="content-section">
|
||
<div class="page-header">
|
||
<div class="page-header-content">
|
||
<h1 class="page-title"><i class="fab fa-docker"></i> Docker 服务状态</h1>
|
||
<p class="page-subtitle">查看和管理Docker容器状态和操作</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 新增表格容器以支持标题和操作区域 -->
|
||
<div class="table-container">
|
||
<div id="dockerTableContainer" class="table-responsive">
|
||
<table id="dockerStatusTable" class="modern-table excel-table">
|
||
<thead></thead>
|
||
<tbody id="dockerStatusTableBody"></tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Docker监控配置 -->
|
||
<div id="docker-monitoring" class="content-section">
|
||
<div class="page-header">
|
||
<div class="page-header-content">
|
||
<h1 class="page-title"><i class="fas fa-chart-line"></i> Docker 容器监控</h1>
|
||
<p class="page-subtitle">配置容器监控和告警通知</p>
|
||
</div>
|
||
<div class="monitoring-status-badge">
|
||
<span>监控状态:</span>
|
||
<span id="monitoringStatus" class="status-indicator">加载中...</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 通知配置卡片 - 全宽 -->
|
||
<div class="config-card monitoring-config-card">
|
||
<div class="config-card-header">
|
||
<div class="config-card-icon green">
|
||
<i class="fas fa-bell"></i>
|
||
</div>
|
||
<div class="config-card-title">
|
||
<h3>通知配置</h3>
|
||
<p>设置告警通知方式和监控参数</p>
|
||
</div>
|
||
</div>
|
||
<div class="config-card-body">
|
||
<div class="monitoring-form-grid">
|
||
<!-- 左侧:通知方式选择 -->
|
||
<div class="monitoring-form-section">
|
||
<h4 class="form-section-title"><i class="fas fa-paper-plane"></i> 通知渠道</h4>
|
||
<div class="modern-form-group">
|
||
<label for="notificationType">通知方式</label>
|
||
<select id="notificationType" class="modern-input">
|
||
<option value="wechat">企业微信群机器人</option>
|
||
<option value="telegram">Telegram Bot</option>
|
||
</select>
|
||
</div>
|
||
<div id="wechatFields">
|
||
<div class="modern-form-group">
|
||
<label for="webhookUrl"><i class="fas fa-link"></i> Webhook URL</label>
|
||
<input type="text" id="webhookUrl" name="webhookUrl" class="modern-input" placeholder="企业微信机器人 Webhook URL">
|
||
<span class="input-hint">从企业微信群机器人设置中获取</span>
|
||
</div>
|
||
</div>
|
||
<div id="telegramFields" style="display: none;">
|
||
<div class="modern-form-group">
|
||
<label for="telegramToken"><i class="fas fa-key"></i> Bot Token</label>
|
||
<input type="text" id="telegramToken" name="telegramToken" class="modern-input" placeholder="Telegram Bot Token">
|
||
<span class="input-hint">从 @BotFather 获取</span>
|
||
</div>
|
||
<div class="modern-form-group">
|
||
<label for="telegramChatId"><i class="fas fa-comments"></i> Chat ID</label>
|
||
<input type="text" id="telegramChatId" name="telegramChatId" class="modern-input" placeholder="Telegram Chat ID">
|
||
<span class="input-hint">个人/群组/频道的 Chat ID</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 右侧:监控参数 -->
|
||
<div class="monitoring-form-section">
|
||
<h4 class="form-section-title"><i class="fas fa-cog"></i> 监控参数</h4>
|
||
<div class="modern-form-group">
|
||
<label for="monitorInterval"><i class="fas fa-clock"></i> 监控间隔 (秒)</label>
|
||
<input type="number" id="monitorInterval" name="monitorInterval" min="1" value="60" class="modern-input">
|
||
<span class="input-hint">建议设置 60 秒以上,避免频繁检测</span>
|
||
</div>
|
||
|
||
<div class="monitoring-info-box">
|
||
<div class="info-box-icon">
|
||
<i class="fas fa-info-circle"></i>
|
||
</div>
|
||
<div class="info-box-content">
|
||
<h5>监控说明</h5>
|
||
<p>系统会定期检查容器状态,当发现容器停止运行时,会通过配置的渠道发送告警通知。</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 操作按钮 -->
|
||
<div class="monitoring-actions">
|
||
<button class="btn btn-outline-secondary btn-with-icon" id="testNotifyBtn" onclick="app.testNotification()">
|
||
<i class="fas fa-vial"></i> 测试通知
|
||
</button>
|
||
<button class="btn btn-primary btn-with-icon" id="saveConfigBtn" onclick="app.saveMonitoringConfig()">
|
||
<i class="fas fa-save"></i> 保存配置
|
||
</button>
|
||
<button class="btn btn-secondary btn-with-icon" id="toggleMonitoringBtn" onclick="app.toggleMonitoring()">
|
||
<i class="fas fa-power-off"></i> 开启/关闭监控
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 已停止容器卡片 -->
|
||
<div class="config-card">
|
||
<div class="config-card-header">
|
||
<div class="config-card-icon red">
|
||
<i class="fas fa-stop-circle"></i>
|
||
</div>
|
||
<div class="config-card-title">
|
||
<h3>已停止的容器</h3>
|
||
<p>显示当前处于停止状态的容器列表</p>
|
||
</div>
|
||
</div>
|
||
<div class="config-card-body">
|
||
<div class="table-responsive">
|
||
<table id="stoppedContainersTable" class="modern-table">
|
||
<thead>
|
||
<tr>
|
||
<th>容器ID</th>
|
||
<th>容器名称</th>
|
||
<th>镜像名称</th>
|
||
<th>运行状态</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="stoppedContainersBody"></tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div id="messageContainer"></div>
|
||
</div>
|
||
|
||
<!-- 用户中心部分 -->
|
||
<div id="user-center" class="content-section">
|
||
<div class="user-center-header">
|
||
<div>
|
||
<h1 class="user-center-title"><i class="fas fa-user-cog"></i> 用户中心</h1>
|
||
<p class="user-center-subtitle">管理您的个人信息和账户安全</p>
|
||
</div>
|
||
<button class="btn btn-danger-outline" id="ucLogoutBtn">
|
||
<i class="fas fa-sign-out-alt"></i> 退出登录
|
||
</button>
|
||
</div>
|
||
|
||
<!-- 个人资料卡片 -->
|
||
<div class="user-profile-card">
|
||
<div class="user-profile-avatar">
|
||
<i class="fas fa-user-circle"></i>
|
||
</div>
|
||
<div class="user-profile-info">
|
||
<h2 class="user-profile-name" id="profileUsername">管理员</h2>
|
||
<p class="user-profile-role">系统管理员</p>
|
||
<div class="user-profile-badges">
|
||
<span class="user-badge admin"><i class="fas fa-shield-alt"></i> 管理员</span>
|
||
<span class="user-badge active"><i class="fas fa-check-circle"></i> 活跃</span>
|
||
</div>
|
||
</div>
|
||
<div class="user-profile-actions">
|
||
<button class="btn btn-outline" onclick="userCenter.refreshUserInfo()">
|
||
<i class="fas fa-sync-alt"></i> 刷新信息
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 账户统计卡片 - 独立行 -->
|
||
<div class="user-stats-row">
|
||
<div class="stat-card-enhanced">
|
||
<div class="stat-icon-wrapper blue">
|
||
<i class="fas fa-sign-in-alt"></i>
|
||
</div>
|
||
<div class="stat-content">
|
||
<div class="stat-value" id="loginCount">--</div>
|
||
<div class="stat-label">登录次数</div>
|
||
</div>
|
||
</div>
|
||
<div class="stat-card-enhanced">
|
||
<div class="stat-icon-wrapper green">
|
||
<i class="fas fa-clock"></i>
|
||
</div>
|
||
<div class="stat-content">
|
||
<div class="stat-value" id="lastLogin">--</div>
|
||
<div class="stat-label">上次登录</div>
|
||
</div>
|
||
</div>
|
||
<div class="stat-card-enhanced">
|
||
<div class="stat-icon-wrapper purple">
|
||
<i class="fas fa-calendar-alt"></i>
|
||
</div>
|
||
<div class="stat-content">
|
||
<div class="stat-value" id="accountAge">--</div>
|
||
<div class="stat-label">账户天数</div>
|
||
</div>
|
||
</div>
|
||
<div class="stat-card-enhanced">
|
||
<div class="stat-icon-wrapper orange">
|
||
<i class="fas fa-shield-alt"></i>
|
||
</div>
|
||
<div class="stat-content">
|
||
<div class="stat-value">安全</div>
|
||
<div class="stat-label">账户状态</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 安全设置区域 -->
|
||
<div class="security-section-header">
|
||
<h2><i class="fas fa-lock"></i> 安全设置</h2>
|
||
<p>管理您的账户安全信息,定期修改密码可以提高账户安全性</p>
|
||
</div>
|
||
|
||
<div class="user-dashboard-grid">
|
||
<!-- 修改用户名卡片 -->
|
||
<div class="user-center-card security-card">
|
||
<div class="card-icon-header">
|
||
<div class="card-icon blue">
|
||
<i class="fas fa-user-edit"></i>
|
||
</div>
|
||
<h2 class="user-center-section-title">修改用户名</h2>
|
||
</div>
|
||
<p class="card-description">修改登录用户名,建议使用不易猜测的用户名以提高安全性</p>
|
||
<form id="changeUsernameForm" class="modern-form">
|
||
<div class="form-group">
|
||
<label for="ucNewUsername">
|
||
<i class="fas fa-user"></i> 新用户名
|
||
</label>
|
||
<input type="text" id="ucNewUsername" name="newUsername" placeholder="请输入新用户名" class="form-input">
|
||
<span class="input-hint">3-20位,只能包含字母、数字和下划线</span>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="ucUsernamePassword">
|
||
<i class="fas fa-key"></i> 当前密码
|
||
</label>
|
||
<div class="password-input-wrapper">
|
||
<input type="password" id="ucUsernamePassword" name="password" placeholder="请输入当前密码验证身份" class="form-input">
|
||
<button type="button" class="toggle-password" onclick="userCenter.togglePasswordVisibility('ucUsernamePassword', this)">
|
||
<i class="fas fa-eye"></i>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<button type="submit" class="btn btn-primary btn-block">
|
||
<i class="fas fa-save"></i> 保存新用户名
|
||
</button>
|
||
</form>
|
||
</div>
|
||
|
||
<!-- 密码修改卡片 -->
|
||
<div class="user-center-card security-card">
|
||
<div class="card-icon-header">
|
||
<div class="card-icon orange">
|
||
<i class="fas fa-lock"></i>
|
||
</div>
|
||
<h2 class="user-center-section-title">修改密码</h2>
|
||
</div>
|
||
<p class="card-description">定期修改密码可以有效提高账户安全性,建议每3个月更换一次</p>
|
||
<form id="changePasswordForm" class="modern-form">
|
||
<div class="form-group">
|
||
<label for="ucCurrentPassword">
|
||
<i class="fas fa-key"></i> 当前密码
|
||
</label>
|
||
<div class="password-input-wrapper">
|
||
<input type="password" id="ucCurrentPassword" name="currentPassword" placeholder="请输入当前密码" class="form-input">
|
||
<button type="button" class="toggle-password" onclick="userCenter.togglePasswordVisibility('ucCurrentPassword', this)">
|
||
<i class="fas fa-eye"></i>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="ucNewPassword">
|
||
<i class="fas fa-lock"></i> 新密码
|
||
</label>
|
||
<div class="password-input-wrapper">
|
||
<input type="password" id="ucNewPassword" name="newPassword" placeholder="请输入新密码" class="form-input" oninput="userCenter.checkUcPasswordStrength()">
|
||
<button type="button" class="toggle-password" onclick="userCenter.togglePasswordVisibility('ucNewPassword', this)">
|
||
<i class="fas fa-eye"></i>
|
||
</button>
|
||
</div>
|
||
<div class="password-strength-bar">
|
||
<div class="strength-indicator" id="strengthIndicator"></div>
|
||
</div>
|
||
<span class="input-hint" id="ucPasswordHint">8-16位,需包含字母、数字和特殊字符</span>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="ucConfirmPassword">
|
||
<i class="fas fa-check-circle"></i> 确认新密码
|
||
</label>
|
||
<div class="password-input-wrapper">
|
||
<input type="password" id="ucConfirmPassword" name="confirmPassword" placeholder="请再次输入新密码" class="form-input">
|
||
<button type="button" class="toggle-password" onclick="userCenter.togglePasswordVisibility('ucConfirmPassword', this)">
|
||
<i class="fas fa-eye"></i>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div class="form-actions">
|
||
<button type="submit" class="btn btn-primary btn-block">
|
||
<i class="fas fa-save"></i> 更新密码
|
||
</button>
|
||
<span id="ucPasswordStrength" class="password-strength-text"></span>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 安全提示 -->
|
||
<div class="security-tips">
|
||
<div class="tip-header">
|
||
<i class="fas fa-lightbulb"></i>
|
||
<span>安全提示</span>
|
||
</div>
|
||
<ul class="tip-list">
|
||
<li><i class="fas fa-check"></i> 使用强密码,包含大小写字母、数字和特殊字符</li>
|
||
<li><i class="fas fa-check"></i> 不要与他人共享您的登录凭据</li>
|
||
<li><i class="fas fa-check"></i> 定期更换密码,建议每3个月更换一次</li>
|
||
<li><i class="fas fa-check"></i> 使用独特的用户名,避免使用常见名称如admin、root等</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="login-modal" id="loginModal" style="display: none;">
|
||
<div class="login-content">
|
||
<div class="login-header">
|
||
<h2 id="loginTitle">管理员登录</h2>
|
||
</div>
|
||
|
||
<!-- 登录表单 -->
|
||
<form id="loginForm" class="login-form">
|
||
<input type="text" id="username" name="username" placeholder="用户名" required>
|
||
<input type="password" id="password" name="password" placeholder="密码" required>
|
||
<!-- 修复这里的结构问题 - 添加了缺失的开始标签 -->
|
||
<div class="captcha-container">
|
||
<input type="text" id="captcha" name="captcha" placeholder="验证码" required>
|
||
<span id="captchaText" onclick="auth.refreshCaptcha()">点击刷新验证码</span>
|
||
</div>
|
||
<button type="submit" id="loginButton">登录</button>
|
||
<div class="forgot-password-link">
|
||
<a href="javascript:void(0)" onclick="auth.showForgotPassword()">忘记密码?</a>
|
||
</div>
|
||
</form>
|
||
|
||
<!-- 忘记密码表单 - 步骤1: 验证用户名 -->
|
||
<form id="forgotPasswordForm" class="login-form" style="display: none;">
|
||
<div class="form-description">
|
||
<i class="fas fa-key"></i>
|
||
<span>请输入您的用户名来获取密码重置令牌</span>
|
||
</div>
|
||
<input type="text" id="resetUsername" name="resetUsername" placeholder="用户名" required>
|
||
<div class="captcha-container">
|
||
<input type="text" id="resetCaptcha" name="resetCaptcha" placeholder="验证码" required>
|
||
<span id="resetCaptchaText" onclick="auth.refreshCaptcha()">点击刷新验证码</span>
|
||
</div>
|
||
<button type="submit" id="getTokenButton">获取重置令牌</button>
|
||
<div class="back-to-login">
|
||
<a href="javascript:void(0)" onclick="auth.showLoginForm()"><i class="fas fa-arrow-left"></i> 返回登录</a>
|
||
</div>
|
||
</form>
|
||
|
||
<!-- 重置密码表单 - 步骤2: 设置新密码 -->
|
||
<form id="resetPasswordForm" class="login-form" style="display: none;">
|
||
<div class="form-description">
|
||
<i class="fas fa-lock"></i>
|
||
<span>请设置您的新密码</span>
|
||
</div>
|
||
<div id="resetTokenDisplay" class="token-display">
|
||
<div class="token-label"><i class="fas fa-ticket-alt"></i> 重置令牌</div>
|
||
<div class="token-value" id="tokenValue"></div>
|
||
</div>
|
||
<input type="password" id="resetNewPassword" name="resetNewPassword" placeholder="新密码(8-16位,含字母、数字和特殊字符)" required>
|
||
<input type="password" id="resetConfirmPassword" name="resetConfirmPassword" placeholder="确认新密码" required>
|
||
<div class="password-requirements">
|
||
<i class="fas fa-info-circle"></i>
|
||
密码要求:8-16位,包含字母、数字和特殊字符
|
||
</div>
|
||
<button type="submit" id="resetPasswordButton">重置密码</button>
|
||
<div class="back-to-login">
|
||
<a href="javascript:void(0)" onclick="auth.showLoginForm()"><i class="fas fa-arrow-left"></i> 返回登录</a>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
<script src="https://cdnjs.cloudflare.com/ajax/libs/dragula/3.7.2/dragula.min.js"></script>
|
||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||
|
||
<!-- 添加 Bootstrap 5 JavaScript -->
|
||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
|
||
|
||
<!-- Toast UI Editor - 添加编辑器需要的依赖 -->
|
||
<script src="https://uicdn.toast.com/editor/latest/toastui-editor-all.min.js"></script>
|
||
<link rel="stylesheet" href="https://uicdn.toast.com/editor/latest/toastui-editor.min.css" />
|
||
|
||
<!-- 模块化JS文件 - 按依赖顺序加载 -->
|
||
<script src="js/core.js"></script>
|
||
<script src="js/auth.js"></script>
|
||
<script src="js/userCenter.js"></script>
|
||
<script src="js/menuManager.js"></script>
|
||
<script src="js/documentManager.js"></script>
|
||
<script src="js/systemStatus.js"></script>
|
||
<script src="js/dockerManager.js"></script>
|
||
<script src="js/networkTest.js"></script>
|
||
<script src="js/app.js"></script>
|
||
|
||
<script>
|
||
// 在DOM加载完成后初始化登录表单
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
const loginForm = document.getElementById('loginForm');
|
||
if (loginForm) {
|
||
loginForm.addEventListener('submit', function(e) {
|
||
e.preventDefault();
|
||
auth.login();
|
||
});
|
||
}
|
||
|
||
const changePasswordForm = document.getElementById('changePasswordForm');
|
||
if (changePasswordForm) {
|
||
changePasswordForm.addEventListener('submit', function(e) {
|
||
e.preventDefault();
|
||
userCenter.changePassword();
|
||
});
|
||
}
|
||
|
||
// 设置超时自动显示登录框,避免一直显示"加载中..."
|
||
setTimeout(function() {
|
||
const loadingIndicator = document.getElementById('loadingIndicator');
|
||
if (loadingIndicator && loadingIndicator.style.display !== 'none') {
|
||
console.log('超时自动显示登录框');
|
||
if (core && typeof core.hideLoadingIndicator === 'function') {
|
||
core.hideLoadingIndicator();
|
||
}
|
||
|
||
const loginModal = document.getElementById('loginModal');
|
||
if (loginModal) {
|
||
loginModal.style.display = 'flex';
|
||
if (window.auth && typeof window.auth.refreshCaptcha === 'function') {
|
||
window.auth.refreshCaptcha();
|
||
}
|
||
}
|
||
}
|
||
}, 3000); // 3秒后如果仍在加载,则显示登录框
|
||
|
||
// 确保saveConfig可用
|
||
window.saveConfig = window.app ? window.app.saveConfig : function(data) {
|
||
console.error('saveConfig未定义');
|
||
};
|
||
|
||
// 确保validateAndSaveConfig可用
|
||
window.validateAndSaveConfig = window.app ? window.app.validateAndSaveConfig : function(type) {
|
||
console.error('validateAndSaveConfig未定义');
|
||
};
|
||
});
|
||
</script>
|
||
</body>
|
||
</html> |