';
(document.body || document.documentElement).appendChild(root);
state.mounted = true;
root.querySelector('#tm-min').addEventListener('click', function () {
state.minimized = !state.minimized;
if (state.minimized) root.classList.add('mini');
else root.classList.remove('mini');
this.textContent = state.minimized ? '+' : '—';
this.title = state.minimized ? '展开' : '收起';
});
root.querySelector('#tm-close').addEventListener('click', function () {
if (root.parentNode) root.parentNode.removeChild(root);
state.mounted = false;
});
enableDrag(root, root.querySelector('.tm-head'));
return root;
}
function enableDrag(panel, handle) {
var startX = 0, startY = 0, startRight = 0, startBottom = 0, dragging = false;
handle.addEventListener('mousedown', function (e) {
if (e.button !== 0) return;
dragging = true;
startX = e.clientX;
startY = e.clientY;
var rect = panel.getBoundingClientRect();
startRight = window.innerWidth - rect.right;
startBottom = window.innerHeight - rect.bottom;
document.addEventListener('mousemove', onMove);
document.addEventListener('mouseup', onUp);
e.preventDefault();
});
function onMove(e) {
if (!dragging) return;
var dx = e.clientX - startX;
var dy = e.clientY - startY;
var right = startRight - dx;
var bottom = startBottom - dy;
var maxRight = window.innerWidth - 120;
var maxBottom = window.innerHeight - 40;
if (right < 6) right = 6;
if (bottom < 6) bottom = 6;
if (right > maxRight) right = maxRight;
if (bottom > maxBottom) bottom = maxBottom;
panel.style.right = right + 'px';
panel.style.bottom = bottom + 'px';
panel.style.left = 'auto';
panel.style.top = 'auto';
}
function onUp() {
dragging = false;
document.removeEventListener('mousemove', onMove);
document.removeEventListener('mouseup', onUp);
}
}
function getAnswerRecordDetails(payload) {
if (!payload || payload.errorCode !== 0 || !payload.result) return [];
var result = payload.result;
var sheetDatas = deepParse(result.sheetDatas);
var details = null;
if (sheetDatas && sheetDatas.userAnswerRecordDTO && sheetDatas.userAnswerRecordDTO.answerRecordDetails) {
details = sheetDatas.userAnswerRecordDTO.answerRecordDetails;
}
if (!details && result.userAnswerRecordDTO && result.userAnswerRecordDTO.answerRecordDetails) {
details = result.userAnswerRecordDTO.answerRecordDetails;
}
return (details && details.length) ? details : [];
}
function extractCompositions(payload) {
var details = getAnswerRecordDetails(payload);
if (!details.length) return [];
var list = [];
var i, d, ss, typeId;
for (i = 0; i < details.length; i++) {
d = details[i];
if (!d) continue;
typeId = String(d.topicTypeId || '');
ss = Number(d.standardScore || 0);
// 主规则:写作类主观题 06/07,标准分>=10
if (d.answerType === 's02Image' && (typeId === '06' || typeId === '07') && ss >= 10) {
list.push(d);
}
}
// 兜底:若未命中,则主观题里取标准分最高前3(>=10)
if (!list.length) {
var subjective = [];
for (i = 0; i < details.length; i++) {
d = details[i];
if (d && d.answerType === 's02Image' && Number(d.standardScore || 0) >= 10) {
subjective.push(d);
}
}
subjective.sort(function (a, b) {
return Number(b.standardScore || 0) - Number(a.standardScore || 0);
});
for (i = 0; i < subjective.length && i < 3; i++) list.push(subjective[i]);
}
// 去重(按 topicNumber)
var seen = {};
var unique = [];
for (i = 0; i < list.length; i++) {
var key = String(list[i].topicNumber || ('idx_' + i));
if (!seen[key]) {
seen[key] = 1;
unique.push(list[i]);
}
}
unique.sort(function (a, b) {
return Number(a.topicNumber || 0) - Number(b.topicNumber || 0);
});
return unique;
}
function buildTeacherScores(comp) {
var scores = [];
var subTopics = comp && comp.subTopics ? comp.subTopics : [];
var i, j, st, recs, r;
for (i = 0; i < subTopics.length; i++) {
st = subTopics[i];
recs = st && st.teacherMarkingRecords ? st.teacherMarkingRecords : [];
if (recs.length) {
for (j = 0; j < recs.length; j++) {
r = recs[j];
if (r && r.score != null) scores.push(Number(r.score));
}
} else if (st && st.score != null) {
scores.push(Number(st.score));
}
}
return scores;
}
function renderCompositions(comps) {
var root = ensureUI();
var body = root.querySelector('#' + BODY_ID);
if (!body) return;
if (!comps || !comps.length) {
body.innerHTML = '
已命中接口,但未识别到作文/写作大题
';
return;
}
var html = '';
var i, j;
for (i = 0; i < comps.length; i++) {
var c = comps[i];
var title = c.dispTitle != null ? c.dispTitle : (c.topicNumber != null ? c.topicNumber : '-');
var typeId = c.topicTypeId != null ? String(c.topicTypeId) : '-';
var finalScore = c.score != null ? c.score : '-';
var fullScore = c.standardScore != null ? c.standardScore : '-';
html += '
题号 / 类型' + title + ' / ' + typeId + '
';
html += '
最终得分' + finalScore + ' / ' + fullScore + '
';
var scores = buildTeacherScores(c);
if (scores.length) {
var sum = 0;
for (j = 0; j < scores.length; j++) sum += scores[j];
var avg = Math.round((sum / scores.length) * 100) / 100;
html += '
';
for (j = 0; j < scores.length; j++) {
html += '
老师' + (j + 1) + '' + scores[j] + ' 分
';
}
html += '
均分' + avg + ' 分
';
html += '
';
} else {
html += '
无老师明细,仅有最终分
';
}
if (i !== comps.length - 1) html += '';
}
body.innerHTML = html;
}
function maybeHandle(url, text) {
if (!/checksheet/i.test(String(url || ''))) return;
var payload = deepParse(text);
if (!payload || typeof payload !== 'object') return;
var comps = extractCompositions(payload);
renderCompositions(comps);
}
// 初始化UI
ensureUI();
// 防止 body 晚加载
var timer = setInterval(function () {
if (!state.mounted) ensureUI();
}, 500);
setTimeout(function () { clearInterval(timer); }, 15000);
// Hook fetch
var rawFetch = window.fetch;
if (typeof rawFetch === 'function') {
window.fetch = function () {
var args = arguments;
return rawFetch.apply(this, args).then(function (resp) {
try {
var req0 = args[0];
var url = (req0 && req0.url) ? req0.url : String(req0 || '');
if (/checksheet/i.test(url) && resp && typeof resp.clone === 'function') {
resp.clone().text().then(function (txt) {
maybeHandle(url, txt);
});
}
} catch (e) {}
return resp;
});
};
}
// Hook XHR
var rawOpen = XMLHttpRequest.prototype.open;
var rawSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.open = function (method, url, async, user, password) {
this.__tm_url = url;
return rawOpen.call(this, method, url, async, user, password);
};
XMLHttpRequest.prototype.send = function () {
this.addEventListener('load', function () {
try { maybeHandle(this.__tm_url, this.responseText); } catch (e) {}
});
return rawSend.apply(this, arguments);
};
})();