php
· 7.7 KiB · PHP
Ham
<?php
/**
* 友链
*
* @package custom
*
**/
if (!defined('__TYPECHO_ROOT_DIR__')) {
http_response_code(404);
exit;
}
$this->need('module/single/pjax.php');
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<?php $this->need('module/head.php') ?>
<link rel="stylesheet" href="<?= joe\theme_url('assets/css/joe.friend.css') ?>">
<style>
.status-tag {
position: absolute;
top: 0px;
right: 0px;
padding: 3px 8px;
border-radius: 0px 12px 0px 12px;
font-size: 12px;
color: white;
font-weight: bold;
transition: font-size 0.3s ease-out, width 0.3s ease-out, opacity 0.3s ease-out;
z-index: 1;
}
.joe_detail__friends-item:hover .status-tag {
font-size: 0px;
opacity: 0;
}
/* 固态颜色 */
.status-tag-green {
background-color: #005E00; /* 绿色 */
}
.status-tag-light-yellow {
background-color: #FED101; /* 浅黄色 */
}
.status-tag-dark-yellow {
background-color: #F0B606; /* 深黄色 */
}
.status-tag-red {
background-color: #B90000; /* 红色 */
}
/* 修改卡片样式,使用头像作为背景 */
.joe_detail__friends-item .contain {
position: relative;
overflow: hidden;
background: rgba(255, 255, 255, 0.1) !important;
backdrop-filter: blur(10px);
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
border-radius: 12px;
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.joe_detail__friends-item .contain::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-image: var(--bg-image);
background-size: cover;
background-position: center;
opacity: 0.5;
z-index: -1;
border-radius: 12px;
}
.joe_detail__friends-item .contain:hover {
transform: translateY(-5px);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
}
.joe_detail__friends-item .content {
position: relative;
z-index: 2;
}
.joe_detail__friends-item .title {
color: #fff;
text-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
font-weight: bold;
}
.joe_detail__friends-item .desc {
color: rgba(255, 255, 255, 0.9);
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
}
.joe_detail__friends-item .avatar {
border: 2px solid rgba(255, 255, 255, 0.8);
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
}
</style>
</head>
<body>
<?php $this->need('module/header.php'); ?>
<div id="Joe">
<div class="joe_container">
<main class="joe_main">
<div class="joe_detail" data-cid="<?= $this->cid ?>">
<?php $this->need('module/single/batten.php'); ?>
<?php $this->need('module/single/article.php'); ?>
<?php
$friends = think\facade\Db::name('friends')->where('status', 1)->whereFindInSet('position', 'single')->order('order', 'desc')->select()->toArray();
?>
<?php if (sizeof($friends) > 0 && ($this->options->JFriendsSpiderHide != 'on' || !joe\detectSpider())) : ?>
<style>
.joe_detail__article {
margin-bottom: 0px;
}
</style>
<ul class="joe_detail__friends">
<?php
if ($this->options->JFriends_shuffle == 'on') shuffle($friends);
foreach ($friends as $item) :
?>
<li class="joe_detail__friends-item">
<a class="contain" href="<?= $item['url'] ?>" target="_blank" rel="<?= $item['rel'] ?>" referrer="unsafe-url" style="--bg-image: url('<?= $item['logo'] ?>')">
<span class="title"><?= $item['title'] ?></span>
<div class="content">
<div class="desc"><?= $item['description'] ?></div>
<img referrerpolicy="no-referrer" rel="noreferrer" width="40" height="40" class="avatar lazyload" onerror="Joe.avatarError(this)" src="<?= joe\getAvatarLazyload(); ?>" data-src="<?= $item['logo'] ?>" alt="<?= $item['title'] ?>" />
</div>
</a>
</li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
<?php
if ($this->options->JFriends_Submit == 'on') $this->need('module/friends/submit.php');
?>
<?php $this->need('module/single/handle.php'); ?>
<?php $this->need('module/single/copyright.php'); ?>
</div>
<?php $this->need('module/single/comment.php'); ?>
</main>
<?php joe\isPc() ? $this->need('module/aside.php') : null ?>
</div>
<?php $this->need('module/bottom.php'); ?>
</div>
<?php $this->need('module/footer.php') ?>
<script>
function addStatusTagsWithCache(jsonUrl) {
const cacheKey = "statusTagsData";
const cacheExpirationTime = 30 * 60 * 1000; // 半小时
function applyStatusTags(data) {
const linkStatus = data.link_status;
document.querySelectorAll('.joe_detail__friends-item').forEach(card => {
const linkAnchor = card.querySelector('a.contain');
if (!linkAnchor) return;
const link = linkAnchor.href.replace(/\/$/, '');
const statusTag = document.createElement('div');
statusTag.classList.add('status-tag');
let matched = false;
// 查找链接状态
const status = linkStatus.find(item => item.link.replace(/\/$/, '') === link);
if (status) {
let latencyText = '未知';
let className = 'status-tag-red'; // 默认红色
if (status.latency === -1) {
latencyText = '未知';
} else {
latencyText = status.latency.toFixed(2) + ' s';
if (status.latency <= 2) {
className = 'status-tag-green';
} else if (status.latency <= 5) {
className = 'status-tag-light-yellow';
} else if (status.latency <= 10) {
className = 'status-tag-dark-yellow';
}
}
statusTag.textContent = latencyText;
statusTag.classList.add(className);
matched = true;
}
if (matched) {
card.style.position = 'relative';
card.appendChild(statusTag);
}
});
}
function fetchDataAndUpdateUI() {
fetch(jsonUrl)
.then(response => response.json())
.then(data => {
applyStatusTags(data);
const cacheData = {
data: data,
timestamp: Date.now()
};
localStorage.setItem(cacheKey, JSON.stringify(cacheData));
})
.catch(error => console.error('Error fetching test-flink result.json:', error));
}
const cachedData = localStorage.getItem(cacheKey);
if (cachedData) {
const { data, timestamp } = JSON.parse(cachedData);
if (Date.now() - timestamp < cacheExpirationTime) {
applyStatusTags(data);
return;
}
}
fetchDataAndUpdateUI();
}
setTimeout(() => {
addStatusTagsWithCache('https://你的部署地址/result.json');
}, 0);
</script>
</body>
</html>
| 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 | <!DOCTYPE html> |
| 17 | <html lang="zh-CN"> |
| 18 | |
| 19 | <head> |
| 20 | <?php $this->need('module/head.php') ?> |
| 21 | <link rel="stylesheet" href="<?= joe\theme_url('assets/css/joe.friend.css') ?>"> |
| 22 | <style> |
| 23 | .status-tag { |
| 24 | position: absolute; |
| 25 | top: 0px; |
| 26 | right: 0px; |
| 27 | padding: 3px 8px; |
| 28 | border-radius: 0px 12px 0px 12px; |
| 29 | font-size: 12px; |
| 30 | color: white; |
| 31 | font-weight: bold; |
| 32 | transition: font-size 0.3s ease-out, width 0.3s ease-out, opacity 0.3s ease-out; |
| 33 | z-index: 1; |
| 34 | } |
| 35 | .joe_detail__friends-item:hover .status-tag { |
| 36 | font-size: 0px; |
| 37 | opacity: 0; |
| 38 | } |
| 39 | /* 固态颜色 */ |
| 40 | .status-tag-green { |
| 41 | background-color: #005E00; /* 绿色 */ |
| 42 | } |
| 43 | .status-tag-light-yellow { |
| 44 | background-color: #FED101; /* 浅黄色 */ |
| 45 | } |
| 46 | .status-tag-dark-yellow { |
| 47 | background-color: #F0B606; /* 深黄色 */ |
| 48 | } |
| 49 | .status-tag-red { |
| 50 | background-color: #B90000; /* 红色 */ |
| 51 | } |
| 52 | |
| 53 | /* 修改卡片样式,使用头像作为背景 */ |
| 54 | .joe_detail__friends-item .contain { |
| 55 | position: relative; |
| 56 | overflow: hidden; |
| 57 | background: rgba(255, 255, 255, 0.1) !important; |
| 58 | backdrop-filter: blur(10px); |
| 59 | box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1); |
| 60 | border-radius: 12px; |
| 61 | transition: transform 0.3s ease, box-shadow 0.3s ease; |
| 62 | } |
| 63 | |
| 64 | .joe_detail__friends-item .contain::before { |
| 65 | content: ''; |
| 66 | position: absolute; |
| 67 | top: 0; |
| 68 | left: 0; |
| 69 | right: 0; |
| 70 | bottom: 0; |
| 71 | background-image: var(--bg-image); |
| 72 | background-size: cover; |
| 73 | background-position: center; |
| 74 | opacity: 0.5; |
| 75 | z-index: -1; |
| 76 | border-radius: 12px; |
| 77 | } |
| 78 | |
| 79 | .joe_detail__friends-item .contain:hover { |
| 80 | transform: translateY(-5px); |
| 81 | box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15); |
| 82 | } |
| 83 | |
| 84 | .joe_detail__friends-item .content { |
| 85 | position: relative; |
| 86 | z-index: 2; |
| 87 | } |
| 88 | |
| 89 | .joe_detail__friends-item .title { |
| 90 | color: #fff; |
| 91 | text-shadow: 0 1px 3px rgba(0, 0, 0, 0.5); |
| 92 | font-weight: bold; |
| 93 | } |
| 94 | |
| 95 | .joe_detail__friends-item .desc { |
| 96 | color: rgba(255, 255, 255, 0.9); |
| 97 | text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3); |
| 98 | } |
| 99 | |
| 100 | .joe_detail__friends-item .avatar { |
| 101 | border: 2px solid rgba(255, 255, 255, 0.8); |
| 102 | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2); |
| 103 | } |
| 104 | </style> |
| 105 | </head> |
| 106 | |
| 107 | <body> |
| 108 | <?php $this->need('module/header.php'); ?> |
| 109 | <div id="Joe"> |
| 110 | <div class="joe_container"> |
| 111 | <main class="joe_main"> |
| 112 | <div class="joe_detail" data-cid="<?= $this->cid ?>"> |
| 113 | <?php $this->need('module/single/batten.php'); ?> |
| 114 | <?php $this->need('module/single/article.php'); ?> |
| 115 | <?php |
| 116 | $friends = think\facade\Db::name('friends')->where('status', 1)->whereFindInSet('position', 'single')->order('order', 'desc')->select()->toArray(); |
| 117 | ?> |
| 118 | <?php if (sizeof($friends) > 0 && ($this->options->JFriendsSpiderHide != 'on' || !joe\detectSpider())) : ?> |
| 119 | <style> |
| 120 | .joe_detail__article { |
| 121 | margin-bottom: 0px; |
| 122 | } |
| 123 | </style> |
| 124 | <ul class="joe_detail__friends"> |
| 125 | <?php |
| 126 | if ($this->options->JFriends_shuffle == 'on') shuffle($friends); |
| 127 | foreach ($friends as $item) : |
| 128 | ?> |
| 129 | <li class="joe_detail__friends-item"> |
| 130 | <a class="contain" href="<?= $item['url'] ?>" target="_blank" rel="<?= $item['rel'] ?>" referrer="unsafe-url" style="--bg-image: url('<?= $item['logo'] ?>')"> |
| 131 | <span class="title"><?= $item['title'] ?></span> |
| 132 | <div class="content"> |
| 133 | <div class="desc"><?= $item['description'] ?></div> |
| 134 | <img referrerpolicy="no-referrer" rel="noreferrer" width="40" height="40" class="avatar lazyload" onerror="Joe.avatarError(this)" src="<?= joe\getAvatarLazyload(); ?>" data-src="<?= $item['logo'] ?>" alt="<?= $item['title'] ?>" /> |
| 135 | </div> |
| 136 | </a> |
| 137 | </li> |
| 138 | <?php endforeach; ?> |
| 139 | </ul> |
| 140 | <?php endif; ?> |
| 141 | <?php |
| 142 | if ($this->options->JFriends_Submit == 'on') $this->need('module/friends/submit.php'); |
| 143 | ?> |
| 144 | <?php $this->need('module/single/handle.php'); ?> |
| 145 | <?php $this->need('module/single/copyright.php'); ?> |
| 146 | </div> |
| 147 | <?php $this->need('module/single/comment.php'); ?> |
| 148 | </main> |
| 149 | <?php joe\isPc() ? $this->need('module/aside.php') : null ?> |
| 150 | </div> |
| 151 | <?php $this->need('module/bottom.php'); ?> |
| 152 | </div> |
| 153 | <?php $this->need('module/footer.php') ?> |
| 154 | <script> |
| 155 | function addStatusTagsWithCache(jsonUrl) { |
| 156 | const cacheKey = "statusTagsData"; |
| 157 | const cacheExpirationTime = 30 * 60 * 1000; // 半小时 |
| 158 | function applyStatusTags(data) { |
| 159 | const linkStatus = data.link_status; |
| 160 | document.querySelectorAll('.joe_detail__friends-item').forEach(card => { |
| 161 | const linkAnchor = card.querySelector('a.contain'); |
| 162 | if (!linkAnchor) return; |
| 163 | const link = linkAnchor.href.replace(/\/$/, ''); |
| 164 | const statusTag = document.createElement('div'); |
| 165 | statusTag.classList.add('status-tag'); |
| 166 | let matched = false; |
| 167 | // 查找链接状态 |
| 168 | const status = linkStatus.find(item => item.link.replace(/\/$/, '') === link); |
| 169 | if (status) { |
| 170 | let latencyText = '未知'; |
| 171 | let className = 'status-tag-red'; // 默认红色 |
| 172 | if (status.latency === -1) { |
| 173 | latencyText = '未知'; |
| 174 | } else { |
| 175 | latencyText = status.latency.toFixed(2) + ' s'; |
| 176 | if (status.latency <= 2) { |
| 177 | className = 'status-tag-green'; |
| 178 | } else if (status.latency <= 5) { |
| 179 | className = 'status-tag-light-yellow'; |
| 180 | } else if (status.latency <= 10) { |
| 181 | className = 'status-tag-dark-yellow'; |
| 182 | } |
| 183 | } |
| 184 | statusTag.textContent = latencyText; |
| 185 | statusTag.classList.add(className); |
| 186 | matched = true; |
| 187 | } |
| 188 | if (matched) { |
| 189 | card.style.position = 'relative'; |
| 190 | card.appendChild(statusTag); |
| 191 | } |
| 192 | }); |
| 193 | } |
| 194 | function fetchDataAndUpdateUI() { |
| 195 | fetch(jsonUrl) |
| 196 | .then(response => response.json()) |
| 197 | .then(data => { |
| 198 | applyStatusTags(data); |
| 199 | const cacheData = { |
| 200 | data: data, |
| 201 | timestamp: Date.now() |
| 202 | }; |
| 203 | localStorage.setItem(cacheKey, JSON.stringify(cacheData)); |
| 204 | }) |
| 205 | .catch(error => console.error('Error fetching test-flink result.json:', error)); |
| 206 | } |
| 207 | const cachedData = localStorage.getItem(cacheKey); |
| 208 | if (cachedData) { |
| 209 | const { data, timestamp } = JSON.parse(cachedData); |
| 210 | if (Date.now() - timestamp < cacheExpirationTime) { |
| 211 | applyStatusTags(data); |
| 212 | return; |
| 213 | } |
| 214 | } |
| 215 | fetchDataAndUpdateUI(); |
| 216 | } |
| 217 | setTimeout(() => { |
| 218 | addStatusTagsWithCache('https://你的部署地址/result.json'); |
| 219 | }, 0); |
| 220 | </script> |
| 221 | </body> |
| 222 | |
| 223 | </html> |