- Complete survey management system with web interface - Question generation tools and prompts - Report generation and analysis capabilities - Docker configuration for deployment - Database initialization scripts 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
777 lines
26 KiB
JavaScript
777 lines
26 KiB
JavaScript
// Enhanced Report list manager - 管理测评报告列表
|
||
class ReportListManager {
|
||
constructor() {
|
||
this.reports = [];
|
||
this.allReports = [];
|
||
this.currentPage = 1;
|
||
this.pageSize = 10;
|
||
this.totalPages = 1;
|
||
this.totalRecords = 0;
|
||
this.init();
|
||
}
|
||
|
||
async init() {
|
||
try {
|
||
await this.fetchReports();
|
||
this.render();
|
||
} catch (error) {
|
||
console.error('初始化失败:', error);
|
||
this.showError(`数据加载失败: ${error.message}`);
|
||
}
|
||
}
|
||
|
||
async fetchReports() {
|
||
try {
|
||
// 显示加载状态
|
||
document.getElementById('loading').style.display = 'block';
|
||
|
||
// 调用本地API获取报告数据
|
||
const response = await fetch(`/api/reports?page=${this.currentPage}&pageSize=${this.pageSize}`, {
|
||
method: 'GET',
|
||
headers: {
|
||
'content-type': 'application/json'
|
||
}
|
||
});
|
||
|
||
if (!response.ok) {
|
||
throw new Error(`API请求失败: ${response.status}`);
|
||
}
|
||
|
||
const data = await response.json();
|
||
|
||
this.reports = data.reports || [];
|
||
this.totalRecords = data.total || 0;
|
||
this.totalPages = data.total_pages || 1;
|
||
this.currentPage = data.page || 1;
|
||
|
||
// 隐藏加载状态
|
||
document.getElementById('loading').style.display = 'none';
|
||
|
||
// 如果没有数据,显示空状态
|
||
if (this.reports.length === 0) {
|
||
document.getElementById('empty').style.display = 'block';
|
||
document.getElementById('table-content').style.display = 'none';
|
||
} else {
|
||
document.getElementById('empty').style.display = 'none';
|
||
document.getElementById('table-content').style.display = 'block';
|
||
}
|
||
|
||
} catch (error) {
|
||
console.error('获取报告失败:', error);
|
||
throw error;
|
||
}
|
||
}
|
||
|
||
render() {
|
||
this.renderTable();
|
||
this.renderPagination();
|
||
}
|
||
|
||
renderTable() {
|
||
const tbody = document.getElementById('report-list');
|
||
tbody.innerHTML = '';
|
||
|
||
this.reports.forEach((report, index) => {
|
||
const row = document.createElement('tr');
|
||
|
||
// 格式化日期
|
||
// 解析时间戳并转换为东八区时间
|
||
const dateObj = new Date(report.generated_at);
|
||
// 加8小时转换为东八区时间
|
||
const east8Time = new Date(dateObj.getTime() + 8 * 60 * 60 * 1000);
|
||
|
||
// 格式化为 YYYY-MM-DD HH:MM
|
||
const year = east8Time.getFullYear();
|
||
const month = String(east8Time.getMonth() + 1).padStart(2, '0');
|
||
const day = String(east8Time.getDate()).padStart(2, '0');
|
||
const hours = String(east8Time.getHours()).padStart(2, '0');
|
||
const minutes = String(east8Time.getMinutes()).padStart(2, '0');
|
||
|
||
const date = `${year}-${month}-${day} ${hours}:${minutes}`;
|
||
|
||
row.innerHTML = `
|
||
<td class="name-cell">${report.name}</td>
|
||
<td class="time-cell">${date}</td>
|
||
<td class="score-cell">${report.total_score}分</td>
|
||
<td class="grade-cell">${report.grade}</td>
|
||
<td class="school-cell">${report.school}</td>
|
||
<td class="action-cell">
|
||
<a href="/public/report.html?id=${report.id}" class="view-btn">查看报告</a>
|
||
</td>
|
||
`;
|
||
|
||
tbody.appendChild(row);
|
||
});
|
||
}
|
||
|
||
renderPagination() {
|
||
const pagination = document.getElementById('pagination-left');
|
||
const pageInfo = document.querySelector('.page-info');
|
||
const controls = document.querySelector('.pagination-controls');
|
||
|
||
// 更新页面信息
|
||
pageInfo.textContent = `第 ${this.currentPage} 页,共 ${this.totalPages} 页`;
|
||
|
||
// 更新下拉列表
|
||
const pageSizeSelect = document.querySelector('.page-size-select');
|
||
if (pageSizeSelect) {
|
||
pageSizeSelect.value = this.pageSize;
|
||
}
|
||
|
||
// 生成页码按钮
|
||
controls.innerHTML = '';
|
||
|
||
// 上一页按钮
|
||
const prevBtn = document.createElement('button');
|
||
prevBtn.className = 'pagination-btn';
|
||
prevBtn.textContent = '上一页';
|
||
prevBtn.disabled = this.currentPage === 1;
|
||
prevBtn.onclick = () => this.goToPage(this.currentPage - 1);
|
||
controls.appendChild(prevBtn);
|
||
|
||
// 页码按钮
|
||
const startPage = Math.max(1, this.currentPage - 2);
|
||
const endPage = Math.min(this.totalPages, this.currentPage + 2);
|
||
|
||
if (startPage > 1) {
|
||
this.addPageButton(controls, 1);
|
||
if (startPage > 2) {
|
||
const ellipsis = document.createElement('span');
|
||
ellipsis.className = 'pagination-ellipsis';
|
||
ellipsis.textContent = '...';
|
||
controls.appendChild(ellipsis);
|
||
}
|
||
}
|
||
|
||
for (let i = startPage; i <= endPage; i++) {
|
||
this.addPageButton(controls, i);
|
||
}
|
||
|
||
if (endPage < this.totalPages) {
|
||
if (endPage < this.totalPages - 1) {
|
||
const ellipsis = document.createElement('span');
|
||
ellipsis.className = 'pagination-ellipsis';
|
||
ellipsis.textContent = '...';
|
||
controls.appendChild(ellipsis);
|
||
}
|
||
this.addPageButton(controls, this.totalPages);
|
||
}
|
||
|
||
// 下一页按钮
|
||
const nextBtn = document.createElement('button');
|
||
nextBtn.className = 'pagination-btn';
|
||
nextBtn.textContent = '下一页';
|
||
nextBtn.disabled = this.currentPage === this.totalPages;
|
||
nextBtn.onclick = () => this.goToPage(this.currentPage + 1);
|
||
controls.appendChild(nextBtn);
|
||
}
|
||
|
||
addPageButton(container, pageNum) {
|
||
const btn = document.createElement('button');
|
||
btn.className = `pagination-btn ${pageNum === this.currentPage ? 'active' : ''}`;
|
||
btn.textContent = pageNum;
|
||
btn.onclick = () => this.goToPage(pageNum);
|
||
container.appendChild(btn);
|
||
}
|
||
|
||
async goToPage(page) {
|
||
if (page < 1 || page > this.totalPages || page === this.currentPage) {
|
||
return;
|
||
}
|
||
|
||
this.currentPage = page;
|
||
await this.fetchReports();
|
||
this.render();
|
||
}
|
||
|
||
async changePageSize(pageSize) {
|
||
if (pageSize === this.pageSize) {
|
||
return;
|
||
}
|
||
|
||
this.pageSize = pageSize;
|
||
this.currentPage = 1;
|
||
await this.fetchReports();
|
||
this.render();
|
||
}
|
||
|
||
showError(message) {
|
||
const errorDiv = document.getElementById('error');
|
||
errorDiv.textContent = message;
|
||
errorDiv.style.display = 'block';
|
||
|
||
setTimeout(() => {
|
||
errorDiv.style.display = 'none';
|
||
}, 5000);
|
||
}
|
||
}
|
||
try {
|
||
const reportContent = JSON.parse(reportData.report);
|
||
// 将解析后的报告内容与原始数据合并
|
||
return { ...reportData, ...reportContent };
|
||
} catch (parseError) {
|
||
console.warn('解析report字段失败:', parseError);
|
||
return reportData;
|
||
}
|
||
}
|
||
|
||
return reportData;
|
||
});
|
||
} else if (Array.isArray(data)) {
|
||
// 如果是数组,直接使用
|
||
allReports = data;
|
||
} else if (data.reports && Array.isArray(data.reports)) {
|
||
// 如果有reports字段且是数组,使用reports
|
||
allReports = data.reports;
|
||
} else if (data.studentInfo) {
|
||
// 如果是单个报告对象,包装成数组
|
||
allReports = [data];
|
||
}
|
||
|
||
// 存储所有数据
|
||
this.allReports = allReports;
|
||
this.totalRecords = allReports.length;
|
||
this.totalPages = Math.ceil(this.totalRecords / this.pageSize);
|
||
|
||
// 应用分页
|
||
this.applyPagination();
|
||
|
||
// 隐藏加载状态
|
||
document.getElementById('loading').style.display = 'none';
|
||
|
||
} catch (error) {
|
||
document.getElementById('loading').style.display = 'none';
|
||
throw error;
|
||
}
|
||
}
|
||
|
||
applyPagination() {
|
||
// 计算当前页的数据
|
||
const startIndex = (this.currentPage - 1) * this.pageSize;
|
||
const endIndex = startIndex + this.pageSize;
|
||
this.reports = this.allReports.slice(startIndex, endIndex);
|
||
}
|
||
|
||
render() {
|
||
const tableContent = document.getElementById('table-content');
|
||
const reportList = document.getElementById('report-list');
|
||
const emptyState = document.getElementById('empty');
|
||
|
||
if (this.reports.length === 0) {
|
||
tableContent.style.display = 'none';
|
||
emptyState.style.display = 'block';
|
||
return;
|
||
}
|
||
|
||
// 生成表格行
|
||
const rows = this.reports.map(report => this.createReportRow(report)).join('');
|
||
reportList.innerHTML = rows;
|
||
|
||
// 添加分页控件
|
||
this.renderPagination();
|
||
|
||
// 显示表格
|
||
tableContent.style.display = 'block';
|
||
emptyState.style.display = 'none';
|
||
}
|
||
|
||
createReportRow(report) {
|
||
// 从数据中提取学生信息
|
||
let name = this.extractNameFromAnswer(report);
|
||
let testDate = this.formatDate(report.create_at);
|
||
let subject = this.extractSubjectFromReport(report);
|
||
|
||
// 使用原始id作为报告ID
|
||
const reportId = report.id || this.generateReportId(report);
|
||
|
||
return `
|
||
<tr>
|
||
<td class="name-cell">${this.escapeHtml(name)}</td>
|
||
<td class="time-cell">${this.escapeHtml(testDate)}</td>
|
||
|
||
<td class="action-cell">
|
||
<a href="report.html?id=${reportId}" class="view-btn">查看报告</a>
|
||
</td>
|
||
</tr>
|
||
`;
|
||
}
|
||
|
||
generateReportId(report) {
|
||
// 如果有明确的ID,直接使用
|
||
if (report.id) {
|
||
return report.id;
|
||
}
|
||
|
||
// 否则基于学生信息生成一个简单的ID
|
||
const name = this.extractNameFromAnswer(report);
|
||
const testDate = report.create_at || '';
|
||
const subject = this.extractSubjectFromReport(report);
|
||
|
||
// 简单的哈希函数生成ID
|
||
const str = `${name}-${testDate}-${subject}`;
|
||
let hash = 0;
|
||
for (let i = 0; i < str.length; i++) {
|
||
const char = str.charCodeAt(i);
|
||
hash = ((hash << 5) - hash) + char;
|
||
hash = hash & hash; // 转换为32位整数
|
||
}
|
||
return Math.abs(hash).toString();
|
||
}
|
||
|
||
extractNameFromAnswer(report) {
|
||
// 尝试从answer字段中提取姓名
|
||
try {
|
||
if (report.answer) {
|
||
const answerData = JSON.parse(report.answer);
|
||
|
||
// 遍历答案数据,查找包含姓名的题目
|
||
for (const [questionId, answer] of Object.entries(answerData)) {
|
||
// 假设姓名题目的答案格式为 {"xxx": "姓名"} 或 {"xxx": "姓名文本"}
|
||
if (typeof answer === 'object') {
|
||
for (const [optionId, value] of Object.entries(answer)) {
|
||
// 如果答案看起来像是姓名(2-4个中文字符)
|
||
if (typeof value === 'string' && /^[\u4e00-\u9fa5]{2,4}$/.test(value)) {
|
||
return value;
|
||
}
|
||
}
|
||
} else if (typeof answer === 'string' && /^[\u4e00-\u9fa5]{2,4}$/.test(answer)) {
|
||
// 如果答案直接是姓名字符串
|
||
return answer;
|
||
}
|
||
}
|
||
}
|
||
} catch (error) {
|
||
console.warn('解析answer字段失败:', error);
|
||
}
|
||
|
||
// 如果从answer中找不到,尝试从report字段中获取
|
||
if (report.report) {
|
||
try {
|
||
const reportData = typeof report.report === 'string' ? JSON.parse(report.report) : report.report;
|
||
if (reportData.studentInfo && reportData.studentInfo.name) {
|
||
return reportData.studentInfo.name;
|
||
}
|
||
} catch (error) {
|
||
console.warn('解析report字段失败:', error);
|
||
}
|
||
}
|
||
|
||
return '未知';
|
||
}
|
||
|
||
extractSubjectFromReport(report) {
|
||
// 尝试从report字段中提取科目
|
||
if (report.report) {
|
||
try {
|
||
const reportData = typeof report.report === 'string' ? JSON.parse(report.report) : report.report;
|
||
if (reportData.studentInfo && reportData.studentInfo.subject) {
|
||
return reportData.studentInfo.subject;
|
||
}
|
||
} catch (error) {
|
||
console.warn('解析report字段失败:', error);
|
||
}
|
||
}
|
||
|
||
return '未知科目';
|
||
}
|
||
|
||
formatDate(dateStr) {
|
||
// 处理日期格式
|
||
if (!dateStr) {
|
||
return '未知时间';
|
||
}
|
||
|
||
// 如果已经是中文格式(如:2025年10月5日),直接返回
|
||
if (dateStr.includes('年')) {
|
||
return dateStr;
|
||
}
|
||
|
||
// 处理标准日期格式(如:2025-10-05 17:04:26)
|
||
try {
|
||
const date = new Date(dateStr);
|
||
if (isNaN(date.getTime())) {
|
||
return dateStr; // 如果无法解析,返回原始字符串
|
||
}
|
||
|
||
const year = date.getFullYear();
|
||
const month = date.getMonth() + 1;
|
||
const day = date.getDate();
|
||
|
||
return `${year}年${month}月${day}日`;
|
||
} catch (error) {
|
||
return dateStr; // 如果出错,返回原始字符串
|
||
}
|
||
}
|
||
|
||
escapeHtml(text) {
|
||
const div = document.createElement('div');
|
||
div.textContent = text;
|
||
return div.innerHTML;
|
||
}
|
||
|
||
renderPagination() {
|
||
const paginationContainer = document.getElementById('pagination');
|
||
|
||
if (!paginationContainer) {
|
||
// 如果分页容器不存在,创建一个
|
||
const tableContainer = document.querySelector('.table-container');
|
||
const paginationDiv = document.createElement('div');
|
||
paginationDiv.id = 'pagination';
|
||
paginationDiv.className = 'pagination-container';
|
||
tableContainer.appendChild(paginationDiv);
|
||
}
|
||
|
||
const paginationEl = document.getElementById('pagination');
|
||
|
||
if (this.totalPages <= 1) {
|
||
paginationEl.style.display = 'none';
|
||
return;
|
||
}
|
||
|
||
paginationEl.style.display = 'flex';
|
||
paginationEl.innerHTML = this.createPaginationHTML();
|
||
}
|
||
|
||
createPaginationHTML() {
|
||
let html = '<div class="pagination-left">';
|
||
html += '<div class="pagination-info">';
|
||
html += `<span>共 ${this.totalRecords} 条记录</span>`;
|
||
html += '</div>';
|
||
|
||
html += '<div class="page-size-selector">';
|
||
html += '<label for="page-size">每页显示:</label>';
|
||
html += `<select id="page-size" class="page-size-select" onchange="reportListManager.changePageSize(this.value)">`;
|
||
|
||
const pageSizes = [5, 10, 20, 50];
|
||
pageSizes.forEach(size => {
|
||
html += `<option value="${size}" ${size === this.pageSize ? 'selected' : ''}>${size}条</option>`;
|
||
});
|
||
|
||
html += '</select>';
|
||
html += '</div>';
|
||
html += '</div>';
|
||
|
||
html += '<div class="pagination-controls">';
|
||
|
||
// 上一页按钮
|
||
html += `<button class="pagination-btn ${this.currentPage === 1 ? 'disabled' : ''}"
|
||
onclick="reportListManager.goToPage(${this.currentPage - 1})"
|
||
${this.currentPage === 1 ? 'disabled' : ''}>上一页</button>`;
|
||
|
||
// 页码按钮
|
||
const startPage = Math.max(1, this.currentPage - 2);
|
||
const endPage = Math.min(this.totalPages, this.currentPage + 2);
|
||
|
||
if (startPage > 1) {
|
||
html += `<button class="pagination-btn" onclick="reportListManager.goToPage(1)">1</button>`;
|
||
if (startPage > 2) {
|
||
html += '<span class="pagination-ellipsis">...</span>';
|
||
}
|
||
}
|
||
|
||
for (let i = startPage; i <= endPage; i++) {
|
||
html += `<button class="pagination-btn ${i === this.currentPage ? 'active' : ''}"
|
||
onclick="reportListManager.goToPage(${i})">${i}</button>`;
|
||
}
|
||
|
||
if (endPage < this.totalPages) {
|
||
if (endPage < this.totalPages - 1) {
|
||
html += '<span class="pagination-ellipsis">...</span>';
|
||
}
|
||
html += `<button class="pagination-btn" onclick="reportListManager.goToPage(${this.totalPages})">${this.totalPages}</button>`;
|
||
}
|
||
|
||
// 下一页按钮
|
||
html += `<button class="pagination-btn ${this.currentPage === this.totalPages ? 'disabled' : ''}"
|
||
onclick="reportListManager.goToPage(${this.currentPage + 1})"
|
||
${this.currentPage === this.totalPages ? 'disabled' : ''}>下一页</button>`;
|
||
|
||
html += '<span class="page-info">';
|
||
html += `第 ${this.currentPage} / ${this.totalPages} 页`;
|
||
html += '</span>';
|
||
|
||
html += '</div>';
|
||
|
||
return html;
|
||
}
|
||
|
||
changePageSize(newPageSize) {
|
||
this.pageSize = parseInt(newPageSize);
|
||
this.currentPage = 1; // 重置到第一页
|
||
|
||
// 重新计算总页数
|
||
this.totalPages = Math.ceil(this.totalRecords / this.pageSize);
|
||
|
||
// 应用分页
|
||
this.applyPagination();
|
||
|
||
// 重新渲染
|
||
this.render();
|
||
}
|
||
|
||
goToPage(page) {
|
||
if (page < 1 || page > this.totalPages || page === this.currentPage) {
|
||
return;
|
||
}
|
||
|
||
// 更新当前页码
|
||
this.currentPage = page;
|
||
|
||
// 应用分页
|
||
this.applyPagination();
|
||
|
||
// 重新渲染
|
||
this.render();
|
||
}
|
||
|
||
showError(message) {
|
||
document.getElementById('loading').style.display = 'none';
|
||
document.getElementById('error').style.display = 'block';
|
||
document.getElementById('error').textContent = message;
|
||
document.getElementById('table-content').style.display = 'none';
|
||
document.getElementById('empty').style.display = 'none';
|
||
}
|
||
}
|
||
|
||
// 示例数据生成器(用于测试和演示)
|
||
class SampleDataGenerator {
|
||
static generateSampleReports() {
|
||
return [
|
||
{
|
||
id: '001',
|
||
studentInfo: {
|
||
name: '张三',
|
||
testDate: '2024-01-15',
|
||
subject: '数学',
|
||
school: '实验小学'
|
||
}
|
||
},
|
||
{
|
||
id: '002',
|
||
studentInfo: {
|
||
name: '李四',
|
||
testDate: '2024-01-18',
|
||
subject: '语文',
|
||
school: '育才小学'
|
||
}
|
||
},
|
||
{
|
||
id: '003',
|
||
studentInfo: {
|
||
name: '王五',
|
||
testDate: '2024-01-20',
|
||
subject: '英语',
|
||
school: '希望小学'
|
||
}
|
||
}
|
||
];
|
||
}
|
||
}
|
||
|
||
// 测评报告跳转地址映射表
|
||
const reportUrls = [
|
||
// 一年级
|
||
{ grade: 'grade1', subject: 'math', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
{ grade: 'grade1', subject: 'chinese', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
{ grade: 'grade1', subject: 'english', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
|
||
// 二年级
|
||
{ grade: 'grade2', subject: 'math', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
{ grade: 'grade2', subject: 'chinese', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
{ grade: 'grade2', subject: 'english', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
|
||
// 三年级
|
||
{ grade: 'grade3', subject: 'math', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
{ grade: 'grade3', subject: 'chinese', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
{ grade: 'grade3', subject: 'english', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
|
||
// 四年级
|
||
{ grade: 'grade4', subject: 'math', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
{ grade: 'grade4', subject: 'chinese', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
{ grade: 'grade4', subject: 'english', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
|
||
// 五年级
|
||
{ grade: 'grade5', subject: 'math', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
{ grade: 'grade5', subject: 'chinese', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
{ grade: 'grade5', subject: 'english', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
|
||
// 六年级
|
||
{ grade: 'grade6', subject: 'math', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
{ grade: 'grade6', subject: 'chinese', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
{ grade: 'grade6', subject: 'english', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
|
||
// 七年级
|
||
{ grade: 'grade7', subject: 'math', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
{ grade: 'grade7', subject: 'chinese', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
{ grade: 'grade7', subject: 'english', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
{ grade: 'grade7', subject: 'physics', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
{ grade: 'grade7', subject: 'chemistry', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
{ grade: 'grade7', subject: 'biology', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
{ grade: 'grade7', subject: 'history', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
{ grade: 'grade7', subject: 'geography', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
{ grade: 'grade7', subject: 'politics', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
|
||
// 八年级
|
||
{ grade: 'grade8', subject: 'math', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
{ grade: 'grade8', subject: 'chinese', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
{ grade: 'grade8', subject: 'english', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
{ grade: 'grade8', subject: 'physics', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
{ grade: 'grade8', subject: 'chemistry', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
{ grade: 'grade8', subject: 'biology', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
{ grade: 'grade8', subject: 'history', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
{ grade: 'grade8', subject: 'geography', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
{ grade: 'grade8', subject: 'politics', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
|
||
// 九年级
|
||
{ grade: 'grade9', subject: 'math', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
{ grade: 'grade9', subject: 'chinese', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
{ grade: 'grade9', subject: 'english', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
{ grade: 'grade9', subject: 'physics', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
{ grade: 'grade9', subject: 'chemistry', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
{ grade: 'grade9', subject: 'biology', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
{ grade: 'grade9', subject: 'history', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
{ grade: 'grade9', subject: 'geography', url: 'http://120.26.23.172:1991/s/HxWL2e' },
|
||
{ grade: 'grade9', subject: 'politics', url: 'http://120.26.23.172:1991/s/HxWL2e' }
|
||
];
|
||
|
||
// 报告跳转管理器
|
||
class ReportJumpManager {
|
||
constructor() {
|
||
this.gradeSelect = document.getElementById('grade-select');
|
||
this.subjectSelect = document.getElementById('subject-select');
|
||
this.createReportBtn = document.getElementById('create-report-btn');
|
||
this.init();
|
||
}
|
||
|
||
init() {
|
||
// 绑定事件
|
||
this.createReportBtn.addEventListener('click', this.handleButtonClick.bind(this));
|
||
this.gradeSelect.addEventListener('change', this.handleGradeChange.bind(this));
|
||
this.subjectSelect.addEventListener('change', this.handleSubjectChange.bind(this));
|
||
}
|
||
|
||
// 查找对应的测评报告URL
|
||
findReportUrl(grade, subject) {
|
||
const report = reportUrls.find(r => r.grade === grade && r.subject === subject);
|
||
return report ? report.url : null;
|
||
}
|
||
|
||
// 显示提示消息
|
||
showMessage(message, type = 'info') {
|
||
// 创建提示元素
|
||
const messageEl = document.createElement('div');
|
||
messageEl.style.cssText = `
|
||
position: fixed;
|
||
top: 20px;
|
||
right: 20px;
|
||
padding: 12px 20px;
|
||
border-radius: 6px;
|
||
color: white;
|
||
font-size: 14px;
|
||
z-index: 1000;
|
||
max-width: 300px;
|
||
opacity: 0;
|
||
transform: translateX(100%);
|
||
transition: all 0.3s ease;
|
||
`;
|
||
|
||
// 根据类型设置背景色
|
||
if (type === 'error') {
|
||
messageEl.style.background = '#e74c3c';
|
||
} else if (type === 'warning') {
|
||
messageEl.style.background = '#f39c12';
|
||
} else {
|
||
messageEl.style.background = '#2ecc71';
|
||
}
|
||
|
||
messageEl.textContent = message;
|
||
document.body.appendChild(messageEl);
|
||
|
||
// 显示动画
|
||
setTimeout(() => {
|
||
messageEl.style.opacity = '1';
|
||
messageEl.style.transform = 'translateX(0)';
|
||
}, 100);
|
||
|
||
// 3秒后自动消失
|
||
setTimeout(() => {
|
||
messageEl.style.opacity = '0';
|
||
messageEl.style.transform = 'translateX(100%)';
|
||
setTimeout(() => {
|
||
if (messageEl.parentNode) {
|
||
document.body.removeChild(messageEl);
|
||
}
|
||
}, 300);
|
||
}, 3000);
|
||
}
|
||
|
||
// 按钮点击事件处理
|
||
handleButtonClick() {
|
||
const selectedGrade = this.gradeSelect.value;
|
||
const selectedSubject = this.subjectSelect.value;
|
||
|
||
// 检查是否选择了年级和学科
|
||
if (!selectedGrade) {
|
||
this.showMessage('请选择年级', 'warning');
|
||
this.gradeSelect.focus();
|
||
return;
|
||
}
|
||
|
||
if (!selectedSubject) {
|
||
this.showMessage('请选择学科', 'warning');
|
||
this.subjectSelect.focus();
|
||
return;
|
||
}
|
||
|
||
// 查找对应的URL
|
||
const reportUrl = this.findReportUrl(selectedGrade, selectedSubject);
|
||
|
||
if (reportUrl) {
|
||
this.showMessage('正在跳转到测评报告页面...', 'info');
|
||
// 在新标签页中打开URL
|
||
setTimeout(() => {
|
||
window.open(reportUrl, '_blank');
|
||
}, 500);
|
||
} else {
|
||
this.showMessage('未找到对应的测评报告链接', 'error');
|
||
}
|
||
}
|
||
|
||
// 年级选择变化事件
|
||
handleGradeChange() {
|
||
// 如果已经选择了学科,检查是否存在对应的组合
|
||
if (this.subjectSelect.value) {
|
||
const reportUrl = this.findReportUrl(this.gradeSelect.value, this.subjectSelect.value);
|
||
if (!reportUrl) {
|
||
this.showMessage('该年级暂无此学科的测评报告', 'warning');
|
||
}
|
||
}
|
||
}
|
||
|
||
// 学科选择变化事件
|
||
handleSubjectChange() {
|
||
// 如果已经选择了年级,检查是否存在对应的组合
|
||
if (this.gradeSelect.value) {
|
||
const reportUrl = this.findReportUrl(this.gradeSelect.value, this.subjectSelect.value);
|
||
if (!reportUrl) {
|
||
this.showMessage('该学科在此年级暂无测评报告', 'warning');
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 初始化报告列表管理器和跳转管理器
|
||
let reportListManager; // 全局变量,用于分页控件访问
|
||
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
reportListManager = new ReportListManager();
|
||
new ReportJumpManager();
|
||
});
|
||
|
||
// 如果需要测试,可以使用以下代码替换实际的API调用
|
||
// document.addEventListener('DOMContentLoaded', function() {
|
||
// const manager = new ReportListManager();
|
||
// manager.reports = SampleDataGenerator.generateSampleReports();
|
||
// manager.render();
|
||
// });
|