您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Generate homework report PDF automatically.
当前为
// ==UserScript== // @name OJCN Report Gen // @description Generate homework report PDF automatically. // @description:en Generate homework report PDF automatically. // @description:zh-CN 自动生成作业报告 PDF。虽然大家并不想理我。 // @namespace https://gf.qytechs.cn/users/197529 // @version 0.2.1 // @author kkocdko // @license Unlicense // @match *://noi.openjudge.cn/* // ==/UserScript== "use strict"; const cfg = { homeworkId: 2, studentName: "Ninja", problems: [ "ch0104/01", "ch0104/03", "ch0104/07", "ch0104/08", "ch0104/09", "ch0104/14", "ch0104/15", "ch0104/16", "ch0104/18", "ch0104/19", ], userId: document.querySelector("#userToolbar>li")?.textContent, }; if (!document.querySelector(".account-link")) throw alert("login required"); if (!cfg.studentName === "Ninja") throw alert("please modify the script to fit your personal info"); document.lastChild.appendChild(document.createElement("style")).textContent = ` body::before { content: ""; position: fixed; left: 40px; top: 40px; padding: 20px; border: 8px solid #37b; border-radius: 25%; z-index: 2000; animation: spin 12s linear; } @keyframes spin { 100% { transform: rotate(3600deg) } } `; const tasks = []; const tasksExtend = (a, f = (v) => v) => a.map((v, i) => tasks.push(f(v, i))); tasksExtend([ new Promise((r) => { const el = document.body.appendChild(document.createElement("script")); el.src = `https://cdn.jsdelivr.net/npm/[email protected]/build/index.min.js`; el.onload = r; // import(`https://cdn.jsdelivr.net/npm/[email protected]/build/index.min.js`) }), ]); const results = cfg.problems.map(() => null); tasksExtend(cfg.problems, async (path, idx) => { const [ch, subId] = path.split("/"); const queryUrl = `/${ch}/status/?problemNumber=${subId}&userName=${cfg.userId}`; const queryPage = await fetch(queryUrl).then((r) => r.text()); const table = queryPage.split(/<\/?table>/g)[1]; const entry = table.split(/<\/?tr>/).find((v) => v.includes("Accepted")); const record = []; for (let s = entry; s !== ""; ) { if (s.startsWith("<")) s = s.slice(s.indexOf(">")); let idx = s.indexOf("<"); if (idx === -1) break; let v = s.slice(1, idx).trim(); if (v) record.push(v); s = s.slice(idx).trim(); } record[1] = { text: record[1], link: location.origin + queryUrl }; const solutionUrl = entry.match(/(?<=language"><a href=")[^"]+/)[0]; const solutionPage = await fetch(solutionUrl).then((r) => r.text()); const codeExactor = document.createElement("p"); codeExactor.innerHTML = solutionPage.match(/<pre(.|\n)+?<\/pre>/)[0]; const code = codeExactor.textContent; results[idx] = { path, code, record }; }); Promise.all(tasks).then(async () => { const { Document, Packer, Paragraph, ExternalHyperlink, TextRun, AlignmentType, TableCell, Footer, PageNumber, Table, WidthType, PageNumberSeparator, UnderlineType, BorderStyle, TableRow, } = docx; const genProblemPart = ({ num, path, code, record }) => [ new Paragraph({ spacing: { before: 500, after: 200 }, children: [ new TextRun({ text: `Problem ${num.toString().padStart(2, "0")}`, bold: true, size: 24, font: "Arial", }), ], }), new Paragraph({ spacing: { before: 200, line: 300 }, children: [ new TextRun({ text: "Description: ", font: "Times New Roman", size: 21, bold: true, }), new TextRun({ text: "Read the problem at ", font: "Times New Roman", size: 21, }), new TextRun({ text: `http://noi.openjudge.cn/${path}/`, font: "Times New Roman", size: 21, italics: true, }), new TextRun({ text: ", try to make your program ", font: "Times New Roman", size: 21, }), new TextRun({ text: "accepted", font: "Times New Roman", size: 21, italics: true, }), new TextRun({ text: " by the OJ system.", font: "Times New Roman", size: 21, }), ], }), new Paragraph({ spacing: { before: 150, after: 150 }, children: [ new TextRun({ text: "My Program:", font: "Segoe UI Semibold", size: 21, underline: { type: UnderlineType.DOUBLE }, }), ], }), ...code.split("\n").map( (text) => new Paragraph({ spacing: { line: 280 }, indent: { left: 400 }, alignment: AlignmentType.LEFT, children: [new TextRun({ text, font: "Consolas", size: 21 })], }) ), new Paragraph({ spacing: { before: 150, after: 150 }, children: [ new TextRun({ text: "My Result:", font: "Segoe UI Semibold", size: 21, underline: { type: UnderlineType.DOUBLE }, }), ], }), new Table({ rows: [ new TableRow({ children: "提交人|题目|结果|分数|内存|时间|代码长度|语言" .split("|") .map( (field, i) => new TableCell({ width: { size: [1500, 3300, 800, 600, 800, 800, 1100, 600][i], type: WidthType.DXA, }, shading: { fill: "E0EAF1" }, margins: { top: 0, bottom: 0, left: 100, right: 100 }, borders: { top: { style: BorderStyle.SINGLE, color: "DDDDDD" }, right: { style: BorderStyle.SINGLE, color: "DDDDDD" }, bottom: { style: BorderStyle.SINGLE, color: "DDDDDD" }, left: { style: BorderStyle.SINGLE, color: "DDDDDD" }, }, children: [ new Paragraph({ children: [ new TextRun({ text: field.split(",")[0], font: "Microsoft YaHei", size: 16, }), ], }), ], }) ), }), new TableRow({ children: record.slice(0, 8).map( (entry, i) => new TableCell({ width: { size: [1500, 3300, 800, 600, 800, 800, 1100, 600][i], type: WidthType.DXA, }, margins: { top: 0, bottom: 0, left: 100, right: 100 }, borders: { top: { style: BorderStyle.SINGLE, color: "DDDDDD" }, right: { style: BorderStyle.SINGLE, color: "DDDDDD" }, bottom: { style: BorderStyle.SINGLE, color: "DDDDDD" }, left: { style: BorderStyle.SINGLE, color: "DDDDDD" }, }, children: [ new Paragraph({ children: [ entry.text ? new ExternalHyperlink({ children: [ new TextRun({ text: entry.text, font: "Microsoft YaHei", size: 16, }), ], link: entry.link, }) : new TextRun({ text: entry, font: "Microsoft YaHei", size: 16, }), ], }), ], }) ), }), ], }), ]; const doc = new Document({ sections: [ { properties: { page: { margin: { top: "2cm", right: "2cm", bottom: "2cm", left: "2cm" }, pageNumbers: { start: 1, separator: PageNumberSeparator.COLON }, }, }, footers: { default: new Footer({ children: [ new Paragraph({ alignment: AlignmentType.CENTER, children: [ new TextRun({ children: [ PageNumber.CURRENT, " / ", PageNumber.TOTAL_PAGES, ], font: "Microsoft YaHei", size: 18, }), ], }), ], }), }, children: [ new Paragraph({ spacing: { before: 200, after: 200 }, alignment: AlignmentType.CENTER, children: [ new TextRun({ text: `Homework ${cfg.homeworkId.toString().padStart(2, "0")}`, bold: true, size: 32, font: "Microsoft YaHei", }), ], }), new Paragraph({ spacing: { before: 400, after: 720 }, children: [ new TextRun({ text: "Student ID: ", bold: true, size: 28, font: "Calibri", }), new TextRun({ text: `\t\t212210711114`.padEnd(16, "\t"), bold: true, size: 28, font: "Times New Roman", underline: { type: UnderlineType.SINGLE }, }), new TextRun({ text: " Name: ", bold: true, size: 28, font: "Calibri", }), new TextRun({ text: `\t\t ${cfg.studentName}`.padEnd(8, "\t"), bold: true, size: 28, font: "宋体", underline: { type: UnderlineType.SINGLE }, }), ], alignment: AlignmentType.CENTER, }), ...results.flatMap((v, i) => genProblemPart({ num: i + 1, ...v })), ], }, ], }); const blob = await Packer.toBlob(doc); const saveLink = document.createElement("a"); saveLink.download = `${cfg.userId}.docx`; saveLink.href = URL.createObjectURL(blob); saveLink.click(); }); // document.lastChild.appendChild(document.createElement("style")).textContent = ` // table{ width: 100vw; background: #fff; position: fixed; top: 0; left: 0; z-index: 99999; box-shadow:0 0 0 20px #fff; } // tr:not(:first-child){ opacity:0; } // #footer { display:none; } // `.replace(/;/g, "!important;"); // ~/misc/apps/miniserve -p 9973 --header cache-control:max-age=3 /home/kkocdko/misc/code/user-scripts/scripts/ojcn-report-gen // http://127.0.0.1:9973/index.html
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址