Última actividad 2 months ago

友链状态页面

Joe

qxzhan's Avatar qxzhan revisó este gist 2 months ago. Ir a la revisión

1 file changed, 470 insertions

php(archivo creado)

@@ -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') ?>
Siguiente Anterior