// ==UserScript==
// @name 正方教务教学评价
// @namespace https://scriptcat.org/
// @version 2.0.3
// @description 支持批量评价、自动切换课程、检测绕过的教学评价自动化脚本
// @author 征途wd
// @match https://*.edu.cn/jwglxt/xspjgl/xspj_cxXspjIndex.html*
// @match http://*.edu.cnw/jwglxt/xspjgl/xspj_cxXspjIndex.html*
// @grant none
// @license MIT
// @supportURL https://github.com/wdvipa/ZF_evaluation_script/issues/new
// @homepageURL https://scriptcat.org/zh-CN/script-show-page/4914
// ==/UserScript==
(function () {
const DEBUG_MODE = false;
const Version = '2.0.3';
const sleep = (delay) => new Promise((resolve) => setTimeout(resolve, delay));
const CSS_STYLES = {
// 按钮样式
button: {
base: `
width: 100%;
height: 35px;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 11px;
font-weight: bold;
transition: all 0.3s ease;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
`,
hover: {
opacity: '0.8',
transform: 'scale(1.02)'
},
normal: {
opacity: '1',
transform: 'scale(1)'
}
},
// 面板样式
panel: {
main: `
position: fixed;
left: 50%;
top: 10px;
transform: translateX(-50%);
z-index: 9999;
background: rgba(30, 30, 30, 0.85);
backdrop-filter: blur(15px);
padding: 15px;
border-radius: 12px;
box-shadow: 0 4px 20px rgba(0,0,0,0.5);
width: 300px;
height: 650px;
max-height: 90vh;
min-width: 200px;
min-height: 200px;
overflow-y: auto;
cursor: move;
user-select: none;
color: white;
font-family: 'Consolas', 'Monaco', monospace;
display: flex;
flex-direction: column;
`,
titleBar: `
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
padding-bottom: 10px;
border-bottom: 2px solid #e0e0e0;
`,
title: `
margin: 0;
color: #fff;
font-size: 16px;
font-weight: bold;
`,
authorInfo: `
display: flex;
align-items: center;
gap: 8px;
margin-top: 5px;
font-size: 12px;
color: #ccc;
`,
authorLink: `
color: #00a1d6;
text-decoration: none;
cursor: pointer;
transition: color 0.3s;
`
},
// 控制按钮样式
controls: {
minimizeBtn: `
background: rgba(255, 255, 255, 0.2);
border: 1px solid rgba(255, 255, 255, 0.3);
border-radius: 4px;
width: 30px;
height: 30px;
cursor: pointer;
font-size: 20px;
line-height: 1;
color: white;
transition: all 0.3s;
`,
clearLogBtn: `
background: rgba(255, 255, 255, 0.2);
border: 1px solid rgba(255, 255, 255, 0.3);
border-radius: 4px;
width: 30px;
height: 30px;
cursor: pointer;
font-size: 14px;
line-height: 1;
color: white;
transition: all 0.3s;
margin-right: 5px;
`
},
// 设置区域样式
settings: {
area: `
margin-bottom: 10px;
padding: 10px;
background: rgba(255, 255, 255, 0.1);
border-radius: 6px;
border: 1px solid rgba(255, 255, 255, 0.2);
`,
title: `
font-size: 14px;
font-weight: bold;
color: #fff;
margin-bottom: 8px;
`,
radioGroup: `
display: flex;
gap: 20px;
align-items: center;
`,
radioLabel: `
display: flex;
align-items: center;
cursor: pointer;
font-size: 13px;
color: #fff;
`,
divider: `
margin-top: 8px;
padding-top: 8px;
border-top: 1px solid rgba(255, 255, 255, 0.2);
`,
select: `
width: 100%;
padding: 4px 8px;
border: 1px solid rgba(255, 255, 255, 0.3);
border-radius: 4px;
background: rgba(255, 255, 255, 0.1);
color: #fff;
font-size: 12px;
`
},
// 按钮容器样式
buttonContainer: `
display: grid;
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
gap: 6px;
margin-bottom: 10px;
`,
// 日志区域样式
log: {
area: `
margin-top: 10px;
padding: 10px;
background: rgba(0, 0, 0, 0.3);
border-radius: 6px;
border: 1px solid rgba(255, 255, 255, 0.2);
min-height: 120px;
overflow-y: auto;
font-size: 12px;
line-height: 1.4;
flex: 1;
display: flex;
flex-direction: column;
`,
title: `
font-size: 13px;
font-weight: bold;
color: #4CAF50;
margin-bottom: 5px;
border-bottom: 1px solid rgba(255, 255, 255, 0.2);
padding-bottom: 3px;
`,
content: `
color: #e0e0e0;
font-family: 'Consolas', 'Monaco', monospace;
white-space: pre-wrap;
word-break: break-all;
flex: 1;
overflow-y: auto;
`,
line: (color) => `
color: ${color};
margin-bottom: 2px;
padding: 2px 0;
border-left: 3px solid ${color};
padding-left: 8px;
margin-left: 5px;
flex-shrink: 0;
`
},
// 调整大小手柄样式
resizeHandle: `
position: absolute;
bottom: 0;
right: 0;
width: 20px;
height: 20px;
background: linear-gradient(-45deg, transparent 30%, rgba(255,255,255,0.4) 30%, rgba(255,255,255,0.4) 70%, transparent 70%);
cursor: nw-resize;
border-bottom-right-radius: 12px;
transition: all 0.3s ease;
`,
// 状态显示样式
status: {
submitted: `
margin-top: 10px;
padding: 8px 12px;
background: rgba(76, 175, 80, 0.2);
border: 1px solid rgba(76, 175, 80, 0.5);
border-radius: 6px;
color: #4CAF50;
font-size: 13px;
text-align: center;
font-weight: bold;
`
},
// 通知样式
notification: `
position: fixed;
top: 20px;
right: 20px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 10px 15px;
border-radius: 5px;
z-index: 10000;
font-size: 14px;
`,
// 按钮颜色
colors: {
excellent: '#28a745',
good: '#6f42c1',
qualified: '#007bff',
unqualified: '#dc3545',
batch: '#17a2b8',
navigation: '#795548',
donate: '#FFD700',
debug: '#6c757d'
},
// 悬停效果
hover: {
authorLink: { color: '#40c5ff' },
minimizeBtn: { background: 'rgba(255, 255, 255, 0.3)' },
clearLogBtn: { background: 'rgba(255, 100, 100, 0.3)' },
resizeHandle: { background: 'linear-gradient(-45deg, transparent 20%, rgba(255,255,255,0.6) 20%, rgba(255,255,255,0.6) 80%, transparent 80%)' }
}
};
const applyStyles = (element, styleString) => {
element.style.cssText = styleString;
};
const addHoverEffect = (element, hoverStyles, normalStyles) => {
element.addEventListener('mouseenter', () => {
Object.assign(element.style, hoverStyles);
});
element.addEventListener('mouseleave', () => {
Object.assign(element.style, normalStyles);
});
};
const createButton = (id, text, color) => {
const button = document.createElement('button');
button.id = id;
applyStyles(button, CSS_STYLES.button.base + `background-color: ${color};`);
button.innerText = text;
addHoverEffect(button,
CSS_STYLES.button.hover,
CSS_STYLES.button.normal
);
return button;
};
const addButton = (parent, button) => {
parent.appendChild(button);
};
const selectAllItems = (doc, optionIndex) => {
let selectedCount = 0;
for (let i = optionIndex; i < doc.length; i += 4) {
if (doc[i]) {
doc[i].checked = true;
selectedCount++;
}
}
logSuccess(`已选择 ${selectedCount} 个评价项的选项 ${['优秀', '良好', '合格', '不合格'][optionIndex]}`);
const requiredItems = document.querySelectorAll('.tr-xspj[data-sfbt="1"]');
logDebug(`页面共有 ${requiredItems.length} 个必填评价项`);
};
const autoSave = () => {
const saveBtn = document.querySelector('#btn_xspj_bc') ||
document.querySelector('button[onclick*="baocun"]') ||
document.querySelector('input[value*="保存"]');
if (saveBtn) {
if (!$(saveBtn).data("enter")) {
$(saveBtn).data("enter", "1");
}
const mouseEnterEvent = new MouseEvent('mouseenter', {
bubbles: true,
cancelable: true,
view: window
});
saveBtn.dispatchEvent(mouseEnterEvent);
setTimeout(() => {
saveBtn.click();
logSuccess('✅ 已自动保存评价');
}, 100);
return true;
} else {
logError('❌ 未找到保存按钮');
return false;
}
};
const autoSubmit = () => {
const saved = autoSave();
if (saved) {
setTimeout(() => {
const submitBtn = document.querySelector('#btn_xspj_tj') ||
document.querySelector('button[onclick*="tijiao"]') ||
document.querySelector('input[value*="提交"]') ||
document.querySelector('button:contains("提交")');
if (submitBtn) {
if (!$(submitBtn).data("enter")) {
$(submitBtn).data("enter", "1");
}
const mouseEnterEvent = new MouseEvent('mouseenter', {
bubbles: true,
cancelable: true,
view: window
});
submitBtn.dispatchEvent(mouseEnterEvent);
setTimeout(() => {
submitBtn.click();
logSuccess('✅ 已自动提交评价');
}, 100);
} else {
logError('❌ 未找到提交按钮');
}
}, 1000);
}
};
const configPanel = document.createElement('div');
configPanel.id = 'evalConfigPanel';
applyStyles(configPanel, CSS_STYLES.panel.main);
const titleBar = document.createElement('div');
applyStyles(titleBar, CSS_STYLES.panel.titleBar);
const title = document.createElement('h4');
applyStyles(title, CSS_STYLES.panel.title);
title.textContent = `🎯 评价助手 v${Version}`;
const authorInfo = document.createElement('div');
applyStyles(authorInfo, CSS_STYLES.panel.authorInfo);
const authorText = document.createElement('span');
authorText.textContent = 'by:';
const authorLink = document.createElement('a');
authorLink.href = 'https://space.bilibili.com/353379484';
authorLink.target = '_blank';
authorLink.textContent = '征途wd';
applyStyles(authorLink, CSS_STYLES.panel.authorLink);
addHoverEffect(authorLink,
CSS_STYLES.hover.authorLink,
{ color: '#00a1d6' }
);
authorInfo.appendChild(authorText);
authorInfo.appendChild(authorLink);
const minimizeBtn = document.createElement('button');
minimizeBtn.textContent = '−';
applyStyles(minimizeBtn, CSS_STYLES.controls.minimizeBtn);
addHoverEffect(minimizeBtn,
CSS_STYLES.hover.minimizeBtn,
{ background: 'rgba(255, 255, 255, 0.2)' }
);
const clearLogBtn = document.createElement('button');
clearLogBtn.textContent = '🗑️';
clearLogBtn.title = '清空日志';
applyStyles(clearLogBtn, CSS_STYLES.controls.clearLogBtn);
addHoverEffect(clearLogBtn,
CSS_STYLES.hover.clearLogBtn,
{ background: 'rgba(255, 255, 255, 0.2)' }
);
const buttonGroup = document.createElement('div');
buttonGroup.style.display = 'flex';
buttonGroup.appendChild(clearLogBtn);
buttonGroup.appendChild(minimizeBtn);
const titleContainer = document.createElement('div');
titleContainer.appendChild(title);
titleContainer.appendChild(authorInfo);
titleBar.appendChild(titleContainer);
titleBar.appendChild(buttonGroup);
// 创建设置区域
const settingsArea = document.createElement('div');
applyStyles(settingsArea, CSS_STYLES.settings.area);
const settingsTitle = document.createElement('div');
applyStyles(settingsTitle, CSS_STYLES.settings.title);
settingsTitle.textContent = '⚙️ 自动操作设置';
const radioGroup = document.createElement('div');
applyStyles(radioGroup, CSS_STYLES.settings.radioGroup);
// 自动保存选项
const saveRadio = document.createElement('label');
applyStyles(saveRadio, CSS_STYLES.settings.radioLabel);
saveRadio.innerHTML = `
自动保存
`;
// 自动提交选项
const submitRadio = document.createElement('label');
applyStyles(submitRadio, CSS_STYLES.settings.radioLabel);
submitRadio.innerHTML = `
自动提交
`;
// 不自动操作选项
const noneRadio = document.createElement('label');
applyStyles(noneRadio, CSS_STYLES.settings.radioLabel);
noneRadio.innerHTML = `
不自动操作
`;
radioGroup.appendChild(saveRadio);
radioGroup.appendChild(submitRadio);
radioGroup.appendChild(noneRadio);
// 添加自动切换课程选项
const autoSwitchDiv = document.createElement('div');
applyStyles(autoSwitchDiv, CSS_STYLES.settings.divider);
const autoSwitchLabel = document.createElement('label');
applyStyles(autoSwitchLabel, CSS_STYLES.settings.radioLabel);
autoSwitchLabel.innerHTML = `
自动跳过已提交课程
`;
autoSwitchDiv.appendChild(autoSwitchLabel);
// 添加评价后自动切换选项
const autoNextDiv = document.createElement('div');
applyStyles(autoNextDiv, CSS_STYLES.settings.divider);
const autoNextLabel = document.createElement('label');
applyStyles(autoNextLabel, CSS_STYLES.settings.radioLabel);
autoNextLabel.innerHTML = `
评价后自动切换下一个
`;
autoNextDiv.appendChild(autoNextLabel);
// 添加批量评价等级选择
const batchLevelDiv = document.createElement('div');
applyStyles(batchLevelDiv, CSS_STYLES.settings.divider);
const batchLevelTitle = document.createElement('div');
applyStyles(batchLevelTitle, CSS_STYLES.settings.title.replace('14px', '12px').replace('8px', '5px'));
batchLevelTitle.textContent = '批量评价等级:';
const batchLevelSelect = document.createElement('select');
batchLevelSelect.id = 'batchEvalLevel';
applyStyles(batchLevelSelect, CSS_STYLES.settings.select);
const levelOptions = [
['🌟 优秀 (100分)', '100'],
['👍 良好 (85分)', '85'],
['✅ 合格 (75分)', '75'],
['❌ 不合格 (50分)', '50']
];
levelOptions.forEach(([text, score], index) => {
const option = document.createElement('option');
Object.assign(option, { value: index, textContent: text });
option.setAttribute('data-score', score);
batchLevelSelect.appendChild(option);
});
// 默认选择优秀
batchLevelSelect.value = '0';
batchLevelDiv.appendChild(batchLevelTitle);
batchLevelDiv.appendChild(batchLevelSelect);
settingsArea.appendChild(settingsTitle);
settingsArea.appendChild(radioGroup);
settingsArea.appendChild(autoSwitchDiv);
settingsArea.appendChild(autoNextDiv);
settingsArea.appendChild(batchLevelDiv);
// 创建按钮容器
const btnContainer = document.createElement('div');
applyStyles(btnContainer, CSS_STYLES.buttonContainer);
const btna = createButton('btna', '🌟 优秀', CSS_STYLES.colors.excellent);
const btnb = createButton('btnb', '👍 良好', CSS_STYLES.colors.good);
const btnc = createButton('btnc', '✅ 合格', CSS_STYLES.colors.qualified);
const btnd = createButton('btnd', '❌ 不合格', CSS_STYLES.colors.unqualified);
const btnAuto = createButton('btnAuto', '⚡ 批量评价', CSS_STYLES.colors.batch);
// 添加课程切换按钮
const btnPrev = createButton('btnPrev', '⬅️ 上一个', CSS_STYLES.colors.navigation);
const btnNext = createButton('btnNext', '➡️ 下一个', CSS_STYLES.colors.navigation);
// 添加打赏按钮
const btnDonate = createButton('btnDonate', '💰 打赏作者', CSS_STYLES.colors.donate);
addButton(btnContainer, btna);
addButton(btnContainer, btnb);
addButton(btnContainer, btnc);
addButton(btnContainer, btnd);
addButton(btnContainer, btnAuto);
addButton(btnContainer, btnPrev);
addButton(btnContainer, btnNext);
addButton(btnContainer, btnDonate);
// 创建日志区域
const logArea = document.createElement('div');
applyStyles(logArea, CSS_STYLES.log.area);
const logTitle = document.createElement('div');
applyStyles(logTitle, CSS_STYLES.log.title);
logTitle.textContent = '📋 运行日志';
const logContent = document.createElement('div');
logContent.id = 'scriptLog';
applyStyles(logContent, CSS_STYLES.log.content);
logArea.appendChild(logTitle);
logArea.appendChild(logContent);
// 创建调整大小手柄
const resizeHandle = document.createElement('div');
applyStyles(resizeHandle, CSS_STYLES.resizeHandle);
// 添加悬停效果
addHoverEffect(resizeHandle,
CSS_STYLES.hover.resizeHandle,
{ background: 'linear-gradient(-45deg, transparent 30%, rgba(255,255,255,0.4) 30%, rgba(255,255,255,0.4) 70%, transparent 70%)' }
);
// 组装面板
configPanel.appendChild(titleBar);
configPanel.appendChild(logArea);
configPanel.appendChild(settingsArea);
configPanel.appendChild(btnContainer);
configPanel.appendChild(resizeHandle);
document.body.appendChild(configPanel);
// 实现拖拽功能
let isDragging = false;
let isResizing = false;
let currentX;
let currentY;
let initialX;
let initialY;
let xOffset = 0;
let yOffset = 0;
titleBar.addEventListener('mousedown', dragStart);
resizeHandle.addEventListener('mousedown', resizeStart);
document.addEventListener('mousemove', handleMouseMove);
document.addEventListener('mouseup', handleMouseUp);
function dragStart(e) {
if (e.target === titleBar || e.target === title) {
// 如果是最小化状态,点击标题栏展开
if (isMinimized) {
minimizeBtn.click();
return;
}
initialX = e.clientX - xOffset;
initialY = e.clientY - yOffset;
isDragging = true;
e.preventDefault();
}
}
function resizeStart(e) {
isResizing = true;
initialX = e.clientX;
initialY = e.clientY;
e.preventDefault();
e.stopPropagation();
}
function handleMouseMove(e) {
if (isDragging) {
e.preventDefault();
currentX = e.clientX - initialX;
currentY = e.clientY - initialY;
xOffset = currentX;
yOffset = currentY;
configPanel.style.transform = `translate(calc(-50% + ${currentX}px), ${currentY}px)`;
} else if (isResizing) {
e.preventDefault();
const deltaX = e.clientX - initialX;
const deltaY = e.clientY - initialY;
const currentWidth = parseInt(configPanel.style.width) || 350;
// 获取当前高度,如果是auto则使用实际高度
let currentHeight;
if (configPanel.style.height === 'auto' || !configPanel.style.height) {
currentHeight = configPanel.offsetHeight;
} else {
currentHeight = parseInt(configPanel.style.height);
}
const newWidth = Math.max(300, currentWidth + deltaX);
const newHeight = Math.max(200, currentHeight + deltaY);
configPanel.style.width = newWidth + 'px';
configPanel.style.height = newHeight + 'px';
// 确保面板有滚动功能
configPanel.style.overflowY = 'auto';
// 更新日志区域布局
updateLogAreaLayout();
initialX = e.clientX;
initialY = e.clientY;
}
}
function handleMouseUp(e) {
if (isDragging) {
initialX = currentX;
initialY = currentY;
}
isDragging = false;
isResizing = false;
}
// 更新日志区域响应式布局
const updateLogAreaLayout = () => {
const logElement = document.getElementById('scriptLog');
if (logElement) {
// 确保滚动到底部
setTimeout(() => {
logElement.scrollTop = logElement.scrollHeight;
}, 10);
}
};
// 日志系统
const originalConsoleLog = console.log;
const logToPanel = (message, type = 'info') => {
const timestamp = new Date().toLocaleTimeString();
const logElement = document.getElementById('scriptLog');
if (logElement) {
const colors = {
info: '#e0e0e0',
success: '#4CAF50',
warning: '#FF9800',
error: '#f44336',
debug: '#2196F3'
};
const logLine = document.createElement('div');
applyStyles(logLine, CSS_STYLES.log.line(colors[type] || colors.info));
logLine.textContent = `[${timestamp}] ${message}`;
logElement.appendChild(logLine);
// 自动滚动到底部
updateLogAreaLayout();
// 限制日志条数,避免内存占用过多
while (logElement.children.length > 150) {
logElement.removeChild(logElement.firstChild);
}
}
};
console.log = function(...args) {
const message = args.join(' ');
logToPanel(message, 'info');
originalConsoleLog.apply(console, args);
};
const logFunctions = {
logSuccess: 'success',
logWarning: 'warning',
logError: 'error'
};
Object.entries(logFunctions).forEach(([name, type]) => {
window[name] = (message) => logToPanel(message, type);
});
window.logDebug = (message) => {
if (DEBUG_MODE) {
logToPanel(message, 'debug');
}
};
// 清空日志功能
clearLogBtn.addEventListener('click', () => {
const logElement = document.getElementById('scriptLog');
if (logElement) {
logElement.innerHTML = '';
logSuccess('日志已清空');
updateLogAreaLayout();
}
});
// 最小化/展开功能
let isMinimized = false;
let originalWidth = '300px';
let originalHeight = '650px';
minimizeBtn.addEventListener('click', () => {
isMinimized = !isMinimized;
if (isMinimized) {
// 保存当前尺寸
originalWidth = configPanel.style.width || '300px';
originalHeight = configPanel.style.height || '650px';
settingsArea.style.display = 'none';
btnContainer.style.display = 'none';
logArea.style.display = 'none';
resizeHandle.style.display = 'none';
// 隐藏状态提示框
const statusDiv = document.getElementById('submissionStatusDiv');
if (statusDiv) {
statusDiv.style.display = 'none';
}
// 最小化样式优化
minimizeBtn.textContent = '📌';
minimizeBtn.title = '展开面板';
title.textContent = '🎯 评价助手';
authorInfo.style.display = 'none';
configPanel.style.width = '140px';
configPanel.style.height = 'auto';
configPanel.style.minHeight = 'auto';
configPanel.style.padding = '8px 12px';
configPanel.style.flexDirection = 'row';
configPanel.style.cursor = 'pointer';
titleBar.style.marginBottom = '0';
titleBar.style.paddingBottom = '0';
titleBar.style.borderBottom = 'none';
titleBar.style.justifyContent = 'flex-start';
titleBar.style.gap = '8px';
// 添加点击标题栏展开的功能
titleBar.style.cursor = 'pointer';
} else {
settingsArea.style.display = 'block';
btnContainer.style.display = 'grid';
logArea.style.display = 'flex';
resizeHandle.style.display = 'block';
// 显示状态提示框
const statusDiv = document.getElementById('submissionStatusDiv');
if (statusDiv) {
statusDiv.style.display = 'block';
}
// 恢复展开样式
minimizeBtn.textContent = '−';
minimizeBtn.title = '最小化面板';
title.textContent = `🎯 评价助手 v${Version}`;
authorInfo.style.display = 'flex';
configPanel.style.width = originalWidth;
configPanel.style.height = originalHeight;
configPanel.style.minHeight = '200px';
configPanel.style.padding = '15px';
configPanel.style.flexDirection = 'column';
configPanel.style.cursor = 'move';
titleBar.style.marginBottom = '10px';
titleBar.style.paddingBottom = '10px';
titleBar.style.borderBottom = '2px solid #e0e0e0';
titleBar.style.justifyContent = 'space-between';
titleBar.style.gap = '';
titleBar.style.cursor = 'move';
// 确保日志区域正确显示
setTimeout(() => {
const logElement = document.getElementById('scriptLog');
if (logElement && logElement.scrollHeight > logElement.clientHeight) {
logElement.scrollTop = logElement.scrollHeight;
}
}, 100);
}
});
// 获取当前设置
const getAutoAction = () => {
const selected = document.querySelector('input[name="autoAction"]:checked');
return selected ? selected.value : 'save';
};
// 获取自动切换设置
const getAutoSwitchSetting = () => {
const checkbox = document.getElementById('autoSwitchCourse');
return checkbox ? checkbox.checked : false;
};
// 获取评价后自动切换下一个设置
const getAutoNextAfterEvalSetting = () => {
const checkbox = document.getElementById('autoNextAfterEval');
return checkbox ? checkbox.checked : false;
};
// 获取批量评价等级设置
const getBatchEvalLevel = () => {
const select = document.getElementById('batchEvalLevel');
if (!select) return { index: 0, score: '100', name: '优秀' };
const selectedOption = select.options[select.selectedIndex];
const levelNames = ['优秀', '良好', '合格', '不合格'];
return {
index: parseInt(select.value),
score: selectedOption.getAttribute('data-score'),
name: levelNames[parseInt(select.value)]
};
};
// 课程切换功能
const switchCourse = (direction) => {
logSuccess(`🔄 正在切换到${direction === 'next' ? '下一个' : '上一个'}课程...`);
try {
// 方法1: 通过jqGrid表格切换课程
const grid = $('#tempGrid');
if (grid.length > 0) {
const currentRowId = grid.jqGrid('getGridParam', 'selrow');
const allRowIds = grid.jqGrid('getDataIDs');
logDebug(`当前选中行ID: ${currentRowId}, 总行数: ${allRowIds.length}`);
if (allRowIds.length > 0) {
let targetRowId = null;
const currentIndex = allRowIds.indexOf(currentRowId);
if (direction === 'next') {
// 查找下一个课程
for (let i = currentIndex + 1; i < allRowIds.length; i++) {
const rowData = grid.jqGrid('getRowData', allRowIds[i]);
// 如果开启了自动跳过,则跳过已提交的课程
if (getAutoSwitchSetting() && (rowData.tjztmc === '提交')) {
logDebug(`跳过已提交课程: ${rowData.jxbmc}`);
continue;
}
targetRowId = allRowIds[i];
break;
}
// 如果没找到,从头开始找
if (!targetRowId) {
for (let i = 0; i < currentIndex; i++) {
const rowData = grid.jqGrid('getRowData', allRowIds[i]);
if (getAutoSwitchSetting() && (rowData.tjztmc === '提交')) {
continue;
}
targetRowId = allRowIds[i];
break;
}
}
} else {
// 查找上一个课程
for (let i = currentIndex - 1; i >= 0; i--) {
const rowData = grid.jqGrid('getRowData', allRowIds[i]);
if (getAutoSwitchSetting() && (rowData.tjztmc === '提交')) {
logDebug(`跳过已提交课程: ${rowData.jxbmc}`);
continue;
}
targetRowId = allRowIds[i];
break;
}
// 如果没找到,从末尾开始找
if (!targetRowId) {
for (let i = allRowIds.length - 1; i > currentIndex; i--) {
const rowData = grid.jqGrid('getRowData', allRowIds[i]);
if (getAutoSwitchSetting() && (rowData.tjztmc === '提交')) {
continue;
}
targetRowId = allRowIds[i];
break;
}
}
}
if (targetRowId) {
const targetRowData = grid.jqGrid('getRowData', targetRowId);
logSuccess(`🎯 切换到课程: ${targetRowData.jxbmc} (${targetRowData.jzgmc})`);
// 选中目标行
grid.jqGrid('setSelection', targetRowId);
// 触发行选择事件,加载课程评价内容
setTimeout(() => {
const row = $(`#${targetRowId}`);
if (row.length > 0) {
row.trigger('click');
// 等待页面加载完成后重新检测提交状态
setTimeout(() => {
logDebug('🔍 重新检测课程提交状态...');
displaySubmissionStatus();
}, 2000);
}
}, 500);
return true;
} else {
if (getAutoSwitchSetting()) {
logWarning('❌ 没有找到未提交的课程');
} else {
logWarning('❌ 已经是最后一个课程');
}
return false;
}
}
}
// 方法2: 通过课程链接切换(备用方案)
const courseRows = document.querySelectorAll('#tempGrid tr[role="row"]');
if (courseRows.length > 1) { // 排除表头
logDebug(`找到 ${courseRows.length - 1} 个课程行`);
// 查找当前选中的行
const selectedRow = document.querySelector('#tempGrid tr.ui-state-highlight');
if (selectedRow) {
const allRows = Array.from(courseRows).slice(1); // 排除表头
const currentIndex = allRows.indexOf(selectedRow);
let targetIndex = -1;
if (direction === 'next') {
targetIndex = (currentIndex + 1) % allRows.length;
} else {
targetIndex = currentIndex > 0 ? currentIndex - 1 : allRows.length - 1;
}
if (targetIndex >= 0 && allRows[targetIndex]) {
const targetRow = allRows[targetIndex];
targetRow.click();
const courseName = targetRow.querySelector('td[aria-describedby*="jxbmc"]')?.textContent || '未知课程';
const teacherName = targetRow.querySelector('td[aria-describedby*="jzgmc"]')?.textContent || '未知教师';
logSuccess(`🎯 切换到课程: ${courseName} (${teacherName})`);
// 等待页面加载完成后重新检测提交状态
setTimeout(() => {
logDebug('🔍 重新检测课程提交状态...');
displaySubmissionStatus();
}, 2000);
return true;
}
}
}
return true;
} catch (error) {
logError(`❌ 课程切换失败: ${error.message}`);
return false;
}
};
// 自动跳过已提交课程
const autoSkipSubmittedCourse = () => {
if (!getAutoSwitchSetting()) {
return false;
}
if (checkSubmissionStatus()) {
logWarning('🔄 检测到已提交课程,自动跳转到下一个...');
setTimeout(() => {
const switched = switchCourse('next');
if (!switched) {
logWarning('🚫 无法自动切换,可能已经是最后一个课程');
}
}, 2000);
return true;
}
return false;
};
// 检测是否已提交
const checkSubmissionStatus = () => {
// 检查方法1: 检查tjzt隐藏字段
const tjztElement = document.getElementById('tjzt');
if (tjztElement && tjztElement.value === '1') {
return true;
}
// 检查方法2: 检查是否存在单选按钮
const radioButtons = document.getElementsByClassName("radio-pjf");
if (radioButtons.length === 0) {
return true;
}
// 检查方法3: 检查评价项是否为纯文本显示
const evaluationRows = document.querySelectorAll('.tr-xspj td:nth-child(2)');
if (evaluationRows.length > 0) {
// 如果第一个评价项只包含文本(如"优秀")而不包含input元素
const firstRow = evaluationRows[0];
const hasInputs = firstRow.querySelector('input, select, textarea');
if (!hasInputs && firstRow.textContent.trim().length > 0) {
return true;
}
}
return false;
};
// 显示提交状态
const displaySubmissionStatus = () => {
const isSubmitted = checkSubmissionStatus();
// 清除之前的状态显示
const existingStatus = settingsArea.parentNode.querySelector('div[style*="rgba(76, 175, 80, 0.2)"]');
if (existingStatus) {
existingStatus.remove();
}
if (isSubmitted) {
// 创建已提交状态显示
const statusDiv = document.createElement('div');
statusDiv.id = 'submissionStatusDiv';
applyStyles(statusDiv, CSS_STYLES.status.submitted);
statusDiv.innerHTML = '✅ 评价已提交完成';
// 重置所有按钮状态
const buttons = btnContainer.querySelectorAll('button');
buttons.forEach(btn => {
btn.disabled = false;
btn.style.opacity = '1';
btn.style.cursor = 'pointer';
btn.title = '';
});
// 禁用评价按钮,但保留导航和一键优秀按钮
buttons.forEach(btn => {
// 不禁用调试、一键优秀、上一个、下一个、打赏按钮
if (btn.id !== 'btnDebug' && btn.id !== 'btnAuto' && btn.id !== 'btnPrev' && btn.id !== 'btnNext' && btn.id !== 'btnDonate') {
btn.disabled = true;
btn.style.opacity = '0.5';
btn.style.cursor = 'not-allowed';
btn.title = '评价已提交,无法再次操作';
}
});
// 重置设置选项
const radioInputs = settingsArea.querySelectorAll('input[type="radio"]');
radioInputs.forEach(radio => {
radio.disabled = false;
});
// 添加状态显示到设置区域后面
settingsArea.parentNode.insertBefore(statusDiv, btnContainer);
logWarning('🚫 检测到评价已提交,评价功能已禁用');
// 获取总分信息
const scoreElement = document.querySelector('.xspjSum');
if (scoreElement) {
const scoreText = scoreElement.textContent || scoreElement.innerText;
logSuccess('📊 ' + scoreText);
}
// 保持批量优秀按钮功能不变
// 检查是否需要自动跳过
setTimeout(() => {
autoSkipSubmittedCourse();
}, 1000);
return true;
} else {
// 重置所有按钮状态
const buttons = btnContainer.querySelectorAll('button');
buttons.forEach(btn => {
btn.disabled = false;
btn.style.opacity = '1';
btn.style.cursor = 'pointer';
btn.title = '';
});
// 重置设置选项
const radioInputs = settingsArea.querySelectorAll('input[type="radio"]');
radioInputs.forEach(radio => {
radio.disabled = false;
});
// 确保批量优秀按钮显示正确的文本
if (btnAuto) {
btnAuto.innerText = '⚡ 批量评价';
btnAuto.title = '批量评价所有未提交课程';
btnAuto.style.backgroundColor = CSS_STYLES.colors.batch; // 恢复原色
}
logSuccess('✅ 评价未提交,功能正常可用');
return false;
}
};
if (DEBUG_MODE) {
logDebug('🔧 调试模式已开启,调试按钮可用');
}
// 添加脚本信息提示
logSuccess(`🎯 正方教务评价脚本已加载 - 脚本猫版本 v${Version}`);
logSuccess('📝 使用说明:点击对应按钮进行评价选择');
logSuccess('🚀 批量评价:可在设置中选择评价等级,批量处理所有未提交课程');
// 调整面板初始高度以显示所有内容
const adjustPanelHeight = () => {
// 等待所有元素渲染完成
setTimeout(() => {
const panelContent = configPanel.scrollHeight;
const viewportHeight = window.innerHeight * 0.9; // 90vh
const defaultHeight = 650;
// 如果内容高度超过视口高度,使用最大高度并启用滚动
if (panelContent > viewportHeight) {
configPanel.style.height = viewportHeight + 'px';
configPanel.style.overflowY = 'auto';
} else if (panelContent > defaultHeight) {
configPanel.style.height = 'auto';
configPanel.style.overflowY = 'visible';
} else {
configPanel.style.height = defaultHeight + 'px';
configPanel.style.overflowY = 'visible';
}
}, 100);
};
// 检测提交状态
setTimeout(() => {
displaySubmissionStatus();
if (btnAuto) {
btnAuto.innerText = '⚡ 批量评价';
btnAuto.title = '批量评价所有未提交课程';
btnAuto.style.backgroundColor = '#17a2b8';
}
// 调整面板高度
adjustPanelHeight();
}, 500);
// 监听自动切换设置变化
setTimeout(() => {
const autoSwitchCheckbox = document.getElementById('autoSwitchCourse');
if (autoSwitchCheckbox) {
autoSwitchCheckbox.addEventListener('change', function() {
const isEnabled = this.checked;
logSuccess(`🔄 自动跳过已提交课程: ${isEnabled ? '已开启' : '已关闭'}`);
// 如果刚开启且当前课程已提交,立即跳转
if (isEnabled && checkSubmissionStatus()) {
logWarning('🔄 当前课程已提交,即将自动跳转...');
setTimeout(() => {
switchCourse('next');
}, 1000);
}
});
}
const autoNextCheckbox = document.getElementById('autoNextAfterEval');
if (autoNextCheckbox) {
autoNextCheckbox.addEventListener('change', function() {
const isEnabled = this.checked;
logSuccess(`⏭️ 评价后自动切换下一个: ${isEnabled ? '已开启' : '已关闭'}`);
if (isEnabled) {
logSuccess('💡 提示: 点击评价按钮后将自动切换到下一个课程');
} else {
logSuccess('💡 提示: 评价后需要手动切换课程');
}
});
}
const batchLevelSelect = document.getElementById('batchEvalLevel');
if (batchLevelSelect) {
batchLevelSelect.addEventListener('change', function() {
const evalLevel = getBatchEvalLevel();
logSuccess(`🎯 批量评价等级已设置为: ${evalLevel.name} (${evalLevel.score}分)`);
});
}
}, 1000);
// 绕过检测系统
const bypassDetection = () => {
// 1. 绕过脚本注入检测
if (window.$ && $.i18n && $.i18n.get) {
const originalGet = $.i18n.get;
$.i18n.get = function(key) {
// 拦截脚本注入警告
if (key === 'qwsyjbzr') {
logWarning('🛡️ 已拦截脚本注入检测');
return '';
}
return originalGet.call(this, key);
};
}
// 2. 模拟正常的设备检测
Object.defineProperty(navigator, 'userAgent', {
get: function() {
return 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36';
},
configurable: true
});
// 3. 绕过进度检测
window.inProgress = false;
// 4. 模拟鼠标事件
const simulateMouseEvents = () => {
document.addEventListener('click', function(e) {
if (e.target.id === 'btn_xspj_bc' || e.target.id === 'btn_xspj_tj') {
// 确保按钮有enter标记
if (!$(e.target).data("enter")) {
$(e.target).data("enter", "1");
}
}
}, true);
};
simulateMouseEvents();
logDebug('🛡️ 检测绕过系统已启用');
};
// 启用绕过系统
bypassDetection();
// 监听窗口大小变化,确保日志区域正确响应
window.addEventListener('resize', () => {
updateLogAreaLayout();
});
// 使用ResizeObserver监听面板大小变化
if (window.ResizeObserver) {
const resizeObserver = new ResizeObserver(entries => {
for (let entry of entries) {
if (entry.target === configPanel) {
updateLogAreaLayout();
}
}
});
resizeObserver.observe(configPanel);
}
// 监听页面内容变化,自动重新检测提交状态
const observePageChanges = () => {
const targetNode = document.getElementById('panel_content');
if (targetNode) {
const observer = new MutationObserver((mutations) => {
let shouldRecheck = false;
mutations.forEach((mutation) => {
if (mutation.type === 'childList' || mutation.type === 'subtree') {
// 检查是否有重要内容变化
if (mutation.target.querySelector('.xspjSum') ||
mutation.target.querySelector('#tjzt') ||
mutation.target.querySelector('.radio-pjf')) {
shouldRecheck = true;
}
}
});
if (shouldRecheck) {
logDebug('🔍 检测到页面内容变化,重新检测提交状态...');
setTimeout(() => {
displaySubmissionStatus();
}, 1000);
}
});
observer.observe(targetNode, {
childList: true,
subtree: true,
attributes: true,
attributeFilter: ['value']
});
logDebug('📡 页面变化监听器已启动');
}
};
// 启动页面变化监听
setTimeout(observePageChanges, 2000);
// 拦截AJAX检测请求
const interceptAjaxDetection = () => {
if (window.jQuery && jQuery.post) {
const originalPost = jQuery.post;
jQuery.post = function(url, data, callback, type) {
// 拦截数据异常检测
if (url && (url.includes('cxInsjjg') || url.includes('cxSftf') || url.includes('cxInmfzb') || url.includes('cxInmffz'))) {
logDebug('🛡️ 已拦截检测请求: ' + url);
// 返回正常结果
if (typeof callback === 'function') {
setTimeout(() => callback(0), 100);
}
return;
}
return originalPost.apply(this, arguments);
};
}
// 拦截设备检测函数
if (window.isPc2) {
window.isPc2 = function() {
return true; // 始终返回PC
};
}
if (window.detectMobileOrTablet) {
window.detectMobileOrTablet = function() {
return "desktop"; // 始终返回桌面
};
}
logDebug('🛡️ AJAX检测拦截已启用');
};
// 延迟启用AJAX拦截,确保jQuery已加载
setTimeout(interceptAjaxDetection, 1000);
// 监听系统弹窗和函数调用
const originalAlert = window.alert;
window.alert = function(message) {
logWarning('🚨 [系统弹窗] Alert: ' + message);
// 拦截特定的检测警告
if (message.includes('脚本注入') || message.includes('qwsyjbzr')) {
logWarning('🛡️ 已拦截脚本检测警告');
return;
}
return originalAlert.call(window, message);
};
const originalConfirm = window.confirm;
window.confirm = function(message) {
logWarning('❓ [系统弹窗] Confirm: ' + message);
const result = originalConfirm.call(window, message);
logSuccess('✅ [用户选择]: ' + (result ? '确定' : '取消'));
return result;
};
// 通用评价处理函数
const handleEvaluation = async (index, score, name) => {
if (checkSubmissionStatus()) {
logError('❌ 评价已提交,无法再次操作');
return;
}
await sleep(200);
const doc = document.getElementsByClassName("radio-pjf");
const input = document.getElementsByClassName("input-sm input-pjf");
if (doc.length === 0) {
logError('❌ 未找到评价选项,可能已提交');
return;
}
if (input.length > 0) {
input[0].value = score;
}
selectAllItems(doc, index);
logSuccess(`✅ 已选择${name}评价`);
await sleep(800);
const action = getAutoAction();
if (action === 'save') {
autoSave();
} else if (action === 'submit') {
autoSubmit();
}
if (getAutoNextAfterEvalSetting()) {
logSuccess('🔄 评价完成,准备自动切换到下一个课程...');
setTimeout(() => {
const switched = switchCourse('next');
if (!switched) {
logWarning('❌ 无法自动切换,可能已经是最后一个课程');
}
}, 2000);
}
};
// 评价按钮事件处理
btna.addEventListener('click', () => handleEvaluation(0, "100", "优秀"));
btnb.addEventListener('click', () => handleEvaluation(1, "85", "良好"));
btnc.addEventListener('click', () => handleEvaluation(2, "75", "合格"));
btnd.addEventListener('click', () => handleEvaluation(3, "50", "不合格"));
// 批量评价所有未提交课程的功能
const batchEvaluateAllCourses = async () => {
logSuccess('🚀 开始批量评价所有未提交课程...');
const grid = $('#tempGrid');
if (grid.length === 0) {
logError('❌ 未找到课程列表');
return false;
}
const allRowIds = grid.jqGrid('getDataIDs');
const unsubmittedCourses = [];
// 查找所有未提交的课程
for (let rowId of allRowIds) {
const rowData = grid.jqGrid('getRowData', rowId);
if (rowData.tjztmc !== '提交') {
unsubmittedCourses.push({
id: rowId,
name: rowData.jxbmc,
teacher: rowData.jzgmc,
status: rowData.tjztmc
});
}
}
if (unsubmittedCourses.length === 0) {
logWarning('🎉 所有课程都已提交完成!');
return true;
}
logSuccess(`📋 找到 ${unsubmittedCourses.length} 个未提交课程,开始批量评价...`);
let successCount = 0;
let failCount = 0;
for (let i = 0; i < unsubmittedCourses.length; i++) {
const course = unsubmittedCourses[i];
logSuccess(`📚 [${i + 1}/${unsubmittedCourses.length}] 正在评价: ${course.name} (${course.teacher})`);
try {
// 切换到目标课程
grid.jqGrid('setSelection', course.id);
await sleep(500);
// 触发行点击事件加载课程内容
const row = $(`#${course.id}`);
if (row.length > 0) {
row.trigger('click');
await sleep(2000); // 等待页面加载
}
// 检查是否已经提交(可能在加载过程中状态发生变化)
if (checkSubmissionStatus()) {
logWarning(`⚠️ 课程 ${course.name} 已提交,跳过`);
continue;
}
// 执行评价
const doc = document.getElementsByClassName("radio-pjf");
const input = document.getElementsByClassName("input-sm input-pjf");
if (doc.length === 0) {
logError(`❌ 课程 ${course.name} 未找到评价选项`);
failCount++;
continue;
}
const evalLevel = getBatchEvalLevel();
if (input.length > 0) {
input[0].value = evalLevel.score;
}
selectAllItems(doc, evalLevel.index);
logSuccess(`✅ 已完成课程 ${course.name} 的${evalLevel.name}评价`);
await sleep(800);
const action = getAutoAction();
if (action === 'save') {
autoSave();
await sleep(1500);
} else if (action === 'submit') {
autoSubmit();
await sleep(2500);
} else {
autoSave();
await sleep(1500);
}
successCount++;
logSuccess(`🎯 课程 ${course.name} 评价完成 (${successCount}/${unsubmittedCourses.length})`);
await sleep(1000);
} catch (error) {
logError(`❌ 评价课程 ${course.name} 时出错: ${error.message}`);
failCount++;
}
}
// 显示批量评价结果
logSuccess('🏁 批量评价完成!');
logSuccess(`📊 成功: ${successCount} 个课程`);
if (failCount > 0) {
logWarning(`⚠️ 失败: ${failCount} 个课程`);
}
logSuccess('🔄 正在刷新页面状态...');
// 刷新页面状态
setTimeout(() => {
location.reload();
}, 2000);
return true;
};
// 一键批量评价功能
btnAuto.addEventListener('click', async function () {
const grid = $('#tempGrid');
if (grid.length === 0) {
logError('❌ 未找到课程列表');
return;
}
const allRowIds = grid.jqGrid('getDataIDs');
const unsubmittedCount = allRowIds.filter(rowId => {
const rowData = grid.jqGrid('getRowData', rowId);
return rowData.tjztmc !== '提交';
}).length;
if (unsubmittedCount === 0) {
logSuccess('🎉 所有课程都已提交完成!');
logSuccess('✅ 无需进行批量评价操作');
return;
}
const isCurrentSubmitted = checkSubmissionStatus();
if (isCurrentSubmitted) {
logSuccess(`💡 当前课程已提交,将批量评价其他 ${unsubmittedCount} 个未提交课程`);
}
const actionText = getAutoAction() === 'submit' ? '提交' : '保存';
const evalLevel = getBatchEvalLevel();
if (confirm(`确定要批量评价所有未提交的课程吗?\n\n📊 未提交课程数量: ${unsubmittedCount} 个\n🎯 评价等级: ${evalLevel.name} (${evalLevel.score}分)\n⚙️ 操作模式: 自动${actionText}\n⏱️ 预计耗时: ${Math.ceil(unsubmittedCount * 6)} 秒\n\n⚠️ 注意: 此操作将自动处理所有未提交课程,请确认后继续。`)) {
this.disabled = true;
this.style.opacity = '0.5';
this.innerText = '🔄 批量评价中...';
try {
await batchEvaluateAllCourses();
} catch (error) {
logError(`❌ 批量评价过程中出错: ${error.message}`);
} finally {
setTimeout(() => {
this.disabled = false;
this.style.opacity = '1';
this.innerText = '⚡ 批量评价';
}, 3000);
}
}
});
// 通用课程切换处理函数
const handleCourseSwitch = function(direction) {
this.disabled = true;
this.style.opacity = '0.5';
const switched = switchCourse(direction);
if (!switched) {
logWarning('❌ 切换失败,请手动选择课程');
}
setTimeout(() => {
this.disabled = false;
this.style.opacity = '1';
}, 3000);
};
// 课程切换按钮事件
btnPrev.addEventListener('click', function() { handleCourseSwitch.call(this, 'prev'); });
btnNext.addEventListener('click', function() { handleCourseSwitch.call(this, 'next'); });
// 打赏按钮事件处理
btnDonate.addEventListener('click', function() {
window.open('https://dg.wdvip.top/dashang', '_blank');
logSuccess('💰 感谢您的支持!已打开打赏页面');
});
// 根据调试模式添加调试按钮
if (DEBUG_MODE) {
const btnDebug = createButton('btnDebug', '🔧 调试', CSS_STYLES.colors.debug);
addButton(btnContainer, btnDebug);
}
// 调试按钮事件处理(仅在调试模式下)
if (DEBUG_MODE) {
const btnDebug = btnContainer.querySelector('#btnDebug');
if (btnDebug) {
btnDebug.addEventListener('click', function() {
const doc = document.getElementsByClassName("radio-pjf");
const requiredItems = document.querySelectorAll('.tr-xspj[data-sfbt="1"]');
const isSubmitted = checkSubmissionStatus();
const tjztElement = document.getElementById('tjzt');
logDebug('=== 调试信息 ===');
logDebug(`提交状态: ${isSubmitted ? '已提交' : '未提交'}`);
logDebug(`tjzt值: ${tjztElement ? tjztElement.value : '未找到'}`);
logDebug(`总共找到 ${doc.length} 个单选按钮`);
logDebug(`总共找到 ${requiredItems.length} 个必填评价项`);
logDebug(`预期应该有 ${requiredItems.length * 4} 个单选按钮`);
logDebug(`当前设置: ${getAutoAction()}`);
logDebug(`自动跳过已提交: ${getAutoSwitchSetting() ? '开启' : '关闭'}`);
logDebug(`评价后自动切换: ${getAutoNextAfterEvalSetting() ? '开启' : '关闭'}`);
const evalLevel = getBatchEvalLevel();
logDebug(`批量评价等级: ${evalLevel.name} (${evalLevel.score}分)`);
logDebug(`批量评价按钮状态: ${btnAuto ? btnAuto.innerText : '未找到'}`);
const scoreElement = document.querySelector('.xspjSum');
if (scoreElement) {
logDebug(`评价总分: ${scoreElement.textContent || scoreElement.innerText}`);
}
const buttons = btnContainer.querySelectorAll('button');
const enabledButtons = Array.from(buttons).filter(btn => !btn.disabled).map(btn => btn.innerText);
logDebug(`可用按钮: ${enabledButtons.join(', ')}`);
const grid = $('#tempGrid');
if (grid.length > 0) {
const currentRowId = grid.jqGrid('getGridParam', 'selrow');
const allRowIds = grid.jqGrid('getDataIDs');
logDebug(`jqGrid - 当前选中: ${currentRowId}, 总课程数: ${allRowIds.length}`);
if (currentRowId) {
const currentRowData = grid.jqGrid('getRowData', currentRowId);
logDebug(`当前课程: ${currentRowData.jxbmc} - ${currentRowData.jzgmc} (${currentRowData.tjztmc})`);
}
}
const courseRows = document.querySelectorAll('#tempGrid tr[role="row"]');
logDebug(`找到 ${courseRows.length - 1} 个课程行`);
if (grid.length > 0) {
const allRowIds = grid.jqGrid('getDataIDs');
const unsubmittedCount = allRowIds.filter(rowId => {
const rowData = grid.jqGrid('getRowData', rowId);
return rowData.tjztmc !== '提交';
}).length;
const submittedCount = allRowIds.length - unsubmittedCount;
logDebug(`课程状态统计: 已提交 ${submittedCount} 个, 未提交 ${unsubmittedCount} 个`);
}
if (doc.length > 0) {
logDebug('--- 单选按钮状态 ---');
for (let i = 0; i < Math.min(10, doc.length); i++) {
const btn = doc[i];
const label = btn.parentElement.textContent.trim();
logDebug(`按钮${i}: ${label} - 选中: ${btn.checked}`);
}
} else {
logDebug('--- 评价项状态 (已提交) ---');
const evaluationRows = document.querySelectorAll('.tr-xspj');
for (let i = 0; i < Math.min(5, evaluationRows.length); i++) {
const row = evaluationRows[i];
const title = row.querySelector('td:first-child')?.textContent?.trim();
const value = row.querySelector('td:nth-child(2)')?.textContent?.trim();
if (title && value) {
logDebug(`${title.replace('*', '').substring(0, 20)}... = ${value}`);
}
}
}
});
}
}
setTimeout(() => {
const notification = document.createElement('div');
applyStyles(notification, CSS_STYLES.notification.replace('top: 20px', 'top: 60px').replace('linear-gradient(135deg, #667eea 0%, #764ba2 100%)', '#28a745'));
notification.innerText = '🎯 评价脚本已就绪!';
document.body.appendChild(notification);
setTimeout(() => {
notification.remove();
}, 3000);
const doc = document.getElementsByClassName("radio-pjf");
const requiredItems = document.querySelectorAll('.tr-xspj[data-sfbt="1"]');
logSuccess('🎯 脚本加载完成');
logDebug(`📊 检测到 ${requiredItems.length} 个评价项,${doc.length} 个选项按钮`);
}, 1000);
})();