Skip to content

Instantly share code, notes, and snippets.

@cubercsl
Created April 26, 2026 04:25
Show Gist options
  • Select an option

  • Save cubercsl/c9383377a5dedef59cb123f8bdde6527 to your computer and use it in GitHub Desktop.

Select an option

Save cubercsl/c9383377a5dedef59cb123f8bdde6527 to your computer and use it in GitHub Desktop.
PTA Rankings - 显示真实评测结果
// ==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