Spaces:
Running
Running
File size: 15,851 Bytes
7481290 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 |
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Claude 刷新倒计时 - 终极炫彩背景</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;900&display=swap" rel="stylesheet">
<style>
/* 页面主体样式 */
body {
font-family: 'Inter', sans-serif; /* 应用 Inter 字体 */
/* 全新终极炫彩背景渐变: "霓虹幻想" 主题 */
background: linear-gradient(135deg,
#ff00ff 0%, /* Magenta */
#ff0080 15%, /* Deep Pink */
#0077ff 30%, /* Bright Blue */
#00ffdd 45%, /* Cyan/Turquoise */
#aaff00 60%, /* Lime Green */
#ffaa00 75%, /* Orange */
#ff0000 90%, /* Red */
#ff00ff 100% /* Magenta (to loop smoothly for animation) */
);
background-size: 400% 400%; /* 增大背景尺寸,为动画提供更广阔的移动空间 */
animation: gradientAnimation 25s ease infinite; /* 应用背景渐变动画,25秒周期,平滑无限循环 */
color: #333; /* 页面默认文字颜色 (主要被卡片内样式覆盖) */
display: flex; /* 使用 Flexbox 布局 */
justify-content: center; /* 水平居中 */
align-items: center; /* 垂直居中 */
min-height: 100vh; /* 最小高度为视口高度,确保内容撑满屏幕 */
margin: 0; /* 移除默认外边距 */
padding: 1rem; /* 页面内边距,防止内容紧贴边缘 */
overflow-x: hidden; /* 防止背景动画可能导致的水平滚动条 */
}
/* 背景渐变动画定义 */
@keyframes gradientAnimation {
0% { background-position: 0% 50%; } /* 动画开始时背景位置 */
50% { background-position: 100% 50%; } /* 动画中间状态背景位置 */
100% { background-position: 0% 50%; } /* 动画结束时背景位置,形成循环 */
}
/* Bento Grid 容器样式 */
.bento-grid {
display: grid; /* 使用 Grid 布局 */
grid-template-columns: repeat(1, 1fr); /* 移动端默认为单列 */
gap: 1.5rem; /* 网格项之间的间距 */
width: 100%; /* 宽度占满父容器 */
max-width: 900px; /* 最大宽度限制,防止在大屏幕上过宽 */
position: relative; /* 相对定位,确保在动画背景之上 */
z-index: 1; /* 层级提高,确保在背景之上 */
}
/* 响应式设计:中等屏幕及以上 (768px) */
@media (min-width: 768px) {
.bento-grid {
grid-template-columns: repeat(2, 1fr); /* 变为两列布局 */
grid-template-rows: repeat(2, minmax(175px, auto)); /* 定义两行,每行最小高度175px */
}
/* 定义网格区域,方便控制卡片位置 */
.main-countdown-box { grid-area: 1 / 1 / 2 / 2; } /* 左上角卡片 */
.next-refresh-box { grid-area: 1 / 2 / 2 / 3; } /* 右上角卡片 */
.last-refresh-box { grid-area: 2 / 1 / 3 / 2; } /* 左下角卡片 */
.base-time-box { grid-area: 2 / 2 / 3 / 3; } /* 右下角卡片 */
}
/* Bento Box (卡片) 通用样式 */
.bento-box {
border-radius: 1.25rem; /* 卡片圆角 */
padding: 1.75rem; /* 卡片内边距 */
box-shadow: 0 12px 45px 0 rgba(0, 0, 0, 0.4); /* 卡片阴影效果 */
transition: transform 0.3s ease-in-out, box-shadow 0.3s ease-in-out; /* 过渡动画:变形和阴影 */
display: flex; /* 使用 Flexbox 布局 */
flex-direction: column; /* 子元素垂直排列 */
justify-content: space-around; /* 子元素在垂直方向上均匀分布空间 */
text-align: center; /* 文字居中 */
color: #ffffff; /* 卡片内文字颜色为白色 */
}
/* 卡片鼠标悬浮效果 */
.bento-box:hover {
transform: translateY(-10px) scale(1.04); /* 轻微上移并放大 */
box-shadow: 0 18px 60px 0 rgba(0, 0, 0, 0.45); /* 增强阴影效果 */
}
/* 特定卡片的背景渐变样式 */
/* 左上角:下次刷新倒计时卡片 */
.main-countdown-box {
background: linear-gradient(135deg, #5433FF 0%, #20BDFF 50%, #A5FECB 100%); /* 靛蓝 -> 亮蓝 -> 薄荷绿 */
}
/* 左下角:上次刷新时间卡片 */
.last-refresh-box {
background: linear-gradient(135deg, #00b09b 0%, #96c93d 50%, #00d2ff 100%); /* 青绿 -> 亮青柠 -> 海洋蓝 */
}
/* 右上角:预计下次刷新卡片 */
.next-refresh-box {
background: linear-gradient(135deg, #6a11cb 0%, #fc00ff 50%, #00dbde 100%); /* 深紫 -> 亮粉 -> 青蓝 */
}
/* 右下角:基准刷新时间卡片 */
.base-time-box {
background: linear-gradient(135deg, #ff4e50 0%, #f9d423 50%, #ffc947 100%); /* 亮红 -> 鲜黄 -> 暖橙黄 */
}
/* 卡片内标题 (h2) 样式 */
.bento-box h2 {
font-size: 1.0rem; /* 字体大小 */
font-weight: 700; /* 字体粗细 (加粗) */
color: rgba(255, 255, 255, 0.95); /* 标题颜色 (略透明的白色) */
margin-bottom: 0.6rem; /* 标题下外边距 */
text-shadow: 0 1px 4px rgba(0,0,0,0.3); /* 文字阴影,增强可读性 */
}
/* 卡片内段落 (p) 和强调文本 (span.accent-text) 样式 */
.bento-box p, .bento-box span.accent-text {
font-size: 1.3rem; /* 字体大小 */
font-weight: 500; /* 字体粗细 (中等) */
color: #ffffff; /* 文字颜色 */
text-shadow: 0 1px 3px rgba(0,0,0,0.2); /* 文字阴影 */
}
/* 卡片内小号文本 (通常用于 "(北京时间)") 样式 */
.bento-box .text-sm {
font-size: 0.8rem; /* 字体大小 */
color: rgba(255, 255, 255, 0.85); /* 文字颜色 (更透明的白色) */
display: block; /* 块级元素,确保换行 */
margin-top: 0.3rem; /* 上外边距 */
}
/* 倒计时数字特定样式 */
.countdown-timer {
font-size: 2.85rem; /* 字体大小 */
font-weight: 800; /* 字体粗细 (特粗) */
color: #ffffff; /* 文字颜色 */
text-shadow: 0 2px 6px rgba(0,0,0,0.35); /* 文字阴影 */
letter-spacing: -0.025em; /* 字间距 */
margin: 0.5rem 0; /* 上下外边距 */
}
/* 响应式设计:小屏幕及以上 (640px) 的倒计时数字调整 */
@media (min-width: 640px) {
.countdown-timer {
font-size: 3.4rem; /* 增大字体 */
}
}
</style>
</head>
<body>
<div class="bento-grid">
<div class="bento-box main-countdown-box">
<h2>下次刷新倒计时</h2>
<span id="countdownDisplay" class="countdown-timer">--:--:--</span>
</div>
<div class="bento-box next-refresh-box">
<h2>预计下次刷新</h2>
<p><span id="nextRefreshTimeDisplay" class="accent-text">正在计算...</span><br><span class="text-sm">(北京时间)</span></p>
</div>
<div class="bento-box last-refresh-box">
<h2>上次刷新时间</h2>
<p><span id="lastRefreshTimeDisplay" class="accent-text">正在计算...</span><br><span class="text-sm">(北京时间)</span></p>
</div>
<div class="bento-box base-time-box">
<h2>基准刷新时间</h2>
<p><span id="baseTimeDisplay" class="accent-text">加载中...</span><br><span class="text-sm">(北京时间)</span></p>
</div>
</div>
<script>
// --- 配置常量 ---
// 基准刷新时间 (北京时间 ISO 8601 格式, +08:00 表示东八区)
// 这是计算所有未来刷新时间的基础锚点。
const baseRefreshTimeCST_ISO = "2025-05-08T19:00:00+08:00";
// 刷新周期 (小时)
const refreshIntervalHours = 5;
// 将刷新周期转换为毫秒
const intervalMilliseconds = refreshIntervalHours * 60 * 60 * 1000;
// --- DOM 元素获取 ---
// 获取用于显示倒计时的元素
const countdownDisplay = document.getElementById('countdownDisplay');
// 获取用于显示下一次刷新时间的元素
const nextRefreshTimeDisplay = document.getElementById('nextRefreshTimeDisplay');
// 获取用于显示上一次刷新时间的元素
const lastRefreshTimeDisplay = document.getElementById('lastRefreshTimeDisplay');
// 获取用于显示基准刷新时间的元素
const baseTimeDisplay = document.getElementById('baseTimeDisplay');
// --- 状态变量 ---
// 用于跟踪已显示的下一次刷新时间点 (Epoch毫秒数),避免不必要的DOM更新
let displayedTargetTimeEpoch = 0;
// --- 辅助函数 ---
/**
* 计算下一次刷新时间点。
* 基于基准刷新时间和当前时间,向前推算直到找到第一个未来的刷新时间点。
* @returns {Date} 下一次刷新的 Date 对象 (内部为UTC时间)。
*/
function calculateNextRefresh() {
// 将ISO格式的基准时间字符串转换为Date对象。
// Date对象内部总是以UTC存储时间。包含时区信息的字符串会被正确解析。
const baseTime = new Date(baseRefreshTimeCST_ISO);
// 获取当前时间的Date对象。
const now = new Date();
// 从基准时间的Epoch毫秒数开始计算。
let nextRefreshEpoch = baseTime.getTime();
// 循环增加刷新间隔,直到计算出的刷新时间点晚于当前时间。
// 这样可以确保即使页面加载时已经错过了多个刷新周期,也能找到正确的下一个刷新点。
while (nextRefreshEpoch <= now.getTime()) {
nextRefreshEpoch += intervalMilliseconds;
}
// 返回计算得到的下一个刷新时间点的Date对象。
return new Date(nextRefreshEpoch);
}
/**
* 将 Date 对象格式化为北京时间字符串 (YYYY-MM-DD HH:MM:SS)。
* @param {Date} dateObj - 需要格式化的 Date 对象。
* @returns {string} 格式化后的北京时间字符串,或在出错时返回错误提示。
*/
function formatToBeijingTime(dateObj) {
// 检查传入的是否是有效的Date对象。
if (!dateObj || isNaN(dateObj.getTime())) {
return "无效日期";
}
try {
// 使用 toLocaleString 方法进行时区转换和格式化。
// 'Asia/Shanghai' 代表中国标准时间 (北京时间)。
return dateObj.toLocaleString('zh-CN', { // 'zh-CN' 用于中文格式
timeZone: 'Asia/Shanghai',
year: 'numeric', // 四位数字年份
month: '2-digit', // 两位数字月份
day: '2-digit', // 两位数字日期
hour: '2-digit', // 两位数字小时 (24小时制)
minute: '2-digit', // 两位数字分钟
second: '2-digit', // 两位数字秒
hour12: false // 使用24小时制
}).replace(/\//g, '-'); // 将日期中的 '/' 替换为 '-',以符合 YYYY-MM-DD 格式。
} catch (e) {
// 如果格式化过程中发生错误,则打印错误到控制台并返回提示信息。
console.error("日期格式化错误:", e);
return "格式化错误";
}
}
// --- 主要倒计时逻辑与UI更新函数 ---
/**
* 更新倒计时显示以及相关的刷新时间信息。
* 此函数会被 setInterval 每秒调用一次。
*/
function updateCountdown() {
// 获取当前时间。
const now = new Date();
// 计算下一次刷新时间点。
const targetDate = calculateNextRefresh(); // 内部为UTC
// 优化:仅当目标刷新时间点发生变化时 (即进入新的刷新周期),才更新“下次刷新时间”和“上次刷新时间”的显示。
// 这样可以避免每秒都对这两个DOM元素进行不必要的重绘。
if (targetDate.getTime() !== displayedTargetTimeEpoch) {
// 更新“预计下次刷新”的显示。
nextRefreshTimeDisplay.textContent = formatToBeijingTime(targetDate);
// 计算并显示“上次刷新时间”。
// 上次刷新时间 = 下次刷新时间 - một刷新周期。
const lastRefreshTimeDate = new Date(targetDate.getTime() - intervalMilliseconds);
lastRefreshTimeDisplay.textContent = formatToBeijingTime(lastRefreshTimeDate);
// 更新已显示的目标时间点。
displayedTargetTimeEpoch = targetDate.getTime();
}
// 计算距离下一次刷新的剩余时间 (毫秒)。
const timeRemaining = targetDate.getTime() - now.getTime();
// 如果已到达或超过刷新时间点。
if (timeRemaining <= 0) {
// 将倒计时显示为 "00:00:00"。
countdownDisplay.textContent = "00:00:00";
// 在下一个 setInterval 周期,calculateNextRefresh 会自动计算出新的未来刷新点。
return; // 提前退出,避免显示负数。
}
// 将剩余毫秒数转换为时、分、秒。
const hours = Math.floor(timeRemaining / (1000 * 60 * 60));
const minutes = Math.floor((timeRemaining % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((timeRemaining % (1000 * 60)) / 1000);
// 格式化为 HH:MM:SS 并更新倒计时显示。
// String().padStart(2, '0') 用于确保单位数时前面补零 (例如 7 -> "07")。
countdownDisplay.textContent =
`${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`;
}
// --- 初始化函数 ---
/**
* 页面加载完成后执行的初始化操作。
*/
function initializePage() {
// 1. 显示固定的基准刷新时间。
const baseDate = new Date(baseRefreshTimeCST_ISO);
baseTimeDisplay.textContent = formatToBeijingTime(baseDate);
// 2. 立即调用一次 updateCountdown,以便页面加载时就能看到正确的初始状态。
updateCountdown();
// 3. 设置定时器,每秒调用一次 updateCountdown 函数来实时更新倒计时。
setInterval(updateCountdown, 1000); // 1000毫秒 = 1秒
}
// --- 事件监听 ---
// 确保在整个HTML文档加载并解析完成后再执行初始化脚本。
document.addEventListener('DOMContentLoaded', initializePage);
</script>
</body>
</html> |