php(檔案已創建)
| @@ -0,0 +1,470 @@ | |||
| 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') ?> | |
上一頁
下一頁