完整的教务系统前端项目 - 包含所有修复和9月份数据

This commit is contained in:
KQL
2025-09-03 13:26:13 +08:00
commit 87b06d3176
270 changed files with 116169 additions and 0 deletions

View File

@@ -0,0 +1,330 @@
/* 个人数据展示区样式 */
.personal-data-display {
background: var(--card-bg);
border-radius: 8px;
box-shadow: var(--shadow);
border: 1px solid var(--border-color);
padding: 20px;
grid-column: span 3; /* 占满整行 */
margin-bottom: 16px;
}
.personal-data-display .module-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
border-bottom: 1px solid var(--border-color);
padding-bottom: 12px;
}
.semester-indicator {
font-size: 12px;
color: var(--text-muted);
background: #f3f4f6;
padding: 4px 8px;
border-radius: 4px;
}
/* 左右分栏布局 */
.data-display-layout {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 24px;
}
/* 通用面板样式 */
.left-panel, .right-panel {
border: 1px solid var(--border-color);
border-radius: 6px;
padding: 16px;
cursor: pointer;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.left-panel:hover, .right-panel:hover {
border-color: var(--primary-color);
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.15);
transform: translateY(-2px);
}
.panel-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
}
.panel-header h4 {
font-size: 14px;
font-weight: 600;
color: var(--text-primary);
margin: 0;
}
.click-hint {
font-size: 11px;
color: var(--text-muted);
opacity: 0;
transition: opacity 0.3s ease;
}
.left-panel:hover .click-hint,
.right-panel:hover .click-hint {
opacity: 1;
}
/* 左侧面板:可视化容器 */
.visualization-container {
display: flex;
flex-direction: column;
gap: 20px;
}
.progress-section {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
}
.progress-circle {
width: 80px;
height: 80px;
position: relative;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 8px;
}
.progress-text {
font-size: 16px;
font-weight: 600;
color: var(--primary-color);
}
.progress-label {
font-size: 12px;
color: var(--text-secondary);
margin: 0;
}
/* 成绩趋势图 */
.trend-section h5 {
font-size: 12px;
font-weight: 500;
color: var(--text-primary);
margin: 0 0 12px 0;
}
.mini-chart {
display: flex;
justify-content: space-between;
align-items: end;
height: 60px;
gap: 8px;
}
.trend-point {
display: flex;
flex-direction: column;
align-items: center;
flex: 1;
}
.trend-bar {
width: 12px;
background: linear-gradient(to top, var(--primary-color), #60a5fa);
border-radius: 2px 2px 0 0;
margin-bottom: 4px;
transition: all 0.3s ease;
}
.trend-label {
font-size: 10px;
color: var(--text-muted);
}
/* 知识点掌握度 */
.knowledge-section h5 {
font-size: 12px;
font-weight: 500;
color: var(--text-primary);
margin: 0 0 12px 0;
}
.knowledge-bars {
display: flex;
flex-direction: column;
gap: 8px;
}
.knowledge-item {
display: flex;
align-items: center;
gap: 8px;
font-size: 11px;
}
.knowledge-name {
color: var(--text-secondary);
width: 60px;
flex-shrink: 0;
}
.knowledge-bar {
flex: 1;
height: 6px;
background: #f3f4f6;
border-radius: 3px;
overflow: hidden;
}
.knowledge-fill {
height: 100%;
background: linear-gradient(90deg, #10b981, #34d399);
border-radius: 3px;
transition: width 0.5s ease;
}
.knowledge-value {
color: var(--text-primary);
font-weight: 500;
width: 30px;
text-align: right;
}
/* 右侧面板:排名表格 */
.ranking-table-container {
position: relative;
}
.ranking-table {
width: 100%;
border-collapse: collapse;
font-size: 12px;
}
.ranking-table th {
background: #f8fafc;
color: var(--text-secondary);
font-weight: 500;
padding: 8px 4px;
text-align: left;
border-bottom: 1px solid var(--border-color);
}
.ranking-table td {
padding: 8px 4px;
border-bottom: 1px solid #f3f4f6;
vertical-align: middle;
}
.ranking-table tbody tr:hover {
background: #f8fafc;
}
.rank-number {
width: 20px;
height: 20px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 10px;
font-weight: 600;
background: #f3f4f6;
color: var(--text-secondary);
}
.rank-number.gold {
background: #fbbf24;
color: white;
}
.rank-number.silver {
background: #d1d5db;
color: white;
}
.rank-number.bronze {
background: #cd7c2f;
color: white;
}
.student-name {
color: var(--text-primary);
font-weight: 500;
}
.student-score {
color: var(--text-primary);
font-weight: 600;
}
.subject-score {
color: var(--text-secondary);
}
.trend-cell {
text-align: center;
}
.trend-indicator {
font-size: 10px;
font-weight: 500;
padding: 2px 4px;
border-radius: 2px;
}
.trend-indicator.up {
color: #10b981;
background: rgba(16, 185, 129, 0.1);
}
.trend-indicator.down {
color: #ef4444;
background: rgba(239, 68, 68, 0.1);
}
.more-indicator {
text-align: center;
margin-top: 12px;
font-size: 11px;
color: var(--primary-color);
font-weight: 500;
}
/* 响应式设计 */
@media (max-width: 1024px) {
.data-display-layout {
grid-template-columns: 1fr;
gap: 16px;
}
.personal-data-display {
grid-column: span 2;
}
}
@media (max-width: 768px) {
.personal-data-display {
grid-column: span 1;
}
.visualization-container {
gap: 16px;
}
.mini-chart {
height: 50px;
}
.ranking-table th,
.ranking-table td {
padding: 6px 2px;
}
}

View File

@@ -0,0 +1,222 @@
import { useNavigate } from "react-router-dom";
import { mockData } from "@/data/mockData";
import "./index.css";
const PersonalDataDisplay = () => {
const navigate = useNavigate();
const { studyProgress, classRanking } = mockData;
// 点击跳转到个人档案,并传递上下文状态
const handleNavigateToProfile = (sourceType) => {
const contextState = {
semester: "2024春季学期",
subject: "all",
sourceModule: sourceType, // 'learning' 或 'ranking'
};
navigate("/profile", {
state: contextState,
});
};
// 计算环形进度条的参数
const radius = 35;
const circumference = 2 * Math.PI * radius;
const strokeDasharray = circumference;
const strokeDashoffset =
circumference - (studyProgress.percentage / 100) * circumference;
// 模拟多维度学习数据
const learningMetrics = {
gradesTrend: [
{ month: "9月", score: 78 },
{ month: "10月", score: 82 },
{ month: "11月", score: 85 },
{ month: "12月", score: 88 },
{ month: "1月", score: 92 },
],
knowledgePoints: [
{ subject: "数据结构", mastery: 85 },
{ subject: "算法设计", mastery: 78 },
{ subject: "数据库", mastery: 92 },
{ subject: "网络编程", mastery: 76 },
],
taskCompletion: 85.6,
};
// 扩展班级排名数据
const extendedRankingData = classRanking.map((student) => ({
...student,
subjects: {
math: Math.floor(Math.random() * 20) + 80,
programming: Math.floor(Math.random() * 20) + 80,
database: Math.floor(Math.random() * 20) + 80,
},
trend: Math.random() > 0.5 ? "up" : "down",
trendValue: Math.floor(Math.random() * 5) + 1,
}));
return (
<div className="personal-data-display">
<div className="module-header">
<h3 className="module-title">个人数据展示区</h3>
<div className="semester-indicator">2024春季学期</div>
</div>
<div className="data-display-layout">
{/* 左侧面板:学习数据可视化 */}
<div
className="left-panel"
onClick={() => handleNavigateToProfile("learning")}
>
<div className="panel-header">
<h4>学习数据分析</h4>
<span className="click-hint">点击查看详情</span>
</div>
<div className="visualization-container">
{/* 圆环进度图 */}
<div className="progress-section">
<div className="progress-circle">
<svg width="80" height="80">
<circle
cx="40"
cy="40"
r={radius}
fill="none"
stroke="#f3f4f6"
strokeWidth="6"
/>
<circle
cx="40"
cy="40"
r={radius}
fill="none"
stroke="var(--primary-color)"
strokeWidth="6"
strokeLinecap="round"
strokeDasharray={strokeDasharray}
strokeDashoffset={strokeDashoffset}
style={{
transform: "rotate(-90deg)",
transformOrigin: "40px 40px",
transition: "stroke-dashoffset 0.5s ease",
}}
/>
</svg>
<div className="progress-text">{studyProgress.percentage}%</div>
</div>
<p className="progress-label">总体完成率</p>
</div>
{/* 成绩趋势折线图(简化版) */}
<div className="trend-section">
<h5>成绩趋势</h5>
<div className="mini-chart">
{learningMetrics.gradesTrend.map((item, index) => (
<div key={index} className="trend-point">
<div
className="trend-bar"
style={{ height: `${(item.score - 70) * 2}px` }}
/>
<span className="trend-label">{item.month}</span>
</div>
))}
</div>
</div>
{/* 知识点掌握度 */}
<div className="knowledge-section">
<h5>知识点掌握度</h5>
<div className="knowledge-bars">
{learningMetrics.knowledgePoints
.slice(0, 3)
.map((point, index) => (
<div key={index} className="knowledge-item">
<span className="knowledge-name">{point.subject}</span>
<div className="knowledge-bar">
<div
className="knowledge-fill"
style={{ width: `${point.mastery}%` }}
/>
</div>
<span className="knowledge-value">{point.mastery}%</span>
</div>
))}
</div>
</div>
</div>
</div>
{/* 右侧面板:班级排名数据表格 */}
<div
className="right-panel"
onClick={() => handleNavigateToProfile("ranking")}
>
<div className="panel-header">
<h4>班级排名</h4>
<span className="click-hint">点击查看详情</span>
</div>
<div className="ranking-table-container">
<table className="ranking-table">
<thead>
<tr>
<th>排名</th>
<th>姓名</th>
<th>综合分</th>
<th>数学</th>
<th>编程</th>
<th>变化</th>
</tr>
</thead>
<tbody>
{extendedRankingData.slice(0, 5).map((student) => (
<tr key={student.id}>
<td>
<div
className={`rank-number ${
student.rank === 1
? "gold"
: student.rank === 2
? "silver"
: student.rank === 3
? "bronze"
: ""
}`}
>
{student.rank <= 3
? student.rank === 1
? "🥇"
: student.rank === 2
? "🥈"
: "🥉"
: student.rank}
</div>
</td>
<td className="student-name">{student.name}</td>
<td className="student-score">{student.score}</td>
<td className="subject-score">{student.subjects.math}</td>
<td className="subject-score">
{student.subjects.programming}
</td>
<td className="trend-cell">
<span className={`trend-indicator ${student.trend}`}>
{student.trend === "up" ? "↗" : "↘"}{" "}
{student.trendValue}
</span>
</td>
</tr>
))}
</tbody>
</table>
<div className="more-indicator">查看完整排名 </div>
</div>
</div>
</div>
</div>
);
};
export default PersonalDataDisplay;