|
@@ -228,124 +228,232 @@ $csj1Ts = strtotime('2026-09-19');
|
|
|
$csp1daysLeft = max(0, (int)floor(($csp1Ts - $todayMidnight) / 86400));
|
|
$csp1daysLeft = max(0, (int)floor(($csp1Ts - $todayMidnight) / 86400));
|
|
|
$csp2Ts = strtotime('2026-10-31');
|
|
$csp2Ts = strtotime('2026-10-31');
|
|
|
$csp2daysLeft = max(0, (int)floor(($csp2Ts - $todayMidnight) / 86400));
|
|
$csp2daysLeft = max(0, (int)floor(($csp2Ts - $todayMidnight) / 86400));
|
|
|
|
|
+$gk27Ts = strtotime('2027-06-07');
|
|
|
|
|
+$gk27daysLeft = max(0, (int)floor(($gk27Ts - $todayMidnight) / 86400));
|
|
|
|
|
+$gk28Ts = strtotime('2028-06-07');
|
|
|
|
|
+$gk28daysLeft = max(0, (int)floor(($gk28Ts - $todayMidnight) / 86400));
|
|
|
?>
|
|
?>
|
|
|
|
|
|
|
|
<div class="row my-4">
|
|
<div class="row my-4">
|
|
|
<!-- ============ 左列:日程 + 博客 ============ -->
|
|
<!-- ============ 左列:日程 + 博客 ============ -->
|
|
|
<div class="col-12 col-lg-9">
|
|
<div class="col-12 col-lg-9">
|
|
|
- <!-- 黑色日期卡片 -->
|
|
|
|
|
- <div class="mb-4 wyoj-date-card" id="wyoj-date-card"
|
|
|
|
|
- style="position:relative;overflow:hidden;background:#000;color:#fff;padding:2rem 1.5rem;border-radius:0;text-shadow:0 1px 3px rgba(0,0,0,0.75);">
|
|
|
|
|
-
|
|
|
|
|
- <!-- 随机方格背景层 -->
|
|
|
|
|
- <div id="wyoj-date-grid"
|
|
|
|
|
- style="position:absolute;top:0;left:0;right:0;bottom:0;display:grid;z-index:0;pointer-events:none;"></div>
|
|
|
|
|
-
|
|
|
|
|
- <!-- 内容层 -->
|
|
|
|
|
- <div style="position:relative;z-index:1;">
|
|
|
|
|
- <div class="d-flex justify-content-center align-items-center">
|
|
|
|
|
- <div style="writing-mode:vertical-rl;font-size:1.5rem;font-weight:bold;letter-spacing:0.3em;line-height:1;">
|
|
|
|
|
- <?= $monthText ?>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="mx-4" style="font-size:5rem;font-weight:600;line-height:1;">
|
|
|
|
|
- <?= $dayNum ?>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div style="writing-mode:vertical-rl;font-size:1.5rem;font-weight:bold;letter-spacing:0.3em;line-height:1;">
|
|
|
|
|
- <?= $weekText ?>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="text-center mt-4" style="font-size:1rem;letter-spacing:0.05em;">
|
|
|
|
|
- <?php if ($daysLeft > 0): ?>
|
|
|
|
|
- 距 <strong>NOIP2026</strong> 还有 <strong><?= $daysLeft ?></strong> 天
|
|
|
|
|
- <?php elseif ($daysLeft === 0): ?>
|
|
|
|
|
- <strong>NOIP2026</strong> 就是今天
|
|
|
|
|
- <?php else: ?>
|
|
|
|
|
- <strong>NOIP2026</strong> 已结束
|
|
|
|
|
- <?php endif; ?>
|
|
|
|
|
- <br/>
|
|
|
|
|
- <?php if ($csp1daysLeft > 0): ?>
|
|
|
|
|
- 距 <strong>CSP-J/S 2026 第一轮</strong> 还有 <strong><?= $csp1daysLeft ?></strong> 天
|
|
|
|
|
- <?php elseif ($csp1daysLeft === 0): ?>
|
|
|
|
|
- <strong>CSP-J/S 2026 第一轮</strong> 就是今天
|
|
|
|
|
- <?php else: ?>
|
|
|
|
|
- <strong>CSP-J/S 2026 第一轮</strong> 已结束
|
|
|
|
|
- <?php endif; ?>
|
|
|
|
|
- <br/>
|
|
|
|
|
- <?php if ($csp2daysLeft > 0): ?>
|
|
|
|
|
- 距 <strong>CSP-J/S 2026 第二轮</strong> 还有 <strong><?= $csp2daysLeft ?></strong> 天
|
|
|
|
|
- <?php elseif ($csp2daysLeft === 0): ?>
|
|
|
|
|
- <strong>CSP-J/S 2026 第二轮</strong> 就是今天!
|
|
|
|
|
- <?php else: ?>
|
|
|
|
|
- <strong>CSP-J/S 2026 第二轮</strong> 已结束
|
|
|
|
|
- <?php endif; ?>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- <script>
|
|
|
|
|
- (function () {
|
|
|
|
|
- var card = document.getElementById('wyoj-date-card');
|
|
|
|
|
- var grid = document.getElementById('wyoj-date-grid');
|
|
|
|
|
- if (!card || !grid) return;
|
|
|
|
|
-
|
|
|
|
|
- // ===== 可调参数 =====
|
|
|
|
|
- var COLORS = ['#000000', '#0c0c0c', '#181818', '#242424', '#303030']; // 5 档灰→黑
|
|
|
|
|
- var CELL = 22; // 每个小方格的边长(px)
|
|
|
|
|
- var P = 0.3; // 每格每秒变色的概率(0~1),越大越跳
|
|
|
|
|
- // ====================
|
|
|
|
|
-
|
|
|
|
|
- var cells = [];
|
|
|
|
|
- var lastCols = 0, lastRows = 0;
|
|
|
|
|
-
|
|
|
|
|
- function pickColor() {
|
|
|
|
|
- return COLORS[Math.floor(Math.random() * COLORS.length)];
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- function build(force) {
|
|
|
|
|
- var w = card.clientWidth;
|
|
|
|
|
- var h = card.clientHeight;
|
|
|
|
|
- var cols = Math.max(1, Math.ceil(w / CELL));
|
|
|
|
|
- var rows = Math.max(1, Math.ceil(h / CELL));
|
|
|
|
|
- if (!force && cols === lastCols && rows === lastRows) return;
|
|
|
|
|
- lastCols = cols;
|
|
|
|
|
- lastRows = rows;
|
|
|
|
|
-
|
|
|
|
|
- grid.style.gridTemplateColumns = 'repeat(' + cols + ', 1fr)';
|
|
|
|
|
- grid.style.gridTemplateRows = 'repeat(' + rows + ', 1fr)';
|
|
|
|
|
- grid.innerHTML = '';
|
|
|
|
|
- cells = [];
|
|
|
|
|
-
|
|
|
|
|
- for (var i = 0; i < cols * rows; i++) {
|
|
|
|
|
- var d = document.createElement('div');
|
|
|
|
|
- d.style.backgroundColor = pickColor();
|
|
|
|
|
- // 每格单独的过渡时长,让变化错开,不会整片一起闪
|
|
|
|
|
- d.style.transition = 'background-color ' + (0.5 + Math.random() * 0.5).toFixed(2) + 's ease';
|
|
|
|
|
- grid.appendChild(d);
|
|
|
|
|
- cells.push(d);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- build(true);
|
|
|
|
|
-
|
|
|
|
|
- // 尺寸变化时重建(只在行列数变化时真的重建,避免无谓重置)
|
|
|
|
|
- if (window.ResizeObserver) {
|
|
|
|
|
- new ResizeObserver(function () { build(false); }).observe(card);
|
|
|
|
|
- } else {
|
|
|
|
|
- window.addEventListener('resize', function () { build(false); });
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 每秒给每格一个 p 的变色机会
|
|
|
|
|
- setInterval(function () {
|
|
|
|
|
- for (var i = 0; i < cells.length; i++) {
|
|
|
|
|
- if (Math.random() < P) {
|
|
|
|
|
- cells[i].style.backgroundColor = pickColor();
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }, 1500);
|
|
|
|
|
- })();
|
|
|
|
|
- </script>
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- <!-- 博客列表 -->
|
|
|
|
|
|
|
+ <!-- 黑色日期卡片 -->
|
|
|
|
|
+ <div class="mb-4 wyoj-date-card" id="wyoj-date-card"
|
|
|
|
|
+ style="position:relative;overflow:hidden;background:#000;color:#fff;padding:2rem 1.5rem;border-radius:0;text-shadow:0 1px 3px rgba(0,0,0,0.75);">
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 随机方格背景:canvas -->
|
|
|
|
|
+ <canvas id="wyoj-date-canvas"
|
|
|
|
|
+ style="position:absolute;top:0;left:0;width:100%;height:100%;z-index:0;pointer-events:none;"></canvas>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 内容层 -->
|
|
|
|
|
+ <div style="position:relative;z-index:1;">
|
|
|
|
|
+ <div class="d-flex justify-content-center align-items-center">
|
|
|
|
|
+ <div style="writing-mode:vertical-rl;font-size:1.5rem;font-weight:bold;letter-spacing:0.3em;line-height:1;">
|
|
|
|
|
+ <?= $monthText ?>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="mx-4" style="font-size:5rem;font-weight:600;line-height:1;">
|
|
|
|
|
+ <?= $dayNum ?>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div style="writing-mode:vertical-rl;font-size:1.5rem;font-weight:bold;letter-spacing:0.3em;line-height:1;">
|
|
|
|
|
+ <?= $weekText ?>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="text-center mt-4" style="font-size:1rem;letter-spacing:0.05em;">
|
|
|
|
|
+ <?php if ($daysLeft > 0): ?>
|
|
|
|
|
+ 距 <strong>NOIP2026</strong> 还有 <strong><?= $daysLeft ?></strong> 天
|
|
|
|
|
+ <?php elseif ($daysLeft === 0): ?>
|
|
|
|
|
+ <strong>NOIP2026</strong> 就是今天
|
|
|
|
|
+ <?php else: ?>
|
|
|
|
|
+ <strong>NOIP2026</strong> 已结束
|
|
|
|
|
+ <?php endif; ?>
|
|
|
|
|
+ <br/>
|
|
|
|
|
+ <?php if ($csp1daysLeft > 0): ?>
|
|
|
|
|
+ 距 <strong>CSP-J/S 2026 第一轮</strong> 还有 <strong><?= $csp1daysLeft ?></strong> 天
|
|
|
|
|
+ <?php elseif ($csp1daysLeft === 0): ?>
|
|
|
|
|
+ <strong>CSP-J/S 2026 第一轮</strong> 就是今天
|
|
|
|
|
+ <?php else: ?>
|
|
|
|
|
+ <strong>CSP-J/S 2026 第一轮</strong> 已结束
|
|
|
|
|
+ <?php endif; ?>
|
|
|
|
|
+ <br/>
|
|
|
|
|
+ <?php if ($csp2daysLeft > 0): ?>
|
|
|
|
|
+ 距 <strong>CSP-J/S 2026 第二轮</strong> 还有 <strong><?= $csp2daysLeft ?></strong> 天
|
|
|
|
|
+ <?php elseif ($csp2daysLeft === 0): ?>
|
|
|
|
|
+ <strong>CSP-J/S 2026 第二轮</strong> 就是今天!
|
|
|
|
|
+ <?php else: ?>
|
|
|
|
|
+ <strong>CSP-J/S 2026 第二轮</strong> 已结束
|
|
|
|
|
+ <?php endif; ?>
|
|
|
|
|
+ <br/>
|
|
|
|
|
+ <?php if ($gk27daysLeft > 0): ?>
|
|
|
|
|
+ 距 <strong>2027 年普通高等学校招生全国统一考试</strong> 还有 <strong><?= $gk27daysLeft ?></strong> 天
|
|
|
|
|
+ <?php elseif ($gk27daysLeft === 0): ?>
|
|
|
|
|
+ <strong>2027 年普通高等学校招生全国统一考试</strong> 就是今天!
|
|
|
|
|
+ <?php else: ?>
|
|
|
|
|
+ <strong>2027 年普通高等学校招生全国统一考试</strong> 已结束
|
|
|
|
|
+ <?php endif; ?>
|
|
|
|
|
+ <br/>
|
|
|
|
|
+ <?php if ($gk28daysLeft > 0): ?>
|
|
|
|
|
+ 距 <strong>2028 年普通高等学校招生全国统一考试</strong> 还有 <strong><?= $gk28daysLeft ?></strong> 天
|
|
|
|
|
+ <?php elseif ($gk28daysLeft === 0): ?>
|
|
|
|
|
+ <strong>2028 年普通高等学校招生全国统一考试</strong> 就是今天!
|
|
|
|
|
+ <?php else: ?>
|
|
|
|
|
+ <strong>2028 年普通高等学校招生全国统一考试</strong> 已结束
|
|
|
|
|
+ <?php endif; ?>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <script>
|
|
|
|
|
+ (function () {
|
|
|
|
|
+ var card = document.getElementById('wyoj-date-card');
|
|
|
|
|
+ var canvas = document.getElementById('wyoj-date-canvas');
|
|
|
|
|
+ if (!card || !canvas) return;
|
|
|
|
|
+
|
|
|
|
|
+ var ctx = canvas.getContext('2d');
|
|
|
|
|
+
|
|
|
|
|
+ // ===== 可调参数 =====
|
|
|
|
|
+ var COLORS = ['#000000', '#0c0c0c', '#181818', '#242424', '#303030'];
|
|
|
|
|
+ var CELL = 26; // 每格边长(px)
|
|
|
|
|
+ var P = 0.3; // 每格每轮变色概率(期望值)
|
|
|
|
|
+ var PERIOD = 1500; // 刷新间隔(ms)
|
|
|
|
|
+ var Z = 1.96; // 95% 置信区间
|
|
|
|
|
+ var USE_DPR = false; // 是否按设备像素比放大 canvas(false 更省 CPU)
|
|
|
|
|
+ // ====================
|
|
|
|
|
+
|
|
|
|
|
+ var dpr = USE_DPR ? (window.devicePixelRatio || 1) : 1;
|
|
|
|
|
+ var cols = 0, rows = 0, nCells = 0;
|
|
|
|
|
+ var lastW = 0, lastH = 0;
|
|
|
|
|
+ var gridColors = [];
|
|
|
|
|
+ var idx = null;
|
|
|
|
|
+ var xs = null, ys = null;
|
|
|
|
|
+
|
|
|
|
|
+ var rafId = null;
|
|
|
|
|
+ var running = false;
|
|
|
|
|
+ var lastTick = 0;
|
|
|
|
|
+
|
|
|
|
|
+ function randColor() {
|
|
|
|
|
+ return COLORS[(Math.random() * COLORS.length) | 0];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ function computeBounds() {
|
|
|
|
|
+ var w = card.clientWidth;
|
|
|
|
|
+ var h = card.clientHeight;
|
|
|
|
|
+ xs = new Int32Array(cols + 1);
|
|
|
|
|
+ ys = new Int32Array(rows + 1);
|
|
|
|
|
+ for (var i = 0; i <= cols; i++) xs[i] = Math.round(i * w / cols);
|
|
|
|
|
+ for (var j = 0; j <= rows; j++) ys[j] = Math.round(j * h / rows);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ function build() {
|
|
|
|
|
+ var w = card.clientWidth;
|
|
|
|
|
+ var h = card.clientHeight;
|
|
|
|
|
+ if (w === 0 || h === 0) return;
|
|
|
|
|
+ if (w === lastW && h === lastH) return; // 尺寸没变就不重建
|
|
|
|
|
+ lastW = w; lastH = h;
|
|
|
|
|
+
|
|
|
|
|
+ cols = Math.max(1, Math.ceil(w / CELL));
|
|
|
|
|
+ rows = Math.max(1, Math.ceil(h / CELL));
|
|
|
|
|
+ nCells = cols * rows;
|
|
|
|
|
+
|
|
|
|
|
+ canvas.width = Math.round(w * dpr);
|
|
|
|
|
+ canvas.height = Math.round(h * dpr);
|
|
|
|
|
+ canvas.style.width = w + 'px';
|
|
|
|
|
+ canvas.style.height = h + 'px';
|
|
|
|
|
+ ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
|
|
|
+ ctx.imageSmoothingEnabled = false;
|
|
|
|
|
+
|
|
|
|
|
+ computeBounds();
|
|
|
|
|
+
|
|
|
|
|
+ gridColors = [];
|
|
|
|
|
+ for (var y = 0; y < rows; y++) {
|
|
|
|
|
+ var row = [];
|
|
|
|
|
+ for (var x = 0; x < cols; x++) row.push(randColor());
|
|
|
|
|
+ gridColors.push(row);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ idx = new Int32Array(nCells);
|
|
|
|
|
+ for (var i = 0; i < nCells; i++) idx[i] = i;
|
|
|
|
|
+
|
|
|
|
|
+ redrawAll();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ function redrawAll() {
|
|
|
|
|
+ for (var y = 0; y < rows; y++) {
|
|
|
|
|
+ var y0 = ys[y], y1 = ys[y + 1];
|
|
|
|
|
+ for (var x = 0; x < cols; x++) {
|
|
|
|
|
+ ctx.fillStyle = gridColors[y][x];
|
|
|
|
|
+ ctx.fillRect(xs[x], y0, xs[x + 1] - xs[x], y1 - y0);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ function tick() {
|
|
|
|
|
+ if (nCells === 0) return;
|
|
|
|
|
+
|
|
|
|
|
+ var mu = nCells * P;
|
|
|
|
|
+ var sigma = Math.sqrt(nCells * P * (1 - P));
|
|
|
|
|
+ var lo = Math.max(0, Math.floor(mu - Z * sigma));
|
|
|
|
|
+ var hi = Math.min(nCells, Math.ceil(mu + Z * sigma));
|
|
|
|
|
+ var m = lo + Math.floor(Math.random() * (hi - lo + 1));
|
|
|
|
|
+
|
|
|
|
|
+ for (var i = 0; i < m; i++) {
|
|
|
|
|
+ var j = i + Math.floor(Math.random() * (nCells - i));
|
|
|
|
|
+ var t = idx[i]; idx[i] = idx[j]; idx[j] = t;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ for (var k = 0; k < m; k++) {
|
|
|
|
|
+ var ci = idx[k];
|
|
|
|
|
+ var x = ci % cols;
|
|
|
|
|
+ var y = (ci / cols) | 0;
|
|
|
|
|
+ var c = randColor();
|
|
|
|
|
+ gridColors[y][x] = c;
|
|
|
|
|
+ ctx.fillStyle = c;
|
|
|
|
|
+ ctx.fillRect(xs[x], ys[y], xs[x + 1] - xs[x], ys[y + 1] - ys[y]);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ function loop(now) {
|
|
|
|
|
+ rafId = null;
|
|
|
|
|
+ if (now - lastTick >= PERIOD) {
|
|
|
|
|
+ lastTick = now;
|
|
|
|
|
+ tick();
|
|
|
|
|
+ }
|
|
|
|
|
+ if (running) rafId = requestAnimationFrame(loop);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ function start() {
|
|
|
|
|
+ if (running) return;
|
|
|
|
|
+ running = true;
|
|
|
|
|
+ lastTick = performance.now();
|
|
|
|
|
+ rafId = requestAnimationFrame(loop);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ function stop() {
|
|
|
|
|
+ running = false;
|
|
|
|
|
+ if (rafId) { cancelAnimationFrame(rafId); rafId = null; }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ build();
|
|
|
|
|
+
|
|
|
|
|
+ if (window.ResizeObserver) {
|
|
|
|
|
+ new ResizeObserver(function () { build(); }).observe(card);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ window.addEventListener('resize', build);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (window.IntersectionObserver) {
|
|
|
|
|
+ new IntersectionObserver(function (entries) {
|
|
|
|
|
+ if (entries[0].isIntersecting) start(); else stop();
|
|
|
|
|
+ }, { threshold: 0 }).observe(card);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ start();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ document.addEventListener('visibilitychange', function () {
|
|
|
|
|
+ if (document.hidden) stop(); else start();
|
|
|
|
|
+ });
|
|
|
|
|
+ })();
|
|
|
|
|
+ </script>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 博客列表 -->
|
|
|
<div class="row">
|
|
<div class="row">
|
|
|
<?php foreach ($recentblogs as $blog): ?>
|
|
<?php foreach ($recentblogs as $blog): ?>
|
|
|
<?= echoBlogCard(queryBlog($blog['id'])) ?>
|
|
<?= echoBlogCard(queryBlog($blog['id'])) ?>
|
|
@@ -461,3 +569,5 @@ $csp2daysLeft = max(0, (int)floor(($csp2Ts - $todayMidnight) / 86400));
|
|
|
|
|
|
|
|
<?php echoUOJPageFooter() ?>
|
|
<?php echoUOJPageFooter() ?>
|
|
|
|
|
|
|
|
|
|
+<div class="row my-4">
|
|
|
|
|
+
|