feat: 完成学情统计和学生成绩页面开发:新增LearningStatistics.vue学情统计页面,包含6个统计模块和ECharts图表,新增StudentGrades.vue学生成绩页面,支持成绩管理、权重设置和提醒功能
This commit is contained in:
parent
dd11e9aa2d
commit
a30e23ab07
@ -1,34 +1,676 @@
|
||||
<template>
|
||||
<div class="learning-statistics">
|
||||
<div class="content-placeholder">
|
||||
<h3>学情统计</h3>
|
||||
<p>学情统计功能正在开发中...</p>
|
||||
<!-- 班级选择 -->
|
||||
<div class="class-selector">
|
||||
<div class="selector-container">
|
||||
<select class="class-select" v-model="selectedClass">
|
||||
<option value="">班级名称</option>
|
||||
<option value="class1">计算机科学1班</option>
|
||||
<option value="class2">计算机科学2班</option>
|
||||
<option value="class3">软件工程1班</option>
|
||||
</select>
|
||||
<div class="selector-arrow">
|
||||
<img src="/images/teacher/箭头-黑.png" alt="箭头" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 统计内容区域 -->
|
||||
<div class="statistics-content">
|
||||
<!-- 章节统计 -->
|
||||
<div class="statistics-card">
|
||||
<h3 class="card-title">
|
||||
<span class="title-main">章节</span>
|
||||
<span class="title-sub">(共4章5小节)</span>
|
||||
</h3>
|
||||
<div class="card-content">
|
||||
<!-- 左侧文本统计 -->
|
||||
<div class="text-stats">
|
||||
<div class="stat-item">
|
||||
<div class="stat-label">章节学习总人次</div>
|
||||
<div class="stat-value">
|
||||
<span class="stat-number">0</span>
|
||||
<span class="stat-unit">人</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<div class="stat-label">章节平均学习次数</div>
|
||||
<div class="stat-value">
|
||||
<span class="stat-number">0</span>
|
||||
<span class="stat-unit">次</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧饼图 -->
|
||||
<div class="chart-section">
|
||||
<h4 class="chart-title">学习次数分布</h4>
|
||||
<div class="chart-container">
|
||||
<v-chart :option="learningDistributionOption" style="height: 100%;" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 作业统计 -->
|
||||
<div class="statistics-card">
|
||||
<h3 class="card-title">
|
||||
<span class="title-main">作业</span>
|
||||
<span class="title-sub">(共5个)</span>
|
||||
</h3>
|
||||
<div class="card-content">
|
||||
<div class="chart-section full-width">
|
||||
<h4 class="chart-title">作业完成率</h4>
|
||||
<div class="chart-container">
|
||||
<v-chart :option="assignmentCompletionOption" style="height: 100%;" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 考试和练习容器 -->
|
||||
<div class="exam-practice-container">
|
||||
<!-- 考试统计卡片 -->
|
||||
<div class="statistics-card">
|
||||
<h3 class="card-title">
|
||||
<span class="title-main">考试</span>
|
||||
<span class="title-sub">(共5场)</span>
|
||||
</h3>
|
||||
<div class="card-content">
|
||||
<!-- 左侧文本统计 -->
|
||||
<div class="text-stats">
|
||||
<div class="stat-item">
|
||||
<div class="stat-label">参与人数</div>
|
||||
<div class="stat-value">
|
||||
<span class="stat-number">70</span>
|
||||
<span class="stat-unit">人</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<div class="stat-label">平均成绩</div>
|
||||
<div class="stat-value">
|
||||
<span class="stat-number">60</span>
|
||||
<span class="stat-unit">分</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 右侧饼图 -->
|
||||
<div class="chart-section">
|
||||
<h4 class="chart-title">成绩占比</h4>
|
||||
<div class="chart-container">
|
||||
<v-chart :option="examScoreOption" style="height: 100%;" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 练习统计卡片 -->
|
||||
<div class="statistics-card">
|
||||
<h3 class="card-title">
|
||||
<span class="title-main">练习</span>
|
||||
<span class="title-sub">(共5场)</span>
|
||||
</h3>
|
||||
<div class="card-content">
|
||||
<!-- 左侧文本统计 -->
|
||||
<div class="text-stats">
|
||||
<div class="stat-item">
|
||||
<div class="stat-label">参与人数</div>
|
||||
<div class="stat-value">
|
||||
<span class="stat-number">70</span>
|
||||
<span class="stat-unit">人</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<div class="stat-label">平均成绩</div>
|
||||
<div class="stat-value">
|
||||
<span class="stat-number">60</span>
|
||||
<span class="stat-unit">分</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 右侧饼图 -->
|
||||
<div class="chart-section">
|
||||
<h4 class="chart-title">成绩占比</h4>
|
||||
<div class="chart-container">
|
||||
<v-chart :option="practiceScoreOption" style="height: 100%;" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 证书和讨论容器 -->
|
||||
<div class="exam-practice-container">
|
||||
<!-- 证书统计卡片 -->
|
||||
<div class="statistics-card">
|
||||
<h3 class="card-title">
|
||||
<span class="title-main">证书</span>
|
||||
<span class="title-sub">(共1个)</span>
|
||||
</h3>
|
||||
<div class="card-content">
|
||||
<div class="chart-section full-width">
|
||||
<h4 class="chart-title">证书获取率</h4>
|
||||
<div class="chart-container">
|
||||
<v-chart :option="certificateOption" style="height: 100%;" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 讨论统计卡片 -->
|
||||
<div class="statistics-card">
|
||||
<h3 class="card-title">
|
||||
<span class="title-main">讨论</span>
|
||||
<span class="title-sub">(共5个)</span>
|
||||
</h3>
|
||||
<div class="card-content">
|
||||
<!-- 左侧文本统计 -->
|
||||
<div class="text-stats">
|
||||
<div class="stat-item">
|
||||
<div class="stat-label">讨论话题</div>
|
||||
<div class="stat-value">
|
||||
<span class="stat-number">7</span>
|
||||
<span class="stat-unit">个</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<div class="stat-label">回复数量</div>
|
||||
<div class="stat-value">
|
||||
<span class="stat-number">60</span>
|
||||
<span class="stat-unit">条</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 右侧饼图 -->
|
||||
<div class="chart-section">
|
||||
<h4 class="chart-title">讨论活跃度</h4>
|
||||
<div class="chart-container">
|
||||
<v-chart :option="discussionOption" style="height: 100%;" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
console.log('LearningStatistics component loaded')
|
||||
import { ref, computed } from 'vue'
|
||||
import type { EChartsOption } from 'echarts'
|
||||
|
||||
// 选中的班级
|
||||
const selectedClass = ref('')
|
||||
|
||||
// 学习次数分布饼图配置
|
||||
const learningDistributionOption = computed<EChartsOption>(() => ({
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{a} <br/>{b}: {c} ({d}%)'
|
||||
},
|
||||
legend: {
|
||||
orient: 'vertical',
|
||||
right: 8,
|
||||
top: 'center',
|
||||
itemWidth: 8,
|
||||
itemHeight: 8,
|
||||
itemGap: 25,
|
||||
textStyle: {
|
||||
fontSize: 11,
|
||||
color: '#666'
|
||||
},
|
||||
icon: 'circle',
|
||||
formatter: function(name: string) {
|
||||
return name.replace(' ', ' ');
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '学习次数分布',
|
||||
type: 'pie',
|
||||
radius: ['70%', '85%'],
|
||||
center: ['28%', '50%'],
|
||||
avoidLabelOverlap: false,
|
||||
label: {
|
||||
show: false
|
||||
},
|
||||
emphasis: {
|
||||
label: {
|
||||
show: false,
|
||||
fontSize: '14',
|
||||
fontWeight: 'bold'
|
||||
}
|
||||
},
|
||||
labelLine: {
|
||||
show: false
|
||||
},
|
||||
data: [
|
||||
{ value: 60, name: '学习一次 60次', itemStyle: { color: '#FF9F7F' } },
|
||||
{ value: 20, name: '学习二次 20次', itemStyle: { color: '#3A8BFF' } },
|
||||
{ value: 20, name: '学习三次 20次', itemStyle: { color: '#9FE6B8' } }
|
||||
]
|
||||
}
|
||||
]
|
||||
}))
|
||||
|
||||
// 作业完成率饼图配置
|
||||
const assignmentCompletionOption = computed<EChartsOption>(() => ({
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{a} <br/>{b}: {c} ({d}%)'
|
||||
},
|
||||
legend: {
|
||||
orient: 'vertical',
|
||||
left: '53%',
|
||||
top: 'center',
|
||||
itemWidth: 8,
|
||||
itemHeight: 8,
|
||||
itemGap: 35,
|
||||
textStyle: {
|
||||
fontSize: 11,
|
||||
color: '#666'
|
||||
},
|
||||
icon: 'circle',
|
||||
formatter: function(name: string) {
|
||||
return name.replace(' ', ' ');
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '作业完成率',
|
||||
type: 'pie',
|
||||
radius: ['70%', '85%'],
|
||||
center: ['38%', '50%'],
|
||||
avoidLabelOverlap: false,
|
||||
label: {
|
||||
show: false
|
||||
},
|
||||
emphasis: {
|
||||
label: {
|
||||
show: false,
|
||||
fontSize: '14',
|
||||
fontWeight: 'bold'
|
||||
}
|
||||
},
|
||||
labelLine: {
|
||||
show: false
|
||||
},
|
||||
data: [
|
||||
{ value: 60, name: '已完成 60%', itemStyle: { color: '#0C99DA' } },
|
||||
{ value: 40, name: '未完成 40%', itemStyle: { color: '#9FE6B8' } }
|
||||
]
|
||||
}
|
||||
]
|
||||
}))
|
||||
|
||||
// 考试成绩占比饼图配置
|
||||
const examScoreOption = computed<EChartsOption>(() => ({
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{a} <br/>{b}: {c} ({d}%)'
|
||||
},
|
||||
legend: {
|
||||
orient: 'vertical',
|
||||
right: 8,
|
||||
top: 'center',
|
||||
itemWidth: 8,
|
||||
itemHeight: 8,
|
||||
itemGap: 25,
|
||||
textStyle: {
|
||||
fontSize: 11,
|
||||
color: '#666'
|
||||
},
|
||||
icon: 'circle',
|
||||
formatter: function(name: string) {
|
||||
return name.replace(' ', ' ');
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '成绩占比',
|
||||
type: 'pie',
|
||||
radius: ['70%', '85%'],
|
||||
center: ['28%', '50%'],
|
||||
avoidLabelOverlap: false,
|
||||
label: {
|
||||
show: false
|
||||
},
|
||||
emphasis: {
|
||||
label: {
|
||||
show: false,
|
||||
fontSize: '14',
|
||||
fontWeight: 'bold'
|
||||
}
|
||||
},
|
||||
labelLine: {
|
||||
show: false
|
||||
},
|
||||
data: [
|
||||
{ value: 60, name: '60分以下 60人', itemStyle: { color: '#3A8BFF' } },
|
||||
{ value: 20, name: '60-79分 20人', itemStyle: { color: '#FF9F7F' } },
|
||||
{ value: 20, name: '80分以上 20人', itemStyle: { color: '#9FE6B8' } }
|
||||
]
|
||||
}
|
||||
]
|
||||
}))
|
||||
|
||||
// 练习成绩占比饼图配置
|
||||
const practiceScoreOption = computed<EChartsOption>(() => ({
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{a} <br/>{b}: {c} ({d}%)'
|
||||
},
|
||||
legend: {
|
||||
orient: 'vertical',
|
||||
right: 8,
|
||||
top: 'center',
|
||||
itemWidth: 8,
|
||||
itemHeight: 8,
|
||||
itemGap: 25,
|
||||
textStyle: {
|
||||
fontSize: 11,
|
||||
color: '#666'
|
||||
},
|
||||
icon: 'circle',
|
||||
formatter: function(name: string) {
|
||||
return name.replace(' ', ' ');
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '成绩占比',
|
||||
type: 'pie',
|
||||
radius: ['70%', '85%'],
|
||||
center: ['28%', '50%'],
|
||||
avoidLabelOverlap: false,
|
||||
label: {
|
||||
show: false
|
||||
},
|
||||
emphasis: {
|
||||
label: {
|
||||
show: false,
|
||||
fontSize: '14',
|
||||
fontWeight: 'bold'
|
||||
}
|
||||
},
|
||||
labelLine: {
|
||||
show: false
|
||||
},
|
||||
data: [
|
||||
{ value: 60, name: '60分以下 60人', itemStyle: { color: '#3A8BFF' } },
|
||||
{ value: 20, name: '60-79分 20人', itemStyle: { color: '#FF9F7F' } },
|
||||
{ value: 20, name: '80分以上 20人', itemStyle: { color: '#9FE6B8' } }
|
||||
]
|
||||
}
|
||||
]
|
||||
}))
|
||||
|
||||
// 证书获取率饼图配置
|
||||
const certificateOption = computed<EChartsOption>(() => ({
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{a} <br/>{b}: {c} ({d}%)'
|
||||
},
|
||||
legend: {
|
||||
orient: 'vertical',
|
||||
left: '53%',
|
||||
top: 'center',
|
||||
itemWidth: 8,
|
||||
itemHeight: 8,
|
||||
itemGap: 35,
|
||||
textStyle: {
|
||||
fontSize: 11,
|
||||
color: '#666'
|
||||
},
|
||||
icon: 'circle',
|
||||
formatter: function(name: string) {
|
||||
return name.replace(' ', ' ');
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '证书获取率',
|
||||
type: 'pie',
|
||||
radius: ['70%', '85%'],
|
||||
center: ['38%', '50%'],
|
||||
avoidLabelOverlap: false,
|
||||
label: {
|
||||
show: false
|
||||
},
|
||||
emphasis: {
|
||||
label: {
|
||||
show: false,
|
||||
fontSize: '14',
|
||||
fontWeight: 'bold'
|
||||
}
|
||||
},
|
||||
labelLine: {
|
||||
show: false
|
||||
},
|
||||
data: [
|
||||
{ value: 60, name: '已获得 60%', itemStyle: { color: '#0C99DA' } },
|
||||
{ value: 40, name: '未获得 40%', itemStyle: { color: '#9FE6B8' } }
|
||||
]
|
||||
}
|
||||
]
|
||||
}))
|
||||
|
||||
// 讨论活跃度饼图配置
|
||||
const discussionOption = computed<EChartsOption>(() => ({
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{a} <br/>{b}: {c} ({d}%)'
|
||||
},
|
||||
legend: {
|
||||
orient: 'vertical',
|
||||
right: 8,
|
||||
top: 'center',
|
||||
itemWidth: 8,
|
||||
itemHeight: 8,
|
||||
itemGap: 25,
|
||||
textStyle: {
|
||||
fontSize: 11,
|
||||
color: '#666'
|
||||
},
|
||||
icon: 'circle',
|
||||
formatter: function(name: string) {
|
||||
return name.replace(' ', ' ');
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '讨论活跃度',
|
||||
type: 'pie',
|
||||
radius: ['70%', '85%'],
|
||||
center: ['28%', '50%'],
|
||||
avoidLabelOverlap: false,
|
||||
label: {
|
||||
show: false
|
||||
},
|
||||
emphasis: {
|
||||
label: {
|
||||
show: false,
|
||||
fontSize: '14',
|
||||
fontWeight: 'bold'
|
||||
}
|
||||
},
|
||||
labelLine: {
|
||||
show: false
|
||||
},
|
||||
data: [
|
||||
{ value: 40, name: '活跃 40%', itemStyle: { color: '#3A8BFF' } },
|
||||
{ value: 60, name: '一般 60%', itemStyle: { color: '#FF9F7F' } }
|
||||
]
|
||||
}
|
||||
]
|
||||
}))
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.learning-statistics {
|
||||
padding: 0 24px 24px;
|
||||
background: #fff;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
/* 班级选择器 */
|
||||
.class-selector {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.selector-container {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.class-select {
|
||||
width: 200px;
|
||||
height: 36px;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid #F1F3F4;
|
||||
border-radius: 4px;
|
||||
background: #fff;
|
||||
font-size: 14px;
|
||||
color: #062333;
|
||||
appearance: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.selector-arrow {
|
||||
position: absolute;
|
||||
right: 12px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.selector-arrow img {
|
||||
width: 14px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
/* 统计内容区域 */
|
||||
.statistics-content {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 24px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
/* 考试和练习卡片容器 */
|
||||
.exam-practice-container {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 24px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
/* 统计卡片 */
|
||||
.statistics-card {}
|
||||
|
||||
.card-title {
|
||||
color: #333;
|
||||
margin: 0 0 16px 0;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.title-main {
|
||||
font-size: 16px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.title-sub {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.card-content {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
align-items: center;
|
||||
border: 1.5px solid #E6E6E6;
|
||||
border-radius: 2px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.content-placeholder {
|
||||
text-align: center;
|
||||
padding: 40px 20px;
|
||||
/* 文本统计 */
|
||||
.text-stats {
|
||||
width: 42%;
|
||||
padding-right: 30px;
|
||||
border-right: 1.5px solid #E6E6E6;
|
||||
}
|
||||
|
||||
.content-placeholder h3 {
|
||||
.stat-item {
|
||||
margin-bottom: 8px;
|
||||
background-color: #F5F8FB;
|
||||
border-radius: 4px;
|
||||
padding: 12px 16px;
|
||||
}
|
||||
|
||||
.stat-item:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.stat-number {
|
||||
font-size: 18px;
|
||||
font-weight: normal;
|
||||
color: #333;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.content-placeholder p {
|
||||
.stat-unit {
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/* 图表区域 */
|
||||
.chart-section {
|
||||
margin-left: 10px;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.chart-section.full-width {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.chart-title {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
color: #333;
|
||||
margin-bottom: 5px;
|
||||
font-weight: 500;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.chart-container {
|
||||
height: 140px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 768px) {
|
||||
.statistics-content {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.card-content {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.chart-container {
|
||||
height: 120px;
|
||||
}
|
||||
}
|
||||
</style>
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user