2026/8/1...大约 5 分钟
第三届大马猴杯世界赛-个人赛
<link rel="stylesheet" href="https://npm.elemecdn.com/font6pro@6.4.0/css/all.min.css">
<link rel="stylesheet" href="https://npm.elemecdn.com/font6pro@6.4.0/css/fontawesome.min.css">
<table>
<thead>
<tr>
<th colspan="5" style="font-size: xxx-large;">2026-第三届 大马猴杯跑跑卡丁车世界赛日程安排</th>
</tr>
<tr>
<th class="thbg">流程日</th>
<th class="thbg">具体日期</th>
<th class="thbg">赛程安排</th>
<th class="thbg">场次</th>
<th class="thbg">备注</th>
</tr>
</thead>
<tbody>
<tr style="height: 53px;">
<td>报名时间</td>
<td>7月18日 ~ 7月22日</td>
<td>报名时间</td>
<td>5天</td>
<td style="background-color: rgb(224,196,178);">报名方式
<br/><i class="fa-brands fa-tiktok"></i> 抖音搜索<a href="https://v.douyin.com/NJqU4CoW9P4/" style="font-weight: bolder;color: rgb(13, 109, 252);text-decoration: none;font-size: large;"
target="_blank"> 大马猴电竞</a><br/>私信发送【世界赛报名】<br/>即可获取报名链接</td>
</tr>
<tr style="height: 53px;">
<td>海选赛</td>
<td>7月25日 ~ 7月27日</td>
<td>N进128</td>
<td>抢分</td>
<td style="background-color: rgb(224,196,178);">海选线上比赛
<br/>随机抽取比赛选手房间</td>
</tr>
<tr style="height: 53px;">
<td>线上 Day1</td>
<td>7月28日</td>
<td>128进64 - ABCDEFGH 组</td>
<td>抢60分</td>
<td rowspan="4" style="background-color: rgb(224,196,178);">线上比赛
<br/>(每晚20:00)<br/>每场比赛全程直播</td>
</tr>
<tr style="height: 53px;">
<td>线上 Day2</td>
<td>7月29日</td>
<td>128进64 - IJKLMNOP 组</td>
<td>抢60分</td>
</tr>
<tr style="height: 53px;">
<td>线上 Day3</td>
<td>7月30日</td>
<td>64进32 - ABCD 组</td>
<td>抢80分</td>
</tr>
<tr style="height: 53px;">
<td>线上Day4</td>
<td>7月31日</td>
<td>64进32 - EFGH 组</td>
<td>抢80分</td>
</tr>
<tr style="height: 53px;">
<td>选手到达广饶 / 训练</td>
<td>8月10日 ~ 8月14日</td>
<td>选手到达/训练</td>
<td>-</td>
</tr>
<tr style="height: 53px;">
<td>线下 Day1</td>
<td>8月15日</td>
<td>32进16 A、B组</td>
<td>/</td>
<td rowspan="6" style="background-color: rgb(172,229,142);">线下比赛
<br/>(每晚18:00开始<br/>每场比赛全程直播)</td>
</tr>
<tr style="height: 53px;">
<td>线下 Day2</td>
<td>8月16日</td>
<td>32进16 C、D组</td>
<td>/</td>
</tr>
<tr style="height: 53px;">
<td>线下 Day3</td>
<td>8月17日</td>
<td>32进16 复活赛(上下半区)</td>
<td>/</td>
</tr>
<tr style="height: 53px;">
<td>线下 Day4</td>
<td>8月19日</td>
<td>16进8 A、B组+胜者组</td>
<td>/</td>
</tr>
<tr style="height: 53px;">
<td>线下 Day5</td>
<td>8月20日</td>
<td>16进8 胜者组+胜败复活</td>
<td>/</td>
</tr>
<tr style="height: 53px;">
<td>线下 Day6</td>
<td>10月18日</td>
<td style="font-size: xx-large;">🏆 总决赛</td>
<td>/</td>
</tr>
</tbody>
</table> /* ===== 原有表格样式 ===== */
table {
width: 100%;
border-collapse: collapse;
text-align: center;
color: var(--vp-c-text) !important;
font-size: 15px;
}
th,
td {
border: 1px solid #333;
padding: 8px;
}
.thbg {
background-color: rgb(168, 196, 221);
}
/* ===== 新增:已完成行样式(由 JS 动态添加) ===== */
tr.row-completed td:not([style*="background-color: rgb(224,196,178)"]) {
background-color: #d4edda !important;
color: #155724 !important;
}
/* 可选:在已完成行加一个小标记(纯 CSS 装饰) */
tr.row-completed td:first-child::after {
content: " ✅";
font-size: 14px;
opacity: 0.8;
} (function() {
'use strict';
// ---------- 配置(可按需修改) ----------
const CONFIG = {
// 表格选择器(默认自动查找页面中的第一个 <table>)
tableSelector: 'table',
// 日期列索引(0-based,第2列 = 索引1)
dateColumnIndex: 1,
// 已完成行的 CSS 类名
completedClass: 'row-completed',
// 是否在控制台输出调试信息
debug: true,
// 年份:null 表示从表格标题自动提取,否则直接指定(如 2026)
year: null,
};
// ---------- 工具函数 ----------
function log(...args) {
if (CONFIG.debug) console.log('[日程标记]', ...args);
}
// 从文本中提取年份(匹配 4 位数字)
function extractYear(text) {
const m = text.match(/(\d{4})/);
return m ? parseInt(m[0]) : null;
}
// 解析单个日期 "X月Y日" → Date 对象(使用指定年份)
function parseSingleDate(str, year) {
const m = str.trim().match(/(\d{1,2})月(\d{1,2})日/);
if (!m) return null;
const month = parseInt(m[1]) - 1; // JS 月份 0-based
const day = parseInt(m[2]);
return new Date(year, month, day);
}
// 解析日期列文本,返回 { endDate, raw },若解析失败返回 null
function parseDateColumn(text, year) {
const cleaned = text.replace(/\s+/g, ' ').trim();
// 尝试匹配范围 "7月18日 ~ 7月22日"
const rangeMatch = cleaned.match(/(\d{1,2}月\d{1,2}日)\s*[~~]\s*(\d{1,2}月\d{1,2}日)/);
if (rangeMatch) {
const endStr = rangeMatch[2];
const endDate = parseSingleDate(endStr, year);
return endDate ? { endDate, raw: cleaned } : null;
}
// 尝试匹配单个日期 "7月28日"
const single = parseSingleDate(cleaned, year);
if (single) {
return { endDate: single, raw: cleaned };
}
return null;
}
// 判断当前日期是否 > 目标日期(只比较日期,忽略时间)
function isDatePassed(targetDate) {
const now = new Date();
// 重置时间为 00:00:00 只比较日期
const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
const target = new Date(targetDate.getFullYear(), targetDate.getMonth(), targetDate.getDate());
return today > target;
}
// ---------- 主逻辑 ----------
function markCompletedRows() {
const table = document.querySelector(CONFIG.tableSelector);
if (!table) {
log('❌ 未找到表格,请检查 tableSelector 配置');
return;
}
// 1. 确定年份
let year = CONFIG.year;
if (!year) {
// 从表格标题(第一个 th 的 colspan=5)提取
const headerTh = table.querySelector('thead tr th[colspan="5"]');
if (headerTh) {
const title = headerTh.textContent;
const extracted = extractYear(title);
if (extracted) {
year = extracted;
log(`📅 从标题提取年份: ${year}`);
}
}
if (!year) {
// 降级使用当前年份
year = new Date().getFullYear();
log(`⚠️ 未提取到年份,使用当前年份: ${year}`);
}
} else {
log(`📅 使用配置年份: ${year}`);
}
// 2. 遍历 tbody 中的所有行
const rows = table.querySelectorAll('tbody tr');
let passedCount = 0;
let totalCount = rows.length;
rows.forEach((row, index) => {
const cells = row.querySelectorAll('td');
if (cells.length <= CONFIG.dateColumnIndex) {
log(`⏭️ 第 ${index+1} 行:列数不足,跳过`);
return;
}
const dateCell = cells[CONFIG.dateColumnIndex];
const dateText = dateCell.textContent.trim();
if (!dateText) {
log(`⏭️ 第 ${index+1} 行:日期列为空,跳过`);
return;
}
// 解析日期
const parsed = parseDateColumn(dateText, year);
if (!parsed) {
log(`⚠️ 第 ${index+1} 行:无法解析日期 "${dateText}",跳过`);
return;
}
const { endDate, raw } = parsed;
// 判断是否已过
if (isDatePassed(endDate)) {
row.classList.add(CONFIG.completedClass);
passedCount++;
log(`✅ 第 ${index+1} 行:已过期 (${raw}) → 添加标记`);
} else {
log(`⏳ 第 ${index+1} 行:未过期 (${raw})`);
}
});
log(`🎯 完成!共 ${totalCount} 行,标记 ${passedCount} 行为“已完成”`);
}
// ---------- 自动执行 ----------
// 确保 DOM 加载完成后运行
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', markCompletedRows);
} else {
// DOM 已就绪,直接执行
markCompletedRows();
}
// 暴露到全局,方便调试或手动重新触发
window.markScheduleCompleted = markCompletedRows;
})();