查看“︁1”︁的源代码
←
1
跳转到导航
跳转到搜索
因为以下原因,您没有权限编辑该页面:
您请求的操作仅限属于该用户组的用户执行:
用户
您可以查看和复制此页面的源代码。
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>服务器详情</title> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;500;700&display=swap"> <script src="https://html2canvas.hertzen.com/dist/html2canvas.min.js"></script> <style> /* ========== 以下样式与原文件完全一致,无任何修改 ========== */ * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Noto Sans SC', 'Segoe UI', 'Microsoft YaHei', sans-serif; } body { background: linear-gradient(135deg, #0f1a3d, #1c2e50); color: #333; min-height: 100vh; padding: 20px; display: flex; flex-direction: column; align-items: center; } .container { width: 100%; max-width: 1200px; background: white; border-radius: 20px; box-shadow: 0 15px 40px rgba(0, 0, 0, 0.5); overflow: hidden; margin: 20px 0; position: relative; } header { background: linear-gradient(90deg, #1a5e1f, #2e7d32); color: white; padding: 30px 40px; text-align: center; position: relative; overflow: hidden; } header::before { content: ""; position: absolute; top: -50%; left: -50%; width: 200%; height: 200%; background: radial-gradient(circle, rgba(255,255,255,0.1) 0%, transparent 70%); transform: rotate(30deg); } h1 { font-size: 2.8rem; margin-bottom: 10px; letter-spacing: 1px; text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3); position: relative; font-weight: 700; } .subtitle { font-size: 1.2rem; opacity: 0.9; margin-top: 10px; position: relative; font-weight: 400; } .content { padding: 30px 40px; } .controls { display: flex; justify-content: space-between; margin-bottom: 20px; padding: 15px 20px; background: #f8f9fa; border-radius: 15px; box-shadow: 0 4px 12px rgba(0,0,0,0.05); flex-wrap: wrap; gap: 15px; } .controls-right { display: flex; align-items: center; gap: 15px; } .server-id { position: absolute; top: 50%; transform: translateY(-10px); left: 10px; background: #2e7d32; color: white; width: 30px; height: 30px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: bold; font-size: 0.9rem; z-index: 1; } .server-card.closed .server-id { background: #e74c3c; } .server-card.today-closed .server-id { background: #f39c12; } .server-card.upcoming .server-id { background: #9b59b6; } .sort-controls { display: flex; gap: 15px; align-items: center; flex-wrap: wrap; } .sort-label { font-weight: 500; color: #555; } .sort-select { padding: 10px 20px; border-radius: 50px; border: 2px solid #e0e0e0; background: white; font-size: 1rem; cursor: pointer; outline: none; transition: all 0.3s ease; min-width: 180px; } .sort-select:focus { border-color: #2e7d32; box-shadow: 0 0 0 3px rgba(46, 125, 50, 0.2); } .download-all-btn { background: linear-gradient(90deg, #3498db, #2980b9); color: white; border: none; padding: 12px 30px; font-size: 1.1rem; border-radius: 50px; cursor: pointer; transition: all 0.3s ease; display: flex; align-items: center; gap: 10px; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2); font-weight: 500; } .download-all-btn:hover { transform: translateY(-3px); box-shadow: 0 8px 20px rgba(0, 0, 0, 0.3); background: linear-gradient(90deg, #2980b9, #2573a7); } .server-card { background: white; border-radius: 15px; box-shadow: 0 5px 20px rgba(0, 0, 0, 0.08); padding: 25px; margin-bottom: 30px; border-left: 5px solid #2e7d32; transition: all 0.3s ease; position: relative; overflow: hidden; } .server-card.closed { border-left: 5px solid #e74c3c; } .server-card.today-closed { border-left: 5px solid #f39c12; } .server-card.upcoming { border-left: 5px solid #9b59b6; } .server-card:hover { transform: translateY(-5px); box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15); } .server-card::before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 5px; background: linear-gradient(90deg, #2e7d32, #1a5e1f); } .server-card.closed::before { background: linear-gradient(90deg, #e74c3c, #c0392b); } .server-card.today-closed::before { background: linear-gradient(90deg, #f39c12, #e67e22); } .server-card.upcoming::before { background: linear-gradient(90deg, #9b59b6, #8e44ad); } .server-title { color: #2e7d32; font-size: 1.8rem; margin-bottom: 15px; display: flex; justify-content: space-between; align-items: flex-start; position: relative; font-weight: 600; } .server-title-content { display: flex; align-items: flex-start; gap: 15px; flex: 1; } .server-name-container { display: flex; flex-direction: row; align-items: center; gap: 8px; flex-wrap: wrap; } .chinese-name { display: block; font-size: 1.8rem; color: inherit; } .english-name { display: block; font-size: 1.1rem; color: #7f8c8d; font-weight: 400; margin-top: 1px; line-height: 0; width: 100%; } .server-card.closed .server-title { color: #e74c3c; } .server-card.today-closed .server-title { color: #f39c12; } .server-card.upcoming .server-title { color: #9b59b6; } .server-title i { background: #e8f5e9; width: 50px; height: 50px; border-radius: 50%; display: flex !important; align-items: center !important; justify-content: center !important; font-size: 1.3rem; line-height: 1 !important; } .server-card.closed .server-title i { background: #ffebee; } .server-card.today-closed .server-title i { background: #fef5e7; } .server-card.upcoming .server-title i { background: #f5e9ff; } .server-info { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 20px; margin-bottom: 20px; } .info-item { display: flex; flex-direction: column; } .info-label { font-weight: 600; color: #7f8c8d; font-size: 0.95rem; margin-bottom: 5px; display: flex; align-items: center; gap: 8px; } .info-value { font-size: 1.15rem; color: #2c3e50; font-weight: 500; word-break: break-all; } .ip-address { font-family: monospace; background: #f8f9fa; padding: 10px 15px; border-radius: 8px; border: 1px solid #e0e0e0; color: #2e7d32; font-weight: 600; font-size: 1.1rem; } .server-card.closed .ip-address { color: #e74c3c; } .server-card.today-closed .ip-address { color: #f39c12; } .server-card.upcoming .ip-address { color: #9b59b6; } .description { background: #f8f9fa; border-left: 3px solid #3498db; padding: 18px; border-radius: 0 12px 12px 0; margin: 25px 0 15px; font-size: 1.1rem; line-height: 1.7; } .server-status { position: absolute; top: 25px; right: 25px; padding: 8px 20px; border-radius: 30px; font-weight: bold; font-size: 0.95rem; text-transform: uppercase; letter-spacing: 1px; box-shadow: 0 3px 8px rgba(0,0,0,0.1); } .status-open { background: #e8f5e9; color: #2e7d32; border: 1px solid #a5d6a7; } .status-closed { background: #ffebee; color: #e74c3c; border: 1px solid #ef9a9a; } .status-today-closed { background: #fef5e7; color: #f39c12; border: 1px solid #f8c471; } .status-upcoming { background: #f5e9ff; color: #9b59b6; border: 1px solid #d6b8f1; } .special-tag { background: #f39c12; color: white; padding: 4px 12px; border-radius: 30px; font-size: 0.9rem; display: inline-block; font-weight: 500; margin-left: 0; } .server-card.upcoming .special-tag { background: #9b59b6; } .footer { background: #1c2e50; color: white; padding: 30px 40px; text-align: center; margin-top: 20px; width: 100%; } .footer-content { display: flex; justify-content: space-between; flex-wrap: wrap; gap: 20px; width: 100%; } .footer-section { flex: 1; min-width: 200px; max-width: 350px; } .footer-title { font-size: 1.3rem; margin-bottom: 15px; color: #ecf0f1; font-weight: 500; } .footer-list { list-style: none; display: flex; flex-direction: column; flex-wrap: wrap; max-height: 180px; } .footer-list li { margin-bottom: 10px; display: flex; align-items: center; gap: 10px; font-size: 1rem; min-width: 150px; } .maintainers-list { display: grid; grid-template-rows: repeat(3, auto); grid-auto-flow: column; gap: 10px 30px; max-height: none; } .maintainers-list li { margin-bottom: 0; min-width: 150px; } .footer-bottom { margin-top: 30px; padding-top: 20px; border-top: 1px solid rgba(255, 255, 255, 0.15); font-size: 0.95rem; opacity: 0.8; width: 100%; } .stats-bar { display: flex; justify-content: space-around; background: #f8f9fa; padding: 18px; border-radius: 15px; margin: 25px 0; border: 1px solid #e0e0e0; box-shadow: 0 4px 12px rgba(0,0,0,0.05); } .stat-item { text-align: center; padding: 10px; } .stat-number { font-size: 2.2rem; font-weight: 700; color: #2e7d32; line-height: 1; } .closed-count { color: #e74c3c; } .today-closed-count { color: #f39c12; } .upcoming-count { color: #9b59b6; } .stat-label { font-size: 1rem; color: #7f8c8d; font-weight: 500; } .filter-controls { display: flex; justify-content: flex-start; align-items: center; gap: 15px; margin-bottom: 20px; flex-wrap: wrap; padding: 15px; background: #f8f9fa; border-radius: 15px; box-shadow: 0 4px 12px rgba(0,0,0,0.05); position: relative; } .filter-label { font-weight: 500; color: #555; white-space: nowrap; } .settings-btn { background: #f8f9fa; border: 2px solid #e0e0e0; border-radius: 50%; width: 40px; height: 40px; display: flex; align-items: center; justify-content: center; cursor: pointer; transition: all 0.3s ease; } .settings-btn:hover { background: #e0e0e0; transform: rotate(30deg); } .language-toggle { display: flex; background: #e8f5e9; border-radius: 50px; overflow: hidden; margin-top: 20px; border: 2px solid #e0e0e0; } .lang-btn { padding: 10px 25px; border: none; background: transparent; font-weight: 500; cursor: pointer; transition: all 0.3s ease; font-size: 1rem; flex: 1; text-align: center; } .lang-btn.active { background: #2e7d32; color: white; } .download-progress { display: none; text-align: center; padding: 15px; background: #e8f5e9; border-radius: 10px; margin-top: 20px; z-index: 1001; } .progress-bar { height: 8px; background: #e0e0e0; border-radius: 4px; margin-top: 10px; overflow: hidden; } .progress-fill { height: 100%; background: #2e7d32; width: 0%; transition: width 0.3s ease; } .header-icons { display: flex; justify-content: center; gap: 20px; margin-top: 15px; } .icon-circle { width: 65px; height: 65px; border-radius: 50%; background: rgba(255, 255, 255, 0.2); display: flex; align-items: center; justify-content: center; font-size: 2rem; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2); } .download-modal { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.7); z-index: 1000; justify-content: center; align-items: center; } .modal-content { background: white; border-radius: 20px; width: 90%; max-width: 500px; overflow: hidden; box-shadow: 0 25px 50px rgba(0,0,0,0.3); transform: translateY(20px); opacity: 0; transition: all 0.4s ease; } .modal-header { background: linear-gradient(90deg, #3498db, #2980b9); color: white; padding: 25px; text-align: center; position: relative; } .modal-title { font-size: 1.8rem; font-weight: 600; } .modal-body { padding: 30px; } .res-options { display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; margin-bottom: 30px; } .res-option { border: 2px solid #e0e0e0; border-radius: 15px; padding: 20px; text-align: center; cursor: pointer; transition: all 0.3s ease; } .res-option:hover { border-color: #3498db; box-shadow: 0 5px 15px rgba(52, 152, 219, 0.2); transform: translateY(-5px); } .res-option.selected { border-color: #3498db; background: #e8f4fc; } .res-percent { font-size: 1.8rem; font-weight: 700; color: #3498db; margin-bottom: 5px; } .res-label { font-size: 1rem; color: #7f8c8d; } .modal-footer { display: flex; justify-content: flex-end; padding: 20px 30px; background: #f8f9fa; border-top: 1px solid #e0e0e0; } .modal-btn { padding: 12px 30px; border-radius: 50px; border: none; font-weight: 500; font-size: 1.1rem; cursor: pointer; transition: all 0.3s ease; } .cancel-btn { background: #f8f9fa; color: #7f8c8d; margin-right: 15px; } .cancel-btn:hover { background: #e0e0e0; } .download-btn { background: linear-gradient(90deg, #2ecc71, #27ae60); color: white; box-shadow: 0 5px 15px rgba(46, 204, 113, 0.3); } .download-btn:hover { background: linear-gradient(90deg, #27ae60, #219653); transform: translateY(-3px); box-shadow: 0 8px 20px rgba(46, 204, 113, 0.4); } .sort-direction { display: flex; align-items: center; justify-content: center; width: 40px; height: 40px; border-radius: 50%; background: #e8f5e9; border: 2px solid #e0e0e0; cursor: pointer; transition: all 0.3s ease; } .sort-direction:hover { background: #d5e8d6; } .sort-direction.desc i { transform: rotate(180deg); } .sort-feedback { position: fixed; top: 20px; left: 50%; transform: translateX(-50%); color: white; padding: 12px 25px; border-radius: 30px; font-weight: 500; box-shadow: 0 5px 15px rgba(0,0,0,0.2); z-index: 3000; opacity: 0; transition: all 0.3s ease; background: rgba(0,0,0,0.7); backdrop-filter: blur(5px); } .sort-feedback.show { opacity: 1; transform: translateX(-50%) translateY(10px); } .settings-modal { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 1000; backdrop-filter: blur(5px); } .settings-content { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); background: white; border-radius: 20px; padding: 30px; width: 90%; max-width: 500px; box-shadow: 0 25px 50px rgba(0,0,0,0.3); } .settings-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 25px; padding-bottom: 15px; border-bottom: 2px solid #f0f0f0; } .settings-title { font-size: 1.5rem; font-weight: 700; color: #333; } .close-settings { background: none; border: none; font-size: 1.5rem; cursor: pointer; color: #666; padding: 5px; border-radius: 50%; transition: all 0.3s ease; } .close-settings:hover { background: #f0f0f0; color: #333; } .settings-section { margin-bottom: 25px; } .settings-section h3 { margin-bottom: 15px; color: #555; font-weight: 600; } .setting-item { display: flex; justify-content: space-between; align-items: center; padding: 12px 0; border-bottom: 1px solid #f8f8f8; } .setting-label { font-weight: 500; color: #333; } .toggle-switch { width: 50px; height: 26px; background: #e0e0e0; border-radius: 13px; position: relative; cursor: pointer; transition: all 0.3s ease; } .toggle-switch::before { content: ''; position: absolute; width: 22px; height: 22px; background: white; border-radius: 50%; top: 2px; left: 2px; transition: all 0.3s ease; box-shadow: 0 2px 4px rgba(0,0,0,0.2); } .toggle-switch.active { background: #2e7d32; } .toggle-switch.active::before { left: 26px; } .sort-center-wrapper { position: absolute; left: 50%; transform: translateX(-50%); display: flex; align-items: center; gap: 10px; } .download-wrapper { margin-left: auto; } @media (max-width: 900px) { .controls { flex-direction: column; gap: 20px; } .sort-center-wrapper { position: static; transform: none; margin: 10px 0; } .download-wrapper { margin-left: 0; width: 100%; } .download-all-btn { width: 100%; justify-content: center; } .footer-list { display: block; max-height: none; } .footer-list li { margin-bottom: 10px; } .maintainers-list { display: block; } .maintainers-list li { margin-bottom: 10px; } } @media (max-width: 768px) { .filter-controls { flex-direction: column; align-items: stretch; } .sort-center-wrapper { flex-wrap: wrap; justify-content: center; } h1 { font-size: 2.2rem; } .content { padding: 20px; } .server-info { grid-template-columns: 1fr; } .server-title { font-size: 1.5rem; } .server-status { position: static; margin-top: 10px; display: inline-block; } .stats-bar { flex-direction: column; gap: 15px; } } </style> </head> <body class="chinese"> <div class="container" id="doc-content"> <header> <h1>服务器详情</h1> <div class="subtitle">本群服及附属群服</div> <div class="header-icons"> <div class="icon-circle"><i class="fas fa-server"></i></div> <div class="icon-circle"><i class="fas fa-train"></i></div> <div class="icon-circle"><i class="fas fa-network-wired"></i></div> </div> </header> <!-- 筛选控制区域 --> <div class="filter-controls"> <div style="display: flex; align-items: center; gap: 15px;"> <span class="filter-label">发起人:</span> <select class="sort-select" id="founder-select"> <option value="all">全部</option> </select> <div class="settings-btn" id="settings-btn"> <i class="fas fa-cog"></i> </div> </div> <div class="sort-center-wrapper"> <span class="sort-label">排序方式:</span> <select class="sort-select" id="sort-select"> <option value="date">开服日期 (默认)</option> <option value="name">服务器名称</option> <option value="founder">发起人</option> <option value="size">地图尺寸</option> <option value="group">所属群聊</option> <option value="version">版本号</option> <option value="open-time">开放时间</option> </select> <div class="sort-direction desc" id="sort-direction" title="切换排序方向"> <i class="fas fa-arrow-down"></i> </div> </div> <div class="download-wrapper"> <button class="download-all-btn" id="download-btn"> <i class="fas fa-download"></i> 下载全图 </button> </div> </div> <!-- 设置模态框 --> <div class="settings-modal" id="settingsModal"> <div class="settings-content"> <div class="settings-header"> <h2 class="settings-title">设置</h2> <button class="close-settings" id="closeSettings"> <i class="fas fa-times"></i> </button> </div> <div class="settings-section"> <h3><i class="fas fa-desktop"></i> 显示设置</h3> <div class="setting-item"> <span class="setting-label">隐藏已关闭服务器</span> <div class="toggle-switch active" id="hideClosedToggle"></div> </div> <div class="setting-item"> <span class="setting-label">隐藏即将开启服务器</span> <div class="toggle-switch" id="hideUpcomingToggle"></div> </div> </div> <div class="settings-section"> <h3><i class="fas fa-info-circle"></i> 关于</h3> <p style="color: #666; line-height: 1.6;" id="settings-about"> 服务器详情-v12.0<br> 更新时间: 2025.12.08<br> 制作人员: Hank </p> </div> </div> </div> <div class="content"> <!-- 统计信息 --> <div class="stats-bar"> <div class="stat-item"><div class="stat-number" id="total-count">0</div><div class="stat-label">服务器总数</div></div> <div class="stat-item"><div class="stat-number" id="configured-count">0</div><div class="stat-label">已配置服务器</div></div> <div class="stat-item"><div class="stat-number" id="open-count">0</div><div class="stat-label">当前开放</div></div> <div class="stat-item"><div class="stat-number closed-count" id="closed-count">0</div><div class="stat-label">永久关闭</div></div> <div class="stat-item"><div class="stat-number upcoming-count" id="upcoming-count">0</div><div class="stat-label">即将开启</div></div> </div> <!-- 服务器列表 --> <div class="servers-container"></div> </div> <div class="footer"> <div class="footer-content"> <div class="footer-section"> <h3 class="footer-title">文档信息</h3> <ul class="footer-list" id="footer-info"> </ul> </div> <div class="footer-section"> <h3 class="footer-title">维护团队</h3> <ul class="footer-list maintainers-list" id="footer-maintainers"> </ul> </div> <div class="footer-section"> <h3 class="footer-title">注意事项</h3> <ul class="footer-list" id="footer-notes"> </ul> </div> </div> <div class="footer-bottom" id="footer-bottom"> <p>© 2026 服务器详情 | 群服及附属群服 | 公开参考版本</p> </div> </div> </div> <!-- 下载全图模态框 --> <div class="download-modal" id="download-modal"> <div class="modal-content" id="modal-content"> <div class="modal-header"> <h2 class="modal-title">下载全图</h2> </div> <div class="modal-body"> <p style="margin-bottom: 25px; text-align: center; font-size: 1.1rem; color: #555;">请选择下载分辨率:</p> <div class="res-options"> <div class="res-option" data-res="100"><div class="res-percent">100%</div><div class="res-label">标准分辨率</div></div> <div class="res-option" data-res="200"><div class="res-percent">200%</div><div class="res-label">高清质量</div></div> <div class="res-option" data-res="400"><div class="res-percent">400%</div><div class="res-label">超清质量</div></div> <div class="res-option" data-res="600"><div class="res-percent">600%</div><div class="res-label">最高质量</div></div> </div> </div> <div class="modal-footer"> <button class="modal-btn cancel-btn" id="cancel-download">取消</button> <button class="modal-btn download-btn" id="confirm-download">下载</button> </div> </div> </div> <div class="download-progress" id="download-progress"> <div>正在生成图片,请稍候...</div> <div class="progress-bar"><div class="progress-fill" id="progress-fill"></div></div> </div> <div class="sort-feedback" id="sortFeedback"></div> <script> // ========== 全局变量 ========== let servers = []; let siteConfig = {}; let sortOrder = 'desc'; // 工具函数 function parseServerId(id) { const parts = id.split('-'); const serverNumber = parseInt(parts[0]); const founderBlocks = parts.slice(1).join('-').split('&'); const founders = founderBlocks.map(block => { const [founderPart, countryPart] = block.split('-'); const [founderName, founderServerId] = founderPart.split('_'); const [countryCode, countryServerId] = countryPart.split('_'); return { name: founderName, founderServerId: parseInt(founderServerId), countryCode, countryServerId: parseInt(countryServerId) }; }); return { serverNumber, founders, isJoint: founders.length > 1, primaryFounder: founders[0].name, allFounderNames: founders.map(f => f.name).join('&') }; } function parseDate(dateStr) { if (dateStr.includes('-')) { const parts = dateStr.split('-'); return new Date(parts[0], parts[1] - 1, parts[2]); } else if (dateStr.includes('.')) { const parts = dateStr.split('.'); return new Date(parts[0], parts[1] - 1, parts[2]); } return new Date(0); } function showSortFeedback(message) { const feedback = document.getElementById('sortFeedback'); if (!feedback) return; feedback.textContent = message; feedback.classList.add('show'); setTimeout(() => { feedback.classList.remove('show'); }, 3000); } // 生成服务器卡片 function generateServerCard(server) { const today = new Date(); const dayOfWeek = today.getDay(); let statusClass = ""; let statusText = ""; let iconClass = "train"; // 解析服务器ID(如果需要ID信息,这里仍保留解析) const idInfo = parseServerId(server.id); // 根据状态显示 if (server.status === "upcoming") { statusClass = "upcoming"; statusText = "即将开启"; iconClass = "clock"; } else if (server.openTime[0] === 0) { statusClass = "closed"; statusText = "关闭"; iconClass = "lock"; } else if (server.openTime[0] === 7) { statusClass = ""; statusText = "开放"; iconClass = "train"; } else { if (server.openTime.includes(dayOfWeek)) { statusClass = ""; statusText = "开放"; iconClass = "train"; } else { statusClass = "today-closed"; statusText = "今日关闭"; iconClass = "calendar-times"; } } // 构建发起人显示(支持多个) const foundersHtml = Array.isArray(server.founder) ? server.founder.join('&') : server.founder; // 构建标签HTML let tagsHtml = ""; server.tags.forEach(tag => { tagsHtml += `<span class="special-tag">${tag}</span>`; }); // 构建开放时间文本 let openTimeText = ""; if (server.status === "upcoming") { openTimeText = "即将开启"; } else if (server.openTime[0] === 0) { openTimeText = "以实际为准"; } else if (server.openTime[0] === 7) { openTimeText = "长期开放"; } else { const dayNames = ["周日", "周一", "周二", "周三", "周四", "周五", "周六"]; openTimeText = "每周" + server.openTime.map(day => dayNames[day]).join("、"); } return ` <div class="server-card ${statusClass}" id="${server.id}" data-date="${server.date}" data-size="${server.size}" data-group="${server.group}" data-version="${server.version}" data-open-time="${server.openTime.join(',')}" data-founder="${Array.isArray(server.founder) ? server.founder.join('&') : server.founder}" data-status="${server.status}"> <h2 class="server-title"> <div class="server-title-content"> <i class="fas fa-${iconClass}"></i> <div class="server-name-container"> <span class="chinese-name">${server.chineseName}</span> ${tagsHtml} <span class="english-name">${server.englishName}</span> </div> </div> </h2> <div class="server-info"> <div class="info-item"> <span class="info-label"><i class="fas fa-user-tie"></i> 发起人</span> <span class="info-value">${foundersHtml}</span> </div> <div class="info-item"> <span class="info-label"><i class="far fa-calendar-alt"></i> 开服日期</span> <span class="info-value">${server.date}</span> </div> <div class="info-item"> <span class="info-label"><i class="fas fa-clock"></i> 开放时间</span> <span class="info-value">${openTimeText}</span> </div> <div class="info-item"> <span class="info-label"><i class="fas fa-expand-arrows-alt"></i> 地图尺寸</span> <span class="info-value">${server.size}</span> </div> <div class="info-item"> <span class="info-label"><i class="fas fa-code-branch"></i> 版本</span> <span class="info-value">${server.version}</span> </div> <div class="info-item"> <span class="info-label"><i class="fas fa-comments"></i> 所属群聊</span> <span class="info-value">${server.group}</span> </div> <div class="info-item"> <span class="info-label"><i class="fas fa-network-wired"></i> IP地址</span> <span class="ip-address">${server.ip}</span> </div> </div> <div class="description"> <strong>简介:</strong> ${server.description} </div> </div> `; } // 渲染服务器列表 function renderServerList() { const container = document.querySelector('.servers-container'); const upcoming = servers.filter(s => s.status === 'upcoming'); const others = servers.filter(s => s.status !== 'upcoming'); container.innerHTML = [...upcoming, ...others].map(s => generateServerCard(s)).join(''); updateStats(); } function updateStats() { const today = new Date(); const dayOfWeek = today.getDay(); let openCount = 0, closedCount = 0, upcomingCount = 0; servers.forEach(s => { if (s.status === 'upcoming') upcomingCount++; else if (s.openTime[0] === 0) closedCount++; else if (s.openTime[0] === 7) openCount++; else if (s.openTime.includes(dayOfWeek)) openCount++; }); const maxId = servers.length ? Math.max(...servers.map(s => parseServerId(s.id).serverNumber)) : 0; document.getElementById('total-count').textContent = maxId; document.getElementById('configured-count').textContent = openCount + upcomingCount; document.getElementById('open-count').textContent = openCount; document.getElementById('closed-count').textContent = closedCount; document.getElementById('upcoming-count').textContent = upcomingCount; } // 页脚配置更新 function updateFooter(config) { // 文档信息列表 const infoList = document.getElementById('footer-info'); if (infoList && config.doc_info) { infoList.innerHTML = config.doc_info.map(item => `<li><i class="${item.icon}"></i> ${item.text}</li>` ).join(''); } // 维护团队列表 const maintList = document.getElementById('footer-maintainers'); if (maintList && config.maintainers) { maintList.innerHTML = config.maintainers.map(name => `<li><i class="fas fa-user"></i> ${name}</li>` ).join(''); } // 注意事项列表 const notesList = document.getElementById('footer-notes'); if (notesList && config.notes) { notesList.innerHTML = config.notes.map(note => `<li><i class="fas fa-exclamation-triangle"></i> ${note}</li>` ).join(''); } // 页脚底部文字 if (config.footer_bottom) { document.getElementById('footer-bottom').innerHTML = `<p>${config.footer_bottom}</p>`; } // 关于页面内的信息 if (config.about) { document.getElementById('settings-about').innerHTML = config.about; } } // ========== 排序与筛选 ========== function parseMapSize(size) { if (!size || size === '未知' || size === '待定' || size === '0x0') return -1; const matches = size.match(/(\d+)\s*[x×]\s*(\d+)/); if (matches && matches.length >= 3) { return parseInt(matches[1]) * parseInt(matches[2]); } const single = size.match(/\d+/); return single ? parseInt(single[0]) : -1; } function filterAndSortServers() { const selectedFounder = document.getElementById('founder-select').value; const hideClosed = document.getElementById('hideClosedToggle').classList.contains('active'); const hideUpcoming = document.getElementById('hideUpcomingToggle').classList.contains('active'); const sortBy = document.getElementById('sort-select').value; let filtered = servers.filter(server => { const founders = Array.isArray(server.founder) ? server.founder : server.founder.split('&').map(s => s.trim()); if (selectedFounder !== 'all' && !founders.includes(selectedFounder)) return false; if (hideClosed && server.openTime[0] === 0 && server.status !== 'upcoming') return false; if (hideUpcoming && server.status === 'upcoming') return false; return true; }); filtered.sort((a, b) => { if (a.status === 'upcoming' && b.status !== 'upcoming') return -1; if (a.status !== 'upcoming' && b.status === 'upcoming') return 1; if (a.status === 'upcoming' && b.status === 'upcoming') return parseDate(a.date) - parseDate(b.date); const dir = sortOrder === 'asc' ? 1 : -1; let av, bv; switch (sortBy) { case 'name': av = a.chineseName; bv = b.chineseName; return dir * av.localeCompare(bv); case 'founder': av = (Array.isArray(a.founder) ? a.founder[0] : a.founder.split('&')[0].trim()); bv = (Array.isArray(b.founder) ? b.founder[0] : b.founder.split('&')[0].trim()); return dir * av.localeCompare(bv); case 'date': return dir * (parseDate(a.date) - parseDate(b.date)); case 'size': av = parseMapSize(a.size); bv = parseMapSize(b.size); if (av === -1 && bv === -1) return 0; if (av === -1) return dir * 1; if (bv === -1) return dir * -1; return dir * (av - bv); case 'group': return dir * a.group.localeCompare(b.group); case 'version': return dir * a.version.localeCompare(b.version); case 'open-time': return dir * (a.openTime.length - b.openTime.length); default: return dir * (parseDate(a.date) - parseDate(b.date)); } }); document.querySelector('.servers-container').innerHTML = filtered.map(s => generateServerCard(s)).join(''); updateStats(); } // ========== 初始化:加载数据 ========== document.addEventListener('DOMContentLoaded', function() { fetch('api/get_servers.php') .then(res => res.json()) .then(data => { // data 应包含 servers 和 config servers = data.servers; siteConfig = data.config || {}; // 渲染页面 renderServerList(); filterAndSortServers(); updateFooter(siteConfig); // 动态生成发起人下拉选项 const founderSelect = document.getElementById('founder-select'); founderSelect.querySelectorAll('option:not([value="all"])').forEach(opt => opt.remove()); if (data.founders && Array.isArray(data.founders)) { data.founders.forEach(name => { const option = document.createElement('option'); option.value = name; option.textContent = name; founderSelect.appendChild(option); }); } // 初始化下载分辨率选项 document.querySelector('.res-option[data-res="100"]').classList.add('selected'); }) .catch(err => { console.error('数据加载失败:', err); alert('无法获取数据,请稍后刷新。'); }); // 排序方向切换 document.getElementById('sort-direction').addEventListener('click', function() { sortOrder = sortOrder === 'asc' ? 'desc' : 'asc'; this.classList.toggle('desc'); filterAndSortServers(); const sortText = document.getElementById('sort-select').selectedOptions[0].text; showSortFeedback(`已按${sortText}${sortOrder === 'desc' ? '降序' : '升序'}排序`); }); // 发起人、排序方式变化 document.getElementById('founder-select').addEventListener('change', function() { filterAndSortServers(); showSortFeedback(`已筛选发起人:${this.selectedOptions[0].text}`); }); document.getElementById('sort-select').addEventListener('change', function() { filterAndSortServers(); const sortText = this.selectedOptions[0].text; showSortFeedback(`已按${sortText}${sortOrder === 'desc' ? '降序' : '升序'}排序`); }); // 设置模态框 const settingsBtn = document.getElementById('settings-btn'); const settingsModal = document.getElementById('settingsModal'); const closeSettings = document.getElementById('closeSettings'); settingsBtn.addEventListener('click', () => { settingsModal.style.display = 'flex'; }); closeSettings.addEventListener('click', () => { settingsModal.style.display = 'none'; }); settingsModal.addEventListener('click', (e) => { if (e.target === settingsModal) settingsModal.style.display = 'none'; }); // 隐藏/显示开关 document.getElementById('hideClosedToggle').addEventListener('click', function() { this.classList.toggle('active'); filterAndSortServers(); }); document.getElementById('hideUpcomingToggle').addEventListener('click', function() { this.classList.toggle('active'); filterAndSortServers(); }); // ---- 下载全图功能 ---- const downloadBtn = document.getElementById('download-btn'); const modal = document.getElementById('download-modal'); const modalContent = document.getElementById('modal-content'); const cancelBtn = document.getElementById('cancel-download'); const confirmBtn = document.getElementById('confirm-download'); const progressDiv = document.getElementById('download-progress'); const progressFill = document.getElementById('progress-fill'); let selectedRes = 100; downloadBtn.addEventListener('click', () => { modal.style.display = 'flex'; setTimeout(() => { modalContent.style.transform = 'translateY(0)'; modalContent.style.opacity = '1'; }, 10); }); cancelBtn.addEventListener('click', () => { modalContent.style.transform = 'translateY(20px)'; modalContent.style.opacity = '0'; setTimeout(() => { modal.style.display = 'none'; }, 300); }); document.querySelectorAll('.res-option').forEach(opt => { opt.addEventListener('click', function() { document.querySelectorAll('.res-option').forEach(o => o.classList.remove('selected')); this.classList.add('selected'); selectedRes = this.dataset.res; }); }); confirmBtn.addEventListener('click', () => { modalContent.style.transform = 'translateY(20px)'; modalContent.style.opacity = '0'; setTimeout(() => { modal.style.display = 'none'; }, 300); progressDiv.style.display = 'block'; progressFill.style.width = '0%'; setTimeout(() => { progressFill.style.width = '30%'; html2canvas(document.querySelector('.container'), { scale: selectedRes / 100, useCORS: true, logging: false, backgroundColor: null, onclone: function(clonedDoc) { clonedDoc.querySelector('.container').style.boxShadow = 'none'; } }).then(canvas => { progressFill.style.width = '90%'; setTimeout(() => { const link = document.createElement('a'); link.href = canvas.toDataURL('image/png'); link.download = `服务器详情_${selectedRes}%_${new Date().toISOString().slice(0,10)}.png`; document.body.appendChild(link); link.click(); document.body.removeChild(link); progressFill.style.width = '100%'; setTimeout(() => { progressDiv.style.display = 'none'; alert('图片下载完成!'); }, 500); }, 500); }).catch(err => { console.error(err); progressDiv.style.display = 'none'; alert('图片生成失败: ' + err.message); }); }, 500); }); // 初始化分辨率默认选中 document.querySelector('.res-option[data-res="100"]').classList.add('selected'); }); </script> </body> </html>
返回
1
。
导航菜单
个人工具
创建账号
登录
命名空间
页面
讨论
大陆简体
查看
阅读
查看源代码
查看历史
更多
搜索
导航
首页
最近更改
随机页面
MediaWiki帮助
特殊页面
工具
链入页面
相关更改
页面信息