Introduction

这个记得是jiepeng哥一开始写了个只能查看作业分数的脚本,后来无意间发现了一个更好的包,后面便结合着gpt改良了一下;

能够将作业和考试的分数罗列在右下角建出来的面板之中

Usage

将其放入油猴插件中启用即可

Codes

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
// ==UserScript==
// @name XZZD_Score_findv1.1
// @namespace http://tampermonkey.net/
// @version 1.1
// @description Display homework scores on the page for various courses
// @author Soleil
// @match *://courses.zju.edu.cn/course/*/*
// @grant none
// ==/UserScript==


(function() {
'use strict';

const courseUrlMatch = window.location.pathname.match(/\/course\/(\d+)\//);
if (!courseUrlMatch) {
console.error('Unable to find course ID in the URL.');
return;
}
const courseId = courseUrlMatch[1];

const scoreContainer = document.createElement('div');
scoreContainer.id = 'score-container';
scoreContainer.style.position = 'fixed';
scoreContainer.style.bottom = '0';
scoreContainer.style.right = '0';
scoreContainer.style.zIndex = '1000';
scoreContainer.style.backgroundColor = 'white';
scoreContainer.style.border = '1px solid black';
scoreContainer.style.maxHeight = '300px';
scoreContainer.style.overflowY = 'auto';
scoreContainer.style.padding = '10px';
scoreContainer.style.width = '350px';
document.body.appendChild(scoreContainer);

let data_first;
let data_second;

const apiUrl = `https://courses.zju.edu.cn/api/course/${courseId}/activity-reads-for-user`;
fetch(apiUrl)
.then(response => response.json())
.then(data => {
console.log('Data from main API:', data); // Log to inspect the data structure
const data_api = data;

const apiUrl1 = `https://courses.zju.edu.cn/api/course/${courseId}/homework-scores?fields=id,title`;
const apiUrl2 = `https://courses.zju.edu.cn/api/courses/${courseId}/exams`;

return Promise.all([fetch(apiUrl1), fetch(apiUrl2), data_api]); // 并行请求
})
.then(async ([response1, response2, data_api]) => {
data_first = await response1.json(); // 第一个 API 的数据
data_second = await response2.json(); // 第二个 API 的数据

console.log('Data from API1:', data_first);
console.log('Data from API2:', data_second);

if (!data_first || !data_first.homework_activities) {
console.error('Homework activities data is missing.');
return;
}

if (!data_second || !data_second.exams) {
console.error('Exams data is missing.');
return;
}

const data_final = merge(data_second.exams, data_first.homework_activities, data_api.activity_reads);
displayScores(data_final);
})
.catch(error => console.error('Error fetching the data:', error));

function merge(examsActivities, homeworkActivities, activityReads) {
const homeworkMap = new Map();
const examsMap = new Map();

homeworkActivities.forEach(activity => {
homeworkMap.set(activity.id, activity.title);
});

examsActivities.forEach(exam => {
examsMap.set(exam.id, exam.title);
});

const updatedActivityReads = activityReads.map(activityRead => {
let title = 'Unknown Title';
if (homeworkMap.has(activityRead.activity_id)) {
title = homeworkMap.get(activityRead.activity_id);
} else if (examsMap.has(activityRead.activity_id)) {
title = examsMap.get(activityRead.activity_id);
}

return {
...activityRead,
title
};
});

console.log('Updated activity reads:', updatedActivityReads);
return updatedActivityReads;
}

function displayScores(activityReads) {
if (activityReads.length === 0) {
scoreContainer.innerHTML = `<strong>No homework data available for course ${courseId}.</strong>`;
return;
}

activityReads.forEach(activity => {
const entry = document.createElement('div');
entry.style.borderBottom = '1px solid #ddd';
entry.style.marginBottom = '5px';
entry.style.paddingBottom = '5px';

if (activity.activity_type === "learning_activity") {
if (activity.title != 'Unknown Title') {
entry.innerHTML = `<strong>Title:</strong> ${activity.title}<br>
<strong>Score:</strong> ${activity.data.score}`;
} else {
entry.innerHTML = `<strong>其他学习活动</strong>`;

const toggleButton = document.createElement('button');
toggleButton.innerText = '显示详情';
toggleButton.style.display = 'block';
toggleButton.style.marginTop = '5px';

const detailsContainer = document.createElement('div');
detailsContainer.style.display = 'none';
detailsContainer.style.marginTop = '5px';

for (const key in activity) {
if (activity.hasOwnProperty(key)) {
const detailEntry = document.createElement('div');
detailEntry.innerHTML = `<strong>${key}:</strong> ${activity[key]}`;
detailsContainer.appendChild(detailEntry);
}
}

toggleButton.addEventListener('click', () => {
if (detailsContainer.style.display === 'none') {
detailsContainer.style.display = 'block';
toggleButton.innerText = '隐藏详情';
} else {
detailsContainer.style.display = 'none';
toggleButton.innerText = '显示详情';
}
});

entry.appendChild(toggleButton);
entry.appendChild(detailsContainer);
}
} else if (activity.activity_type === "exam_activity") {
entry.innerHTML = `<strong>Type:</strong> ${activity.activity_type}<br>
<strong>Title:</strong> ${activity.title}<br>
<strong>Score:</strong> ${activity.data.score}`;
} else {
entry.innerHTML = `<strong>Title:</strong> ${activity.title}<br>
<strong>Score:</strong> No data available`;
}

scoreContainer.appendChild(entry);
});
}
})();

声明

(叠甲x)本插件作为学习使用,造成的一切后果均由使用人承担,本人概不负责