Created
April 26, 2026 04:25
-
-
Save cubercsl/c9383377a5dedef59cb123f8bdde6527 to your computer and use it in GitHub Desktop.
PTA Rankings - 显示真实评测结果
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ==UserScript== | |
| // @name PTA Rankings - 显示真实评测结果 | |
| // @version 0.1.0 | |
| // @description PTA 外榜的「提交」面板会把所有非 AC 结果统一显示为 WA。本脚本读取 React 组件 props 中的真实状态,并把它替换为 TL / RE / ML / OL / CE 等正确缩写。 | |
| // @author cubercsl | |
| // @match https://pintia.cn/rankings/* | |
| // @run-at document-idle | |
| // @grant none | |
| // @license MIT | |
| // ==/UserScript== | |
| (function () { | |
| 'use strict'; | |
| // PTA 评测状态 -> 短缩写 | |
| const STATUS_MAP = { | |
| ACCEPTED: 'AC', | |
| WRONG_ANSWER: 'WA', | |
| TIME_LIMIT_EXCEEDED: 'TL', | |
| MEMORY_LIMIT_EXCEEDED: 'ML', | |
| RUNTIME_ERROR: 'RE', | |
| OUTPUT_LIMIT_EXCEEDED: 'OL', | |
| COMPILE_ERROR: 'CE', | |
| PRESENTATION_ERROR: 'PE', | |
| PARTIAL_ACCEPTED: 'PA', | |
| NO_ANSWER: 'NA', | |
| NON_ANSWER: 'NA', | |
| SAMPLE_ERROR: 'SE', | |
| JUDGE_ERROR: 'JE', | |
| INTERNAL_ERROR: 'IE', | |
| SYSTEM_ERROR: 'SY', | |
| SEGMENTATION_FAULT: 'SF', | |
| FLOAT_POINT_EXCEPTION: 'FPE', | |
| }; | |
| const PROCESSED = '__ptaStatusFixed'; | |
| /** 找到挂在 DOM 节点上的 React fiber */ | |
| function getFiber(el) { | |
| const key = Object.keys(el).find((k) => k.startsWith('__reactFiber')); | |
| return key ? el[key] : null; | |
| } | |
| /** 沿 fiber 父链向上找真实 status: | |
| * - 优先匹配父组件直接持有 status / submissionId 的情况(题目面板的 ps-* 节点) | |
| * - 其次找包含 submissions 数组的 props,按 submissionId 匹配(最近提交面板) | |
| */ | |
| function resolveStatus(el, submissionId) { | |
| let fiber = getFiber(el); | |
| while (fiber) { | |
| const props = fiber.memoizedProps; | |
| if (props && typeof props === 'object') { | |
| if ( | |
| typeof props.status === 'string' && | |
| (props['data-submission-id'] === submissionId || | |
| props.submissionId === submissionId || | |
| props.id === 'ps-' + submissionId || | |
| props.id === 'rs-' + submissionId) | |
| ) { | |
| return props.status; | |
| } | |
| if ( | |
| Array.isArray(props.submissions) && | |
| props.submissions.length > 0 && | |
| props.submissions[0] && | |
| 'submissionId' in props.submissions[0] && | |
| 'status' in props.submissions[0] | |
| ) { | |
| const m = props.submissions.find((s) => String(s.submissionId) === submissionId); | |
| if (m && m.status) return m.status; | |
| } | |
| } | |
| fiber = fiber.return; | |
| } | |
| return null; | |
| } | |
| function shortFor(status) { | |
| if (!status) return null; | |
| if (STATUS_MAP[status]) return STATUS_MAP[status]; | |
| // 兜底:取每个单词的首字母,如 FOO_BAR_BAZ -> FBB | |
| const abbr = String(status) | |
| .split('_') | |
| .map((w) => w.charAt(0)) | |
| .join(''); | |
| return abbr || String(status).slice(0, 2); | |
| } | |
| function fixOne(rowEl) { | |
| if (rowEl[PROCESSED]) return; | |
| const id = rowEl.getAttribute('data-submission-id'); | |
| if (!id) return; | |
| const textEl = rowEl.querySelector('.status-text'); | |
| if (!textEl) return; | |
| const status = resolveStatus(rowEl, id); | |
| if (!status) return; | |
| const short = shortFor(status); | |
| if (!short) return; | |
| // 标记防止重复处理(状态在面板生命周期内不会变) | |
| rowEl[PROCESSED] = true; | |
| if (textEl.textContent !== short) { | |
| textEl.textContent = short; | |
| } | |
| if (textEl.getAttribute('data-content') !== short) { | |
| textEl.setAttribute('data-content', short); | |
| } | |
| // 保留完整状态名作为 tooltip,方便 hover 查看 | |
| const human = String(status).toLowerCase().replace(/_/g, ' '); | |
| textEl.setAttribute('title', human); | |
| textEl.parentElement?.setAttribute('title', human); | |
| } | |
| function scan(root) { | |
| const scope = root && root.querySelectorAll ? root : document; | |
| // 同时覆盖:最近提交面板的 .submission[data-submission-id] | |
| // 以及 题目得分面板的 .timeStatus[data-submission-id] | |
| const nodes = scope.querySelectorAll('[data-submission-id]'); | |
| nodes.forEach(fixOne); | |
| if (root && root.matches && root.matches('[data-submission-id]')) { | |
| fixOne(root); | |
| } | |
| } | |
| // 初次运行 | |
| scan(document); | |
| // 监听后续动态加载的提交 | |
| const observer = new MutationObserver((mutations) => { | |
| for (const m of mutations) { | |
| m.addedNodes.forEach((node) => { | |
| if (node.nodeType === 1) scan(node); | |
| }); | |
| } | |
| }); | |
| observer.observe(document.body, { childList: true, subtree: true }); | |
| })(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment