Files
2025-01-21 03:09:10 +00:00

1199 lines
42 KiB
HTML

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Reports</title>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.min.css">
<style>
/* 基础样式优化 */
body {
background-color: #f8f9fa;
color: #212529;
line-height: 1.6;
}
/* 卡片样式现代化 */
.card {
border: none;
border-radius: 12px;
box-shadow: 0 2px 12px rgba(0,0,0,0.08);
transition: transform 0.2s, box-shadow 0.2s;
margin-bottom: 24px;
}
.card-title {
font-size: 1.25rem; /* 20px */
font-weight: 600; /* 稍微加粗 */
margin-bottom: 0.75rem;
color: #2c3e50; /* 深色系,提高对比度 */
}
.card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 16px rgba(0,0,0,0.12);
}
.card-body {
padding: 24px;
}
/* 按钮样式优化 */
.btn {
border-radius: 8px; /* 减小圆角 */
padding: 6px 10px; /* 减小内边距 */
font-weight: 500;
font-size: 0.8rem; /* 14px */
transition: all 0.2s;
line-height: 1; /* 优化行高 */
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
backdrop-filter: blur(8px);
transition: all 0.3s ease;
}
.btn-sm { /* 更小尺寸的按钮 */
padding: 4px 10px;
font-size: 0.8rem; /* 13px */
border-radius: 8px;
line-height: 1;
}
.btn-warning {
background: linear-gradient(45deg, #6897fe, #3979e0);
border: none;
color: white;
}
.btn-warning:hover {
background: linear-gradient(45deg, #3979e0, #6897fe);
transform: translateY(-1px);
color: white;
}
.btn-success {
background: linear-gradient(45deg, #1fbff4, #61caf7); /* 明亮蓝色 */
border: none;
color: white;
box-shadow: 0 4px 12px rgba(99, 102, 241, 0.2);
}
.btn-secondary {
background: linear-gradient(45deg, #a5a4a4, #7b8389);
border: none;
}
.btn-secondary:hover {
background: linear-gradient(45deg, #7b8389, #a5a4a4);
transform: translateY(-1px);
}
/* 导航栏样式 */
.navbar {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 64px;
background: var(--surface-color, #FFFFFF);
display: flex;
align-items: center;
padding: 0 24px;
z-index: 1000;
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
}
.navbar-brand {
font-size: 20px;
font-weight: 600;
color: var(--primary-color, #6366F1);
margin-right: 48px;
}
.navbar-menu {
display: flex;
gap: 32px;
}
/* 修改导航栏菜单项样式 */
.navbar-menu-item {
padding: 8px 16px;
cursor: pointer;
border-radius: 8px;
transition: all 0.3s;
color: var(--text-secondary, #64748B);
font-weight: 500;
background: transparent; /* 默认透明背景 */
}
/* 修改悬停和激活状态样式 */
.navbar-menu-item:hover {
background: linear-gradient(145deg, var(--primary-color, #6366F1), var(--primary-light, #818CF8));
color: white;
}
.navbar-menu-item.active {
background: linear-gradient(145deg, var(--primary-color, #6366F1), var(--primary-light, #818CF8));
color: white;
}
.navbar-right {
margin-left: auto;
display: flex;
align-items: center;
gap: 24px;
color: var(--text-secondary, #64748B);
}
/* 更新按钮样式 */
.navbar .btn {
padding: 8px 16px;
border-radius: 8px;
display: flex;
align-items: center;
gap: 8px;
font-weight: 500;
transition: all 0.3s;
}
.navbar .btn-primary {
background: linear-gradient(145deg, var(--primary-color, #6366F1), var(--primary-light, #818CF8));
color: white;
border: none;
}
.navbar .btn-secondary {
background: var(--background-color, #F8FAFC);
color: var(--text-secondary, #64748B);
border: none;
}
.navbar .btn:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(99, 102, 241, 0.2);
}
/* 调整主内容区域的上边距,以适应固定导航栏 */
#mainContent {
margin-top: 64px;
}
/* 图表容器优化 */
.charts-container {
display: flex;
flex-direction: column; /* 垂直排列 */
gap: 20px; /* 图表之间的间距 */
width: 100%;
padding: 20px;
}
.chart-wrapper {
width: 100%;
background: white;
border-radius: 8px;
padding: 15px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.chart-container {
height: 300px; /* 每个图表的固定高度 */
width: 100%;
}
.chart-wrapper h5 {
margin: 0 0 10px 0;
color: #333;
font-size: 16px;
}
/* 数据显示区域优化 */
.data-container {
background-color: white;
padding: 20px;
border-radius: 12px;
box-shadow: 0 2px 12px rgba(0,0,0,0.08);
}
/* 表单控件美化 */
.form-control {
border-radius: 8px;
border: 1px solid #dee2e6;
padding: 10px 16px;
transition: all 0.2s;
}
.form-control:focus {
border-color: #4a6bff;
box-shadow: 0 0 0 3px rgba(74,107,255,0.1);
}
/* 模态框优化 */
.modal-content {
border: none;
border-radius: 16px;
}
.modal-header {
border-bottom: 1px solid #eee;
padding: 20px 24px;
}
.modal-body {
padding: 24px;
}
/* 实验数据显示区域 */
#realTimeData {
height: 300px;
border-radius: 12px;
background: white;
box-shadow: 0 2px 12px rgba(0,0,0,0.08);
}
/* 加载动画优化 */
.spinner-border {
width: 1.5rem;
height: 1.5rem;
border-width: 0.2em;
}
/* 警告提示框美化 */
.alert {
border: none;
border-radius: 12px;
box-shadow: 0 2px 12px rgba(0,0,0,0.08);
}
/* 表格样式优化 */
.table {
border-radius: 8px;
overflow: hidden;
}
.table th {
background-color: #f8f9fa;
font-weight: 600;
}
/* 滚动条美化 */
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 4px;
}
::-webkit-scrollbar-thumb {
background: #888;
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: #555;
}
.hidden {
display: none;
}
.page-content {
display: none;
}
.page-content.active {
display: block;
}
.charts-container {
display: flex;
flex-wrap: wrap;
gap: 20px;
margin: 20px 0;
}
.chart-wrapper {
background: white;
padding: 15px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
width: calc(50% - 10px);
min-width: 300px;
}
.chart-container {
position: relative;
height: 250px;
width: 100%;
}
/* 按钮禁用状态样式 */
.btn:disabled,
.btn[disabled] {
background-color: #b8b8b8 !important; /* 使用 !important 确保覆盖其他样式 */
color: white !important;
border: none;
opacity: 0.65 !important; /* 防止 Bootstrap 默认的透明度 */
cursor: not-allowed;
}
/* 确保禁用状态下的渐变背景也变为灰色 */
.btn-warning:disabled,
.btn-primary:disabled,
.btn-info:disabled {
background: #b8b8b8 !important;
background-image: none !important;
}
/* 禁用状态下取消悬停效果 */
.btn:disabled:hover {
transform: none !important;
box-shadow: 0 2px 4px rgba(0,0,0,0.1) !important;
}
/* 禁用状态下的按钮样式 */
.btn-success:disabled,
.btn-success[disabled] {
background: #adb0b4 !important; /* 使用纯色背景 */
background-image: none !important; /* 移除渐变效果 */
background-color: #adb0b4 !important;
border-color: #adb0b4 !important;
color: #fff !important;
opacity: 0.65 !important;
pointer-events: none;
transform: none !important;
}
/* 确保禁用状态下不会显示悬停效果 */
.btn-success:disabled:hover,
.btn-success[disabled]:hover {
background: #adb0b4 !important;
background-image: none !important;
background-color: #adb0b4 !important;
border-color: #adb0b4 !important;
transform: none !important;
}
/* 侧边栏样式 */
.sidebar {
position: fixed;
top: var(--header-height);
left: 0;
bottom: 0;
width: var(--sidebar-width);
background: var(--surface-color);
border-right: 1px solid var(--border-color);
}
.sidebar-menu {
list-style: none;
padding: 16px 0;
}
.sidebar-item {
padding: 12px 20px;
display: flex;
align-items: center;
gap: 12px;
cursor: pointer;
transition: all 0.3s;
margin: 4px 8px;
border-radius: 8px;
color: var(--text-secondary);
font-weight: 500;
}
.sidebar-item:hover {
background: linear-gradient(145deg, var(--primary-color), var(--primary-light));
color: white;
}
.sidebar-item.active {
background: linear-gradient(145deg, var(--primary-color), var(--primary-light));
color: white;
box-shadow: 0 4px 12px rgba(99, 102, 241, 0.2);
}
.sidebar-item .bi {
font-size: 1.2rem;
}
/* 添加CSS变量 */
:root {
--header-height: 64px;
--sidebar-width: 240px;
--surface-color: #FFFFFF;
--border-color: #E2E8F0;
--primary-color: #6366F1;
--primary-light: #818CF8;
--text-secondary: #64748B;
}
/* 移除卡片样式 */
.sidebar.card {
border: none;
box-shadow: none;
background: none;
}
.sidebar .card-body {
padding: 0;
}
/* 主要内容区域 */
.main-content {
margin-left: var(--sidebar-width);
margin-top: var(--header-height);
padding: 24px 32px;
}
.page-header {
margin-bottom: 24px;
display: flex;
justify-content: space-between;
align-items: center;
}
.page-title {
font-size: 24px;
font-weight: 600;
background: linear-gradient(45deg, var(--primary-color), var(--primary-light));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
/* 更新卡片样式 */
.card {
background: var(--surface-color);
border-radius: 16px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.05);
transition: transform 0.3s;
border: none;
}
.card:hover {
transform: translateY(-2px);
}
.card-header {
padding: 20px 24px;
border-bottom: 1px solid var(--border-color);
display: flex;
justify-content: space-between;
align-items: center;
background: transparent;
}
.card-title {
font-size: 16px;
font-weight: 600;
color: var(--text-primary);
}
.card-body {
padding: 24px;
}
/* 更新按钮样式 */
.btn {
padding: 10px 20px;
border-radius: 8px;
border: none;
cursor: pointer;
transition: all 0.3s;
font-weight: 500;
display: inline-flex;
align-items: center;
gap: 8px;
}
.btn-primary {
background: linear-gradient(145deg, var(--primary-color), var(--primary-light));
color: white;
box-shadow: 0 4px 12px rgba(99, 102, 241, 0.2);
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 6px 16px rgba(99, 102, 241, 0.3);
}
.btn-secondary {
background: var(--background-color);
color: var(--text-secondary);
}
.btn-secondary:hover {
background: var(--border-color);
}
/* 更新表单控件样式 */
.form-control {
padding: 10px 16px;
border: 1px solid var(--border-color);
border-radius: 8px;
font-size: 14px;
transition: all 0.3s;
background: var(--background-color);
color: var(--text-primary);
}
.form-control:focus {
border-color: var(--primary-color);
outline: none;
box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1);
}
/* 告部分切换样式 */
.report-section {
display: none;
}
.report-section.active {
display: block;
}
#chartsContainer {
display: flex;
flex-direction: column; /* 垂直排列 */
gap: 20px; /* 图表之间的间距 */
width: 100%;
padding: 20px;
}
.chart-wrapper {
width: 100%;
background: white;
border-radius: 8px;
padding: 15px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.chart-container {
height: 300px; /* 每个图表的固定高度 */
width: 100%;
}
.chart-wrapper h5 {
margin: 0 0 10px 0;
color: #333;
font-size: 16px;
}
.chart-data-panel {
background: #f8f9fa;
border-radius: 12px;
padding: 20px;
box-shadow: 0 2px 8px rgba(0,0,0,0.05);
height: 100%;
min-height: 300px;
}
.custom-data-list {
display: flex;
flex-direction: column;
gap: 15px;
}
.custom-data-item {
background: white;
padding: 15px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
transition: transform 0.2s;
}
.custom-data-item:hover {
transform: translateY(-2px);
}
.custom-data-name {
font-size: 0.9rem;
color: #666;
margin-bottom: 5px;
}
.custom-data-value {
font-size: 1.5rem;
font-weight: 600;
color: #2c3e50;
display: flex;
align-items: baseline;
}
.custom-data-unit {
font-size: 0.9rem;
color: #666;
margin-left: 5px;
}
/* 响应式布局优化 */
@media (max-width: 991.98px) {
.chart-data-panel {
margin-top: 20px;
min-height: auto;
}
}
</style>
</head>
<body>
<nav class="navbar">
<div class="navbar-brand">Lab</div>
<div class="navbar-menu">
<div class="navbar-menu-item" onclick="window.location.href='lab.html'">Project</div>
<div class="navbar-menu-item" onclick="window.location.href='device.html'">Device</div>
<div class="navbar-menu-item active">Reports</div>
<div class="navbar-menu-item" onclick="window.location.href='paper.html'">Paper</div>
</div>
<div class="navbar-right">
<a href="https://beta.obscura.work/lab/device.html" target="_blank" class="btn btn-primary">
<i class="bi bi-plus-circle"></i>
Device Registration
</a>
<span class="nav-item" id="userInfo"></span>
<button class="btn btn-secondary" id="logoutBtn" onclick="logout()">
<i class="bi bi-box-arrow-right"></i>
Logout
</button>
</div>
</nav>
<div class="main-content">
<div class="row">
<!-- 左侧侧边栏 -->
<div class="col-auto">
<div class="sidebar">
<div class="sidebar-menu">
<div class="sidebar-item" onclick="showReportsFilter()">
<i class="bi bi-funnel"></i>
<span>Filter</span>
</div>
<div class="sidebar-item" onclick="showReportsSort()">
<i class="bi bi-sort-down"></i>
<span>Sort</span>
</div>
<div class="sidebar-item" onclick="generateSummaryReport()">
<i class="bi bi-file-earmark-text"></i>
<span>Summary</span>
</div>
<div class="sidebar-item" onclick="exportAllReports()">
<i class="bi bi-download"></i>
<span>Download</span>
</div>
</div>
</div>
</div>
<!-- 右侧主要内容区 -->
<div class="col ps-0 pe-4">
<div class="card w-100">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center mb-4">
<h3 class="page-title">Reports</h3>
</div>
<div id="reportsList" class="mt-4">
<!-- Project reports list will be displayed here dynamically -->
</div>
</div>
</div>
</div>
</div>
<!-- Reports Filter Modal -->
<div class="modal fade" id="reportsFilterModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Filter Reports</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<form id="reportFilterForm">
<div class="mb-3">
<label class="form-label">Project Name</label>
<input type="text" class="form-control" id="filterReportProjectName">
</div>
<div class="mb-3">
<label class="form-label">Date Range</label>
<div class="row">
<div class="col">
<input type="date" class="form-control" id="filterReportStartDate">
</div>
<div class="col">
<input type="date" class="form-control" id="filterReportEndDate">
</div>
</div>
</div>
<div class="mb-3">
<label class="form-label">Report Type</label>
<select class="form-select" id="filterReportType">
<option value="">All</option>
<option value="project">Project</option>
<option value="experiment">experiment</option>
<option value="paper">Paper</option>
</select>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" onclick="resetReportFilters()">Reset</button>
<button type="button" class="btn btn-primary" onclick="applyReportFilters()">Apply</button>
</div>
</div>
</div>
</div>
<!-- Report Detail Page -->
<div id="reportDetailPage" class="page-content"> <!-- 移除 container mt-4 类 -->
<div class="row">
<!-- 左侧侧边栏 -->
<div class="col-auto">
<div class="sidebar">
<div class="sidebar-menu">
<div class="sidebar-item" onclick="switchReportSection('projectReport')">
<i class="bi bi-file-text"></i>
<span>Project</span>
</div>
<div class="sidebar-item" onclick="switchReportSection('paperReport')">
<i class="bi bi-book"></i>
<span>Paper</span>
</div>
<div class="sidebar-item" onclick="downloadCurrentReport()">
<i class="bi bi-download"></i>
<span>Download</span>
</div>
<div class="sidebar-item" onclick="showPage('reports')">
<i class="bi bi-arrow-left"></i>
<span>Back</span>
</div>
</div>
</div>
</div>
<!-- 右侧主要内容区 -->
<div class="col ps-0 pe-4">
<div class="card w-100">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center mb-4">
<h3 id="reportDetailTitle">Project Report</h3>
</div>
<div class="report-sections">
<div id="projectReportSection" class="report-section active">
<pre id="projectReportDetail" class="report-content bg-light p-3 rounded"></pre>
</div>
<div id="paperReportSection" class="report-section">
<pre id="paperReportDetail" class="report-content bg-light p-3 rounded"></pre>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Reports Sort Modal -->
<div class="modal fade" id="reportsSortModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Sort Reports</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<form id="reportSortForm">
<div class="mb-3">
<label class="form-label">Sort By</label>
<select class="form-select" id="reportSortField">
<option value="create_time">Creation Date</option>
<option value="project_name">Project Name</option>
<option value="report_type">Report Type</option>
</select>
</div>
<div class="mb-3">
<label class="form-label">Order</label>
<select class="form-select" id="reportSortOrder">
<option value="desc">Descending</option>
<option value="asc">Ascending</option>
</select>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary" onclick="applyReportSort()">Apply</button>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
<script>
// API base URL
const API_BASE_URL = 'https://dev.obscura.work/lab';
let token = localStorage.getItem('token');
// 过滤和排序状态
let reportsFilter = {
projectName: '',
startDate: '',
endDate: '',
type: ''
};
let reportsSort = {
field: 'create_time',
order: 'desc'
};
// 页面加载时检查登录状态并加载报告
document.addEventListener('DOMContentLoaded', () => {
if (token) {
loadReports();
} else {
window.location.href = 'lab.html';
}
});
// Store current report data being viewed
let currentReportData = null;
// 格式化报告内容的辅助函数
function formatReportContent(jsonData) {
if (!jsonData) return '无数据';
return `<div style="white-space: pre-wrap; word-wrap: break-word;">` +
JSON.stringify(jsonData, null, 2)
// 移除所有括号和引号
.replace(/[{}"]/g, '')
.replace(/},/g, '')
.replace(/{ },/g, '')
.replace(/^\s*,/gm, '') // 处理行首的逗号
.replace(/Project Analysis Report:/, '<div style="text-align: center"><strong style="font-size: 24px;">Project Analysis Report</strong></div>')
.replace(/paper Summary Report:/, '<div style="text-align: center"><strong style="font-size: 24px;">Paper Summary Report</strong></div>')
// 加粗标题 (以数字开头的行)
.replace(/^(\s*\d+\.[^:\n]+:)/gm, '<strong>$1</strong>')
// 保持缩进
.split('\n')
.map(line => line.trimEnd())
.join('\n') +
'</div>';
}
// Add load project report list function
async function loadReports() {
try {
const response = await fetch(`${API_BASE_URL}/projects`, {
headers: {
'Authorization': `Bearer ${token}`
}
});
if (response.ok) {
const projects = await response.json();
const reportsList = document.getElementById('reportsList');
const reportsHtml = projects.map(project => `
<div class="card mb-3" style="cursor: pointer;"
onclick="viewProjectReport('${project._id}', '${project.project_name}')">
<div class="card-body d-flex align-items-center">
<div class="flex-grow-1">
<h5 class="card-title mb-1">${project.project_name}</h5>
<p class="card-text mb-0">${project.description}</p>
</div>
<div>
<button class="btn btn-warning"
onclick="event.stopPropagation(); viewProjectReport('${project._id}', '${project.project_name}')">
View Report
</button>
</div>
</div>
</div>
`).join('');
reportsList.innerHTML = reportsHtml;
}
} catch (error) {
console.error('Failed to load project report list:', error);
alert('Failed to load project report list, please try again');
}
}
// 修改后的 viewProjectReport 函数
async function viewProjectReport(projectId, projectName) {
try {
let projectData = null, paperData = null;
// 隐藏项目列表页面
document.querySelector('.main-content > .row').style.display = 'none';
// 1. 尝试获取项目报告
const projectResponse = await fetch(`${API_BASE_URL}/projects/${projectId}/report`, {
headers: {
'Authorization': `Bearer ${token}`
}
});
if (projectResponse.ok) {
projectData = await projectResponse.json();
} else {
console.log('No project report found');
}
// 2. 如果没有项目报告,尝试获取文献分析报告
if (!projectData) {
const paperResponse = await fetch(`${API_BASE_URL}/references/${projectId}/summary_report`, {
headers: {
'Authorization': `Bearer ${token}`
}
});
if (paperResponse.ok) {
paperData = await paperResponse.json();
} else {
console.log('No paper report found');
}
}
// 3. 如果两种报告都没有,显示提示信息
if (!projectData && !paperData) {
document.getElementById('reportDetailTitle').textContent = `Project Report - ${projectName}`;
document.getElementById('projectReportDetail').innerHTML =
'<div class="alert alert-info">No reports available for this project yet.</div>';
document.getElementById('paperReportDetail').innerHTML =
'<div class="alert alert-info">No paper analysis report available.</div>';
} else {
// 4. 保存当前报告数据
currentReportData = {
projectId,
projectName,
projectReport: projectData,
paperReport: paperData
};
// 5. 更新报告显示
document.getElementById('reportDetailTitle').textContent = `Project Report - ${projectName}`;
document.getElementById('projectReportDetail').innerHTML = projectData ?
formatReportContent(projectData) :
'<div class="alert alert-info">No project report available.</div>';
document.getElementById('paperReportDetail').innerHTML = paperData ?
formatReportContent(paperData) :
'<div class="alert alert-info">No paper analysis report available.</div>';
}
// 6. 显示报告详情页面
document.querySelectorAll('.page-content').forEach(page => {
page.classList.remove('active');
});
document.getElementById('reportDetailPage').classList.add('active');
} catch (error) {
console.error('Failed to view project report:', error);
alert('Failed to view project report, please try again');
}
}
// Download current report being viewed
function downloadCurrentReport() {
if (!currentReportData) return;
// Build complete report object
const combinedReport = {
project_report: currentReportData.projectReport,
paper_analysis: currentReportData.paperReport || "No paper analysis report found"
};
const reportText = JSON.stringify(combinedReport, null, 2);
const blob = new Blob([reportText], { type: 'application/json' });
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `project_complete_report_${currentReportData.projectName}.json`;
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
document.body.removeChild(a);
}
// Add load reports filter function
function showReportsFilter() {
// 设置当前过滤值
document.getElementById('filterReportProjectName').value = reportsFilter.projectName;
document.getElementById('filterReportStartDate').value = reportsFilter.startDate;
document.getElementById('filterReportEndDate').value = reportsFilter.endDate;
document.getElementById('filterReportType').value = reportsFilter.type;
// 显示模态框
new bootstrap.Modal(document.getElementById('reportsFilterModal')).show();
}
// Add load reports sort function
function showReportsSort() {
// 设置当前排序值
document.getElementById('reportSortField').value = reportsSort.field;
document.getElementById('reportSortOrder').value = reportsSort.order;
// 显示模态框
new bootstrap.Modal(document.getElementById('reportsSortModal')).show();
}
// Reset reports filter
function resetReportFilters() {
reportsFilter = {
projectName: '',
startDate: '',
endDate: '',
type: ''
};
// 重置表单
document.getElementById('reportFilterForm').reset();
// 重新加载项目列表
loadReports();
// 关闭模态框
bootstrap.Modal.getInstance(document.getElementById('reportsFilterModal')).hide();
}
// Apply reports filter
function applyReportFilters() {
reportsFilter = {
projectName: document.getElementById('filterReportProjectName').value,
startDate: document.getElementById('filterReportStartDate').value,
endDate: document.getElementById('filterReportEndDate').value,
type: document.getElementById('filterReportType').value
};
// 重新加载项目列表
loadReports();
// 关闭模态框
bootstrap.Modal.getInstance(document.getElementById('reportsFilterModal')).hide();
}
// Apply reports sort
function applyReportSort() {
reportsSort = {
field: document.getElementById('reportSortField').value,
order: document.getElementById('reportSortOrder').value
};
// 重新加载项目列表
loadReports();
// 关闭模态框
bootstrap.Modal.getInstance(document.getElementById('reportsSortModal')).hide();
}
// Export all reports
async function exportAllReports() {
try {
const response = await fetch(`${API_BASE_URL}/projects`, {
headers: {
'Authorization': `Bearer ${token}`
}
});
if (response.ok) {
const projects = await response.json();
const reports = projects.map(project => ({
project_name: project.project_name,
description: project.description,
project_reports: project.project_reports,
paper_analysis: project.paper_analysis
}));
const reportText = JSON.stringify(reports, null, 2);
const blob = new Blob([reportText], { type: 'application/json' });
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'all_reports.json';
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
document.body.removeChild(a);
}
} catch (error) {
console.error('Failed to export all reports:', error);
alert('Failed to export all reports, please try again');
}
}
// Generate summary report
async function generateSummaryReport() {
try {
const response = await fetch(`${API_BASE_URL}/projects`, {
headers: {
'Authorization': `Bearer ${token}`
}
});
if (response.ok) {
const projects = await response.json();
const summary = projects.map(project => ({
project_name: project.project_name,
description: project.description,
project_reports: project.project_reports,
paper_analysis: project.paper_analysis
}));
const summaryText = JSON.stringify(summary, null, 2);
const blob = new Blob([summaryText], { type: 'application/json' });
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'summary_report.json';
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
document.body.removeChild(a);
}
} catch (error) {
console.error('Failed to generate summary report:', error);
alert('Failed to generate summary report, please try again');
}
}
// Switch between project report and paper analysis
function switchReportSection(section) {
// Remove active class from all sections
document.querySelectorAll('.report-section').forEach(section => {
section.classList.remove('active');
});
// Add active class to the selected section
document.getElementById(section + 'Section').classList.add('active');
}
// 切换报告部分
function switchReportSection(sectionId) {
// 隐藏所有报告部分
document.querySelectorAll('.report-section').forEach(section => {
section.classList.remove('active');
});
// 显示选中的报告部分
const selectedSection = document.getElementById(sectionId + 'Section');
if (selectedSection) {
selectedSection.classList.add('active');
}
// 更新标题
const title = sectionId === 'projectReport' ? 'Project Report' : 'paper Analysis';
document.getElementById('reportDetailTitle').textContent = `${title} - ${currentReportData.projectName}`;
// 更新侧边栏选中状态
document.querySelectorAll('.sidebar-item').forEach(item => {
if (item.textContent.trim().includes(title)) {
item.classList.add('active');
} else {
item.classList.remove('active');
}
});
}
// 返回报告列表
function showPage(pageId) {
if (pageId === 'reports') {
document.getElementById('reportDetailPage').classList.remove('active');
document.querySelector('.main-content > .row').style.display = 'flex';
loadReports();
}
}
</script>
</body>
</html>