php
· 14 KiB · PHP
Bruto
<?php
/**
* 友链状态
*
* @package custom
*
**/
if (!defined('__TYPECHO_ROOT_DIR__')) {
http_response_code(404);
exit;
}
$this->need('module/single/pjax.php');
?>
<!DOCTYPE html>
<html lang="zh">
<head>
<?php $this->need('module/head.php') ?>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="robots" content="noindex, nofollow" />
<meta name="googlebot" content="noindex" />
<link
href="https://cdn.bootcdn.net/ajax/libs/font-awesome/6.7.2/css/all.min.css"
rel="stylesheet"
/>
<style>
:root {
--primary-color: #2c3e50;
--secondary-color: #3498db;
--accent-color: #e74c3c;
--text-color: #34495e;
--background-color: #fff;
--code-background-color: #efefef;
}
body.dark {
--primary-color: #a0c1e6;
--secondary-color: #5dade2;
--accent-color: #e74c3c;
--text-color: #e0e0e0;
--background-color: #1a1a2e;
--code-background-color: #2d2d44;
}
.joe_container {
max-width: 1200px;
margin: 0 auto;
padding: 0 15px;
}
.joe_main {
background-color: var(--background-color);
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
margin-bottom: 20px;
}
.flink-status-container {
font-family: "KingHwa_OldSong", "Noto Serif SC", serif;
padding: 40px 20px;
background-color: var(--background-color);
color: var(--text-color);
display: flex;
flex-direction: column;
align-items: center;
}
.container {
max-width: 900px;
width: 100%;
padding: 0 20px;
}
.header {
text-align: center;
margin-bottom: 40px;
position: relative;
}
h1 {
font-size: 2.8rem;
color: var(--primary-color);
margin: 20px 0;
position: relative;
}
h1::after {
content: "";
display: block;
width: 60%;
height: 3px;
background: var(--secondary-color);
margin: 10px auto 0;
}
.subtitle {
font-size: 1.1rem;
color: #7f8c8d;
max-width: 600px;
margin: 0 auto;
line-height: 1.6;
}
.total-info {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 15px;
margin-top: 30px;
}
@media (min-width: 1200px) {
.total-info {
grid-template-columns: repeat(4, 1fr);
}
}
@media (max-width: 380px) {
.total-info {
grid-template-columns: repeat(1, 1fr);
}
}
.total-status-card {
background: var(--background-color);
border: 1px solid rgba(0, 0, 0, 0.1);
border-radius: 8px;
padding: 15px;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
text-align: center;
font-size: 1rem;
display: flex;
justify-content: space-between;
align-items: center;
transition: all 0.2s ease-in-out;
}
.dark .total-status-card {
border-color: rgba(255, 255, 255, 0.1);
}
.total-status-card span {
font-weight: bold;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.total-status-card:hover {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
transform: translateY(-3px);
}
.status-grid {
display: grid;
gap: 15px;
margin-top: 15px;
}
.status-grid.other {
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
}
.status-grid.error {
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
}
.fail_counts {
margin-right: 10px;
color: #000000a5;
}
.dark .fail_counts {
color: #ffffffa5;
}
.status-card {
display: flex;
background: var(--background-color);
border: 1px solid rgba(0, 0, 0, 0.1);
border-radius: 8px;
padding: 15px;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
text-align: center;
font-size: 1rem;
justify-content: space-between;
align-items: center;
transition: all 0.2s ease-in-out;
}
.dark .status-card {
border-color: rgba(255, 255, 255, 0.1);
}
.status-card:hover {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
transform: translateY(-3px);
}
.status-link {
color: var(--primary-color);
text-decoration: none;
font-weight: bold;
transition: all 0.2s ease-in-out;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.status-link:hover {
color: var(--secondary-color);
}
.status-dot {
display: inline-block;
width: 12px;
height: 12px;
border-radius: 50%;
margin-right: 6px;
position: relative;
}
.status-dot::before {
content: "";
position: absolute;
top: -4px;
left: -4px;
width: 20px;
height: 20px;
border-radius: 50%;
animation: pulse 1.5s infinite;
}
@keyframes pulse {
0% {
transform: scale(1);
opacity: 1;
}
50% {
transform: scale(1.5);
opacity: 0.5;
}
100% {
transform: scale(1);
opacity: 1;
}
}
.status-normal {
background: green;
}
.status-normal::before {
background-color: rgba(0, 128, 0, 0.2);
}
.status-slow {
background: rgb(255, 200, 0);
}
.status-slow::before {
background-color: rgba(255, 174, 0, 0.2);
}
.status-error {
background: red;
}
.status-error::before {
background-color: rgba(255, 0, 0, 0.2);
}
footer {
margin-top: 50px;
padding-top: 30px;
border-top: 1px solid #ecf0f1;
width: 100%;
text-align: center;
color: #95a5a6;
}
.dark footer {
border-top: 1px solid rgba(255, 255, 255, 0.1);
}
footer a {
color: #95a5a6;
text-decoration: none;
transition: all 0.2s ease-in-out;
}
footer a:hover {
color: var(--secondary-color);
}
</style>
</head>
<body>
<?php $this->need('module/header.php') ?>
<div class="joe_container">
<div class="joe_main">
<div class="flink-status-container">
<div class="container">
<header class="header">
<h1>友链状态监控</h1>
<p class="subtitle">更新时间:<span id="update-time"></span></p>
</header>
<section class="total-info" id="total-info">
<div class="total-status-card">
<div class="total-status-card-title">
<i class="fa-solid fa-users"></i>
<span>友链总数</span>
</div>
<span id="total-links">加载中...</span>
</div>
<div class="total-status-card">
<div class="total-status-card-title">
<i class="fa-solid fa-circle-check"></i>
<span>正常友链</span>
</div>
<span id="normal-links">加载中...</span>
</div>
<div class="total-status-card">
<div class="total-status-card-title">
<i class="fa-solid fa-circle-exclamation"></i>
<span>慢速友链</span>
</div>
<span id="slow-links">加载中...</span>
</div>
<div class="total-status-card">
<div class="total-status-card-title">
<i class="fa-solid fa-circle-xmark"></i>
<span>错误友链</span>
</div>
<span id="error-links">加载中...</span>
</div>
</section>
<hr
style="
width: 100%;
margin: 15px 0;
border: 0;
border-top: 2px solid #00000021;
"
/>
<h2 class="error-link-h2">失效友链</h2>
<section class="status-grid error" id="status-container-error"></section>
<hr
class="error-link-hr"
style="
width: 100%;
margin: 15px 0;
border: 0;
border-top: 2px solid #00000021;
"
/>
<h2 class="other-link-h2">其他友链</h2>
<section class="status-grid other" id="status-container-other"></section>
<footer>
<script defer src="https://cn.vercount.one/js"></script>
<div style="margin-bottom: 0.5em">
网站总请求量:<span id="vercount_value_site_pv">🤕</span> |
独立访客数:<span id="vercount_value_site_uv">🤕</span>
</div>
</footer>
</div>
</div>
<?php $this->need('module/single/comment.php'); ?>
</div>
<?php joe\isPc() ? $this->need('module/aside.php') : null ?>
</div>
<script>
// 检测暗黑模式
function checkDarkMode() {
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
document.body.classList.add('dark');
}
}
// 初始检测
checkDarkMode();
// 监听暗黑模式变化
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => {
if (e.matches) {
document.body.classList.add('dark');
} else {
document.body.classList.remove('dark');
}
});
// 加载友链数据
fetch("https://你的实际部署域名/result.json")
.then((response) => response.json())
.then((data) => {
// 更新更新时间
const updateTime = data.timestamp;
const updateTimeElement = document.getElementById("update-time");
updateTimeElement.textContent = updateTime;
const container_error = document.getElementById(
"status-container-error"
);
const container_other = document.getElementById(
"status-container-other"
);
let statusHTML = "";
const sortedLinks = data.link_status.sort((a, b) =>
a.latency === -1 ? -1 : b.latency === -1 ? 1 : b.latency - a.latency
);
let totalLinks = 0;
let normalLinks = 0;
let slowLinks = 0;
let errorLinks = 0;
let errorLinksHTML = "";
let otherLinksHTML = "";
sortedLinks.forEach((link) => {
totalLinks++;
let statusClass = "status-normal";
let extraInfo = "";
if (link.latency === -1) {
statusClass = "status-error";
errorLinks++;
extraInfo = `<span class="fail_counts">已持续${link.fail_count}次</span>`;
errorLinksHTML += `<div class="status-card">
<a class="status-link" href="${link.link}" target="_blank" rel="noopener noreferrer noreferrer">${link.name}</a>
<div class="fail-details">
${extraInfo}
<span class="status-dot ${statusClass}"></span>
</div>
</div>`;
} else if (link.latency > 4) {
statusClass = "status-slow";
slowLinks++;
otherLinksHTML += `<div class="status-card">
<a class="status-link" href="${link.link}" target="_blank" rel="noopener noreferrer noreferrer">${link.name}</a>
<span class="status-dot ${statusClass}"></span>
</div>`;
} else {
normalLinks++;
otherLinksHTML += `<div class="status-card">
<a class="status-link" href="${link.link}" target="_blank" rel="noopener noreferrer noreferrer">${link.name}</a>
<span class="status-dot ${statusClass}"></span>
</div>`;
}
});
if (errorLinksHTML) {
container_error.innerHTML = errorLinksHTML;
} else {
// 如果没有错误链接,移除标题和分割线
const errorTitle = document.querySelector(".error-link-h2");
const errorHr = document.querySelector(".error-link-hr");
if (errorTitle) errorTitle.remove();
if (errorHr) errorHr.remove();
}
if (otherLinksHTML) {
container_other.innerHTML = otherLinksHTML;
}
document.getElementById("total-links").textContent = totalLinks;
document.getElementById("normal-links").textContent = normalLinks;
document.getElementById("slow-links").textContent = slowLinks;
document.getElementById("error-links").textContent = errorLinks;
})
.catch((error) => console.error("Error loading status:", error));
</script>
</body>
</html>
<?php $this->need('module/footer.php') ?>
| 1 | <?php |
| 2 | |
| 3 | /** |
| 4 | * 友链状态 |
| 5 | * |
| 6 | * @package custom |
| 7 | * |
| 8 | **/ |
| 9 | |
| 10 | if (!defined('__TYPECHO_ROOT_DIR__')) { |
| 11 | http_response_code(404); |
| 12 | exit; |
| 13 | } |
| 14 | $this->need('module/single/pjax.php'); |
| 15 | ?> |
| 16 | |
| 17 | <!DOCTYPE html> |
| 18 | <html lang="zh"> |
| 19 | <head> |
| 20 | <?php $this->need('module/head.php') ?> |
| 21 | <meta charset="UTF-8" /> |
| 22 | <meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
| 23 | <meta name="robots" content="noindex, nofollow" /> |
| 24 | <meta name="googlebot" content="noindex" /> |
| 25 | <link |
| 26 | href="https://cdn.bootcdn.net/ajax/libs/font-awesome/6.7.2/css/all.min.css" |
| 27 | rel="stylesheet" |
| 28 | /> |
| 29 | <style> |
| 30 | :root { |
| 31 | --primary-color: #2c3e50; |
| 32 | --secondary-color: #3498db; |
| 33 | --accent-color: #e74c3c; |
| 34 | --text-color: #34495e; |
| 35 | --background-color: #fff; |
| 36 | --code-background-color: #efefef; |
| 37 | } |
| 38 | |
| 39 | body.dark { |
| 40 | --primary-color: #a0c1e6; |
| 41 | --secondary-color: #5dade2; |
| 42 | --accent-color: #e74c3c; |
| 43 | --text-color: #e0e0e0; |
| 44 | --background-color: #1a1a2e; |
| 45 | --code-background-color: #2d2d44; |
| 46 | } |
| 47 | |
| 48 | .joe_container { |
| 49 | max-width: 1200px; |
| 50 | margin: 0 auto; |
| 51 | padding: 0 15px; |
| 52 | } |
| 53 | |
| 54 | .joe_main { |
| 55 | background-color: var(--background-color); |
| 56 | padding: 20px; |
| 57 | border-radius: 8px; |
| 58 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05); |
| 59 | margin-bottom: 20px; |
| 60 | } |
| 61 | |
| 62 | .flink-status-container { |
| 63 | font-family: "KingHwa_OldSong", "Noto Serif SC", serif; |
| 64 | padding: 40px 20px; |
| 65 | background-color: var(--background-color); |
| 66 | color: var(--text-color); |
| 67 | display: flex; |
| 68 | flex-direction: column; |
| 69 | align-items: center; |
| 70 | } |
| 71 | |
| 72 | .container { |
| 73 | max-width: 900px; |
| 74 | width: 100%; |
| 75 | padding: 0 20px; |
| 76 | } |
| 77 | |
| 78 | .header { |
| 79 | text-align: center; |
| 80 | margin-bottom: 40px; |
| 81 | position: relative; |
| 82 | } |
| 83 | |
| 84 | h1 { |
| 85 | font-size: 2.8rem; |
| 86 | color: var(--primary-color); |
| 87 | margin: 20px 0; |
| 88 | position: relative; |
| 89 | } |
| 90 | |
| 91 | h1::after { |
| 92 | content: ""; |
| 93 | display: block; |
| 94 | width: 60%; |
| 95 | height: 3px; |
| 96 | background: var(--secondary-color); |
| 97 | margin: 10px auto 0; |
| 98 | } |
| 99 | |
| 100 | .subtitle { |
| 101 | font-size: 1.1rem; |
| 102 | color: #7f8c8d; |
| 103 | max-width: 600px; |
| 104 | margin: 0 auto; |
| 105 | line-height: 1.6; |
| 106 | } |
| 107 | |
| 108 | .total-info { |
| 109 | display: grid; |
| 110 | grid-template-columns: repeat(2, 1fr); |
| 111 | gap: 15px; |
| 112 | margin-top: 30px; |
| 113 | } |
| 114 | |
| 115 | @media (min-width: 1200px) { |
| 116 | .total-info { |
| 117 | grid-template-columns: repeat(4, 1fr); |
| 118 | } |
| 119 | } |
| 120 | |
| 121 | @media (max-width: 380px) { |
| 122 | .total-info { |
| 123 | grid-template-columns: repeat(1, 1fr); |
| 124 | } |
| 125 | } |
| 126 | |
| 127 | .total-status-card { |
| 128 | background: var(--background-color); |
| 129 | border: 1px solid rgba(0, 0, 0, 0.1); |
| 130 | border-radius: 8px; |
| 131 | padding: 15px; |
| 132 | box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1); |
| 133 | text-align: center; |
| 134 | font-size: 1rem; |
| 135 | display: flex; |
| 136 | justify-content: space-between; |
| 137 | align-items: center; |
| 138 | transition: all 0.2s ease-in-out; |
| 139 | } |
| 140 | |
| 141 | .dark .total-status-card { |
| 142 | border-color: rgba(255, 255, 255, 0.1); |
| 143 | } |
| 144 | |
| 145 | .total-status-card span { |
| 146 | font-weight: bold; |
| 147 | white-space: nowrap; |
| 148 | overflow: hidden; |
| 149 | text-overflow: ellipsis; |
| 150 | } |
| 151 | |
| 152 | .total-status-card:hover { |
| 153 | box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); |
| 154 | transform: translateY(-3px); |
| 155 | } |
| 156 | |
| 157 | .status-grid { |
| 158 | display: grid; |
| 159 | gap: 15px; |
| 160 | margin-top: 15px; |
| 161 | } |
| 162 | |
| 163 | .status-grid.other { |
| 164 | grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); |
| 165 | } |
| 166 | |
| 167 | .status-grid.error { |
| 168 | grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); |
| 169 | } |
| 170 | |
| 171 | .fail_counts { |
| 172 | margin-right: 10px; |
| 173 | color: #000000a5; |
| 174 | } |
| 175 | |
| 176 | .dark .fail_counts { |
| 177 | color: #ffffffa5; |
| 178 | } |
| 179 | |
| 180 | .status-card { |
| 181 | display: flex; |
| 182 | background: var(--background-color); |
| 183 | border: 1px solid rgba(0, 0, 0, 0.1); |
| 184 | border-radius: 8px; |
| 185 | padding: 15px; |
| 186 | box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1); |
| 187 | text-align: center; |
| 188 | font-size: 1rem; |
| 189 | justify-content: space-between; |
| 190 | align-items: center; |
| 191 | transition: all 0.2s ease-in-out; |
| 192 | } |
| 193 | |
| 194 | .dark .status-card { |
| 195 | border-color: rgba(255, 255, 255, 0.1); |
| 196 | } |
| 197 | |
| 198 | .status-card:hover { |
| 199 | box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); |
| 200 | transform: translateY(-3px); |
| 201 | } |
| 202 | |
| 203 | .status-link { |
| 204 | color: var(--primary-color); |
| 205 | text-decoration: none; |
| 206 | font-weight: bold; |
| 207 | transition: all 0.2s ease-in-out; |
| 208 | white-space: nowrap; |
| 209 | overflow: hidden; |
| 210 | text-overflow: ellipsis; |
| 211 | } |
| 212 | |
| 213 | .status-link:hover { |
| 214 | color: var(--secondary-color); |
| 215 | } |
| 216 | |
| 217 | .status-dot { |
| 218 | display: inline-block; |
| 219 | width: 12px; |
| 220 | height: 12px; |
| 221 | border-radius: 50%; |
| 222 | margin-right: 6px; |
| 223 | position: relative; |
| 224 | } |
| 225 | |
| 226 | .status-dot::before { |
| 227 | content: ""; |
| 228 | position: absolute; |
| 229 | top: -4px; |
| 230 | left: -4px; |
| 231 | width: 20px; |
| 232 | height: 20px; |
| 233 | border-radius: 50%; |
| 234 | animation: pulse 1.5s infinite; |
| 235 | } |
| 236 | |
| 237 | @keyframes pulse { |
| 238 | 0% { |
| 239 | transform: scale(1); |
| 240 | opacity: 1; |
| 241 | } |
| 242 | 50% { |
| 243 | transform: scale(1.5); |
| 244 | opacity: 0.5; |
| 245 | } |
| 246 | 100% { |
| 247 | transform: scale(1); |
| 248 | opacity: 1; |
| 249 | } |
| 250 | } |
| 251 | |
| 252 | .status-normal { |
| 253 | background: green; |
| 254 | } |
| 255 | |
| 256 | .status-normal::before { |
| 257 | background-color: rgba(0, 128, 0, 0.2); |
| 258 | } |
| 259 | |
| 260 | .status-slow { |
| 261 | background: rgb(255, 200, 0); |
| 262 | } |
| 263 | |
| 264 | .status-slow::before { |
| 265 | background-color: rgba(255, 174, 0, 0.2); |
| 266 | } |
| 267 | |
| 268 | .status-error { |
| 269 | background: red; |
| 270 | } |
| 271 | |
| 272 | .status-error::before { |
| 273 | background-color: rgba(255, 0, 0, 0.2); |
| 274 | } |
| 275 | |
| 276 | footer { |
| 277 | margin-top: 50px; |
| 278 | padding-top: 30px; |
| 279 | border-top: 1px solid #ecf0f1; |
| 280 | width: 100%; |
| 281 | text-align: center; |
| 282 | color: #95a5a6; |
| 283 | } |
| 284 | |
| 285 | .dark footer { |
| 286 | border-top: 1px solid rgba(255, 255, 255, 0.1); |
| 287 | } |
| 288 | |
| 289 | footer a { |
| 290 | color: #95a5a6; |
| 291 | text-decoration: none; |
| 292 | transition: all 0.2s ease-in-out; |
| 293 | } |
| 294 | |
| 295 | footer a:hover { |
| 296 | color: var(--secondary-color); |
| 297 | } |
| 298 | </style> |
| 299 | </head> |
| 300 | |
| 301 | <body> |
| 302 | <?php $this->need('module/header.php') ?> |
| 303 | <div class="joe_container"> |
| 304 | <div class="joe_main"> |
| 305 | <div class="flink-status-container"> |
| 306 | <div class="container"> |
| 307 | <header class="header"> |
| 308 | <h1>友链状态监控</h1> |
| 309 | <p class="subtitle">更新时间:<span id="update-time"></span></p> |
| 310 | </header> |
| 311 | <section class="total-info" id="total-info"> |
| 312 | <div class="total-status-card"> |
| 313 | <div class="total-status-card-title"> |
| 314 | <i class="fa-solid fa-users"></i> |
| 315 | <span>友链总数</span> |
| 316 | </div> |
| 317 | <span id="total-links">加载中...</span> |
| 318 | </div> |
| 319 | <div class="total-status-card"> |
| 320 | <div class="total-status-card-title"> |
| 321 | <i class="fa-solid fa-circle-check"></i> |
| 322 | <span>正常友链</span> |
| 323 | </div> |
| 324 | <span id="normal-links">加载中...</span> |
| 325 | </div> |
| 326 | <div class="total-status-card"> |
| 327 | <div class="total-status-card-title"> |
| 328 | <i class="fa-solid fa-circle-exclamation"></i> |
| 329 | <span>慢速友链</span> |
| 330 | </div> |
| 331 | <span id="slow-links">加载中...</span> |
| 332 | </div> |
| 333 | <div class="total-status-card"> |
| 334 | <div class="total-status-card-title"> |
| 335 | <i class="fa-solid fa-circle-xmark"></i> |
| 336 | <span>错误友链</span> |
| 337 | </div> |
| 338 | <span id="error-links">加载中...</span> |
| 339 | </div> |
| 340 | </section> |
| 341 | <hr |
| 342 | style=" |
| 343 | width: 100%; |
| 344 | margin: 15px 0; |
| 345 | border: 0; |
| 346 | border-top: 2px solid #00000021; |
| 347 | " |
| 348 | /> |
| 349 | <h2 class="error-link-h2">失效友链</h2> |
| 350 | <section class="status-grid error" id="status-container-error"></section> |
| 351 | <hr |
| 352 | class="error-link-hr" |
| 353 | style=" |
| 354 | width: 100%; |
| 355 | margin: 15px 0; |
| 356 | border: 0; |
| 357 | border-top: 2px solid #00000021; |
| 358 | " |
| 359 | /> |
| 360 | <h2 class="other-link-h2">其他友链</h2> |
| 361 | <section class="status-grid other" id="status-container-other"></section> |
| 362 | <footer> |
| 363 | <script defer src="https://cn.vercount.one/js"></script> |
| 364 | <div style="margin-bottom: 0.5em"> |
| 365 | 网站总请求量:<span id="vercount_value_site_pv">🤕</span> | |
| 366 | 独立访客数:<span id="vercount_value_site_uv">🤕</span> |
| 367 | </div> |
| 368 | </footer> |
| 369 | </div> |
| 370 | </div> |
| 371 | <?php $this->need('module/single/comment.php'); ?> |
| 372 | </div> |
| 373 | <?php joe\isPc() ? $this->need('module/aside.php') : null ?> |
| 374 | </div> |
| 375 | <script> |
| 376 | // 检测暗黑模式 |
| 377 | function checkDarkMode() { |
| 378 | if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) { |
| 379 | document.body.classList.add('dark'); |
| 380 | } |
| 381 | } |
| 382 | |
| 383 | // 初始检测 |
| 384 | checkDarkMode(); |
| 385 | |
| 386 | // 监听暗黑模式变化 |
| 387 | window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => { |
| 388 | if (e.matches) { |
| 389 | document.body.classList.add('dark'); |
| 390 | } else { |
| 391 | document.body.classList.remove('dark'); |
| 392 | } |
| 393 | }); |
| 394 | |
| 395 | // 加载友链数据 |
| 396 | fetch("https://你的实际部署域名/result.json") |
| 397 | .then((response) => response.json()) |
| 398 | .then((data) => { |
| 399 | // 更新更新时间 |
| 400 | const updateTime = data.timestamp; |
| 401 | const updateTimeElement = document.getElementById("update-time"); |
| 402 | updateTimeElement.textContent = updateTime; |
| 403 | const container_error = document.getElementById( |
| 404 | "status-container-error" |
| 405 | ); |
| 406 | const container_other = document.getElementById( |
| 407 | "status-container-other" |
| 408 | ); |
| 409 | let statusHTML = ""; |
| 410 | const sortedLinks = data.link_status.sort((a, b) => |
| 411 | a.latency === -1 ? -1 : b.latency === -1 ? 1 : b.latency - a.latency |
| 412 | ); |
| 413 | let totalLinks = 0; |
| 414 | let normalLinks = 0; |
| 415 | let slowLinks = 0; |
| 416 | let errorLinks = 0; |
| 417 | let errorLinksHTML = ""; |
| 418 | let otherLinksHTML = ""; |
| 419 | sortedLinks.forEach((link) => { |
| 420 | totalLinks++; |
| 421 | let statusClass = "status-normal"; |
| 422 | let extraInfo = ""; |
| 423 | if (link.latency === -1) { |
| 424 | statusClass = "status-error"; |
| 425 | errorLinks++; |
| 426 | extraInfo = `<span class="fail_counts">已持续${link.fail_count}次</span>`; |
| 427 | errorLinksHTML += `<div class="status-card"> |
| 428 | <a class="status-link" href="${link.link}" target="_blank" rel="noopener noreferrer noreferrer">${link.name}</a> |
| 429 | <div class="fail-details"> |
| 430 | ${extraInfo} |
| 431 | <span class="status-dot ${statusClass}"></span> |
| 432 | </div> |
| 433 | </div>`; |
| 434 | } else if (link.latency > 4) { |
| 435 | statusClass = "status-slow"; |
| 436 | slowLinks++; |
| 437 | otherLinksHTML += `<div class="status-card"> |
| 438 | <a class="status-link" href="${link.link}" target="_blank" rel="noopener noreferrer noreferrer">${link.name}</a> |
| 439 | <span class="status-dot ${statusClass}"></span> |
| 440 | </div>`; |
| 441 | } else { |
| 442 | normalLinks++; |
| 443 | otherLinksHTML += `<div class="status-card"> |
| 444 | <a class="status-link" href="${link.link}" target="_blank" rel="noopener noreferrer noreferrer">${link.name}</a> |
| 445 | <span class="status-dot ${statusClass}"></span> |
| 446 | </div>`; |
| 447 | } |
| 448 | }); |
| 449 | if (errorLinksHTML) { |
| 450 | container_error.innerHTML = errorLinksHTML; |
| 451 | } else { |
| 452 | // 如果没有错误链接,移除标题和分割线 |
| 453 | const errorTitle = document.querySelector(".error-link-h2"); |
| 454 | const errorHr = document.querySelector(".error-link-hr"); |
| 455 | if (errorTitle) errorTitle.remove(); |
| 456 | if (errorHr) errorHr.remove(); |
| 457 | } |
| 458 | if (otherLinksHTML) { |
| 459 | container_other.innerHTML = otherLinksHTML; |
| 460 | } |
| 461 | document.getElementById("total-links").textContent = totalLinks; |
| 462 | document.getElementById("normal-links").textContent = normalLinks; |
| 463 | document.getElementById("slow-links").textContent = slowLinks; |
| 464 | document.getElementById("error-links").textContent = errorLinks; |
| 465 | }) |
| 466 | .catch((error) => console.error("Error loading status:", error)); |
| 467 | </script> |
| 468 | </body> |
| 469 | </html> |
| 470 | <?php $this->need('module/footer.php') ?> |