superlishunqin 68b99755ec ALL
2024-11-14 15:46:37 +08:00

276 lines
11 KiB
JavaScript

document.querySelector('.file-input-button').addEventListener('click', function() {
document.getElementById('file').click();
});
document.getElementById('file').addEventListener('change', function(e) {
const fileName = e.target.files[0] ? e.target.files[0].name : '未选择文件';
document.getElementById('file-name').textContent = fileName;
});
document.getElementById('upload-form').addEventListener('submit', async (e) => {
e.preventDefault();
handleSubmission();
});
document.getElementById('verify-submit-button').addEventListener('click', async () => {
await validateCodeAndSubmit();
});
async function handleSubmission() {
const assignment = document.getElementById('assignment').value;
const file = document.getElementById('file').files[0];
const statusDiv = document.getElementById('status');
if (!assignment || !file) {
alert('请选择作业,并选择一个文件。');
return;
}
setLoadingState(true);
try {
const recordResponse = await fetch('/record-submission', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ assignment, filename: file.name })
});
if (recordResponse.status === 401) {
setLoadingState(false);
document.getElementById('verification-container').style.display = 'block';
const emailResponse = await fetch('/generate-code', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ assignment })
});
if (emailResponse.ok) {
alert('作业已提交过,请输入验证码提交');
} else {
const errorData = await emailResponse.json();
throw new Error(`发送验证码失败: ${errorData.error}`);
}
} else if (!recordResponse.ok) {
const errorRecordData = await recordResponse.json();
throw new Error(`记录提交信息失败: ${errorRecordData.error}`);
} else {
const data = await recordResponse.json();
await uploadFile(data.upload_url, file, statusDiv);
alert('文件上传并记录成功');
}
} catch (error) {
console.error('错误:', error);
statusDiv.textContent = `错误: ${error.message}`;
alert('发生错误: ' + error.message);
} finally {
setLoadingState(false);
}
}
async function validateCodeAndSubmit() {
const assignment = document.getElementById('assignment').value;
const file = document.getElementById('file').files[0];
const code = document.getElementById('verification-code').value;
const statusDiv = document.getElementById('status');
setLoadingState(true, true);
try {
const validateResponse = await fetch('/validate-code', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ assignment, code })
});
if (validateResponse.ok) {
const { upload_url } = await validateResponse.json();
await uploadFile(upload_url, file, statusDiv);
alert('文件上传并记录成功');
document.getElementById('verification-container').style.display = 'none';
} else {
const errorData = await validateResponse.json();
throw new Error(`验证码错误: ${errorData.error}`);
}
} catch (error) {
console.error('错误:', error);
statusDiv.textContent = `错误: ${error.message}`;
alert('发生错误: ' + error.message);
} finally {
setLoadingState(false, true);
}
}
async function uploadFile(upload_url, file, statusDiv) {
const progressContainer = document.getElementById('progress-container');
const progressBar = document.getElementById('progress-bar');
const progressPercentage = document.getElementById('progress-percentage');
const uploadSpeed = document.getElementById('upload-speed');
const uploadSize = document.getElementById('upload-size');
const uploadTime = document.getElementById('upload-time');
statusDiv.textContent = '正在上传文件...';
const totalSize = file.size;
let uploadedSize = 0;
let startTime = Date.now();
progressContainer.style.display = 'block';
const updateProgress = (additionalProgress = 0) => {
uploadedSize += additionalProgress;
const percentComplete = (uploadedSize / totalSize) * 100;
const elapsedTime = (Date.now() - startTime) / 1000;
const speed = uploadedSize / elapsedTime;
const remainingSize = totalSize - uploadedSize;
const estimatedRemainingTime = speed > 0 ? remainingSize / speed : 0;
progressBar.style.width = percentComplete + '%';
progressPercentage.textContent = percentComplete.toFixed(2) + '%';
uploadSpeed.textContent = `速度: ${formatSize(speed)}/s`;
uploadSize.textContent = `${formatSize(uploadedSize)} / ${formatSize(totalSize)}`;
uploadTime.textContent = `剩余时间: ${formatTime(estimatedRemainingTime)}`;
};
const progressInterval = setInterval(() => {
if (uploadedSize < totalSize) {
updateProgress(totalSize / 100);
}
}, 200);
const uploadResponse = await fetch(upload_url, {
method: 'PUT',
body: file,
headers: {
'Content-Type': 'application/octet-stream'
}
});
clearInterval(progressInterval);
if (!uploadResponse.ok) {
throw new Error(`上传失败: ${uploadResponse.statusText}`);
}
updateProgress(totalSize - uploadedSize);
}
function setLoadingState(isLoading, isVerify = false) {
const submitButton = document.querySelector('button[type="submit"]');
const verifyButton = document.getElementById('verify-submit-button');
const container = isVerify ? verifyButton.parentElement : submitButton.parentElement;
const loadingIndicator = container.querySelector('.loading-indicator') || document.createElement('div');
loadingIndicator.className = 'loading-indicator';
loadingIndicator.innerHTML = '<span>加载中...</span>';
loadingIndicator.style.display = isLoading ? 'block' : 'none';
if (!loadingIndicator.parentElement) {
container.appendChild(loadingIndicator);
}
if (isVerify) {
verifyButton.disabled = isLoading;
} else {
submitButton.disabled = isLoading;
}
}
function formatSize(bytes) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
function formatTime(seconds) {
if (isNaN(seconds) || !isFinite(seconds)) {
return '计算中';
}
if (seconds < 60) return Math.round(seconds) + ' 秒';
const minutes = Math.floor(seconds / 60);
const remainingSeconds = Math.round(seconds % 60);
return `${minutes}${remainingSeconds}`;
}
function previewTable(apiUrl, title) {
fetch(apiUrl)
.then(response => response.json())
.then(data => {
const newWindow = window.open('', '_blank');
newWindow.document.write('<html><head><title>' + title + '</title><style>');
newWindow.document.write('table { width: 100%; border-collapse: collapse; margin-top: 10px; }');
newWindow.document.write('th, td { border: 1px solid #ddd; padding: 8px; text-align: left; word-wrap: break-word; }');
newWindow.document.write('th { background-color: #f2f2f2; }');
newWindow.document.write('body { font-family: Arial, sans-serif; padding: 20px; }');
newWindow.document.write('</style></head><body>');
newWindow.document.write('<h2>' + title + '</h2>');
const table = newWindow.document.createElement('table');
if (data.length > 0) {
let headers;
if (title === '预览统计表格') {
headers = ['时间', '提交的文件', '姓名', '学号', '作业'];
} else {
headers = ['学号', '姓名', '作业', '提交情况', '提交的文件'];
}
const thead = newWindow.document.createElement('thead');
const tr = newWindow.document.createElement('tr');
headers.forEach((header, index) => {
const th = newWindow.document.createElement('th');
th.textContent = header;
// 设置列宽
if (title === '预览统计表格') {
if (index === 0) th.style.width = '20%'; // 时间
else if (index === 1) th.style.width = '30%'; // 提交的文件
else if (index === 2) th.style.width = '15%'; // 姓名
else if (index === 3) th.style.width = '15%'; // 学号
else if (index === 4) th.style.width = '20%'; // 作业
} else {
if (index === 0) th.style.width = '15%'; // 学号
else if (index === 1) th.style.width = '15%'; // 姓名
else if (index === 2) th.style.width = '20%'; // 作业
else if (index === 3) th.style.width = '15%'; // 提交情况
else if (index === 4) th.style.width = '35%'; // 提交的文件
}
tr.appendChild(th);
});
thead.appendChild(tr);
table.appendChild(thead);
}
const tbody = newWindow.document.createElement('tbody');
data.forEach(row => {
const tr = newWindow.document.createElement('tr');
if (title === '预览统计表格') {
['时间', '提交的文件', '姓名', '学号', '作业'].forEach(key => {
const td = newWindow.document.createElement('td');
td.textContent = row[key] || '';
tr.appendChild(td);
});
} else {
['学号', '姓名', '作业', '提交情况', '提交的文件'].forEach(key => {
const td = newWindow.document.createElement('td');
td.textContent = row[key] || '';
tr.appendChild(td);
});
}
tbody.appendChild(tr);
});
table.appendChild(tbody);
newWindow.document.body.appendChild(table);
newWindow.document.write('</body></html>');
newWindow.document.close();
})
.catch(error => console.error('Error fetching data:', error));
}