feat: 添加统计首页, 基础数据,课堂报告页面
This commit is contained in:
parent
39020bd14c
commit
a0cb27afe4
@ -20,11 +20,13 @@
|
||||
"axios": "^1.11.0",
|
||||
"ckplayer": "^3.1.2",
|
||||
"dplayer": "^1.27.1",
|
||||
"echarts": "5.6.0",
|
||||
"naive-ui": "^2.42.0",
|
||||
"naive-ui-editor": "^1.0.6",
|
||||
"pinia": "^3.0.3",
|
||||
"quill": "^2.0.3",
|
||||
"vue": "^3.5.17",
|
||||
"vue-echarts": "7.0.3",
|
||||
"vue-i18n": "^9.14.5",
|
||||
"vue-quill-editor": "^3.0.6",
|
||||
"vue-router": "^4.5.1"
|
||||
|
61
pnpm-lock.yaml
generated
61
pnpm-lock.yaml
generated
@ -29,6 +29,9 @@ importers:
|
||||
dplayer:
|
||||
specifier: ^1.27.1
|
||||
version: 1.27.1
|
||||
echarts:
|
||||
specifier: 5.6.0
|
||||
version: 5.6.0
|
||||
naive-ui:
|
||||
specifier: ^2.42.0
|
||||
version: 2.42.0(vue@3.5.18(typescript@5.9.2))
|
||||
@ -44,6 +47,9 @@ importers:
|
||||
vue:
|
||||
specifier: ^3.5.17
|
||||
version: 3.5.18(typescript@5.9.2)
|
||||
vue-echarts:
|
||||
specifier: 7.0.3
|
||||
version: 7.0.3(@vue/runtime-core@3.5.18)(echarts@5.6.0)(vue@3.5.18(typescript@5.9.2))
|
||||
vue-i18n:
|
||||
specifier: ^9.14.5
|
||||
version: 9.14.5(vue@3.5.18(typescript@5.9.2))
|
||||
@ -930,6 +936,9 @@ packages:
|
||||
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
echarts@5.6.0:
|
||||
resolution: {integrity: sha512-oTbVTsXfKuEhxftHqL5xprgLoc0k7uScAwtryCgWF6hPYFLRwOUHiFmHGCBKP5NPFNkDVopOieyUqYGH8Fa3kA==}
|
||||
|
||||
electron-to-chromium@1.5.199:
|
||||
resolution: {integrity: sha512-3gl0S7zQd88kCAZRO/DnxtBKuhMO4h0EaQIN3YgZfV6+pW+5+bf2AdQeHNESCoaQqo/gjGVYEf2YM4O5HJQqpQ==}
|
||||
|
||||
@ -1478,6 +1487,9 @@ packages:
|
||||
treemate@0.3.11:
|
||||
resolution: {integrity: sha512-M8RGFoKtZ8dF+iwJfAJTOH/SM4KluKOKRJpjCMhI8bG3qB74zrFoArKZ62ll0Fr3mqkMJiQOmWYkdYgDeITYQg==}
|
||||
|
||||
tslib@2.3.0:
|
||||
resolution: {integrity: sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==}
|
||||
|
||||
type@2.7.3:
|
||||
resolution: {integrity: sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==}
|
||||
|
||||
@ -1582,6 +1594,27 @@ packages:
|
||||
vscode-uri@3.1.0:
|
||||
resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==}
|
||||
|
||||
vue-demi@0.13.11:
|
||||
resolution: {integrity: sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==}
|
||||
engines: {node: '>=12'}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
'@vue/composition-api': ^1.0.0-rc.1
|
||||
vue: ^3.0.0-0 || ^2.6.0
|
||||
peerDependenciesMeta:
|
||||
'@vue/composition-api':
|
||||
optional: true
|
||||
|
||||
vue-echarts@7.0.3:
|
||||
resolution: {integrity: sha512-/jSxNwOsw5+dYAUcwSfkLwKPuzTQ0Cepz1LxCOpj2QcHrrmUa/Ql0eQqMmc1rTPQVrh2JQ29n2dhq75ZcHvRDw==}
|
||||
peerDependencies:
|
||||
'@vue/runtime-core': ^3.0.0
|
||||
echarts: ^5.5.1
|
||||
vue: ^2.7.0 || ^3.1.1
|
||||
peerDependenciesMeta:
|
||||
'@vue/runtime-core':
|
||||
optional: true
|
||||
|
||||
vue-i18n@9.14.5:
|
||||
resolution: {integrity: sha512-0jQ9Em3ymWngyiIkj0+c/k7WgaPO+TNzjKSNq9BvBQaKJECqn9cd9fL4tkDhB5G1QBskGl9YxxbDAhgbFtpe2g==}
|
||||
engines: {node: '>= 16'}
|
||||
@ -1635,6 +1668,9 @@ packages:
|
||||
resolution: {integrity: sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
zrender@5.6.1:
|
||||
resolution: {integrity: sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag==}
|
||||
|
||||
snapshots:
|
||||
|
||||
'@ampproject/remapping@2.3.0':
|
||||
@ -2504,6 +2540,11 @@ snapshots:
|
||||
es-errors: 1.3.0
|
||||
gopd: 1.2.0
|
||||
|
||||
echarts@5.6.0:
|
||||
dependencies:
|
||||
tslib: 2.3.0
|
||||
zrender: 5.6.1
|
||||
|
||||
electron-to-chromium@1.5.199: {}
|
||||
|
||||
entities@4.5.0: {}
|
||||
@ -3061,6 +3102,8 @@ snapshots:
|
||||
|
||||
treemate@0.3.11: {}
|
||||
|
||||
tslib@2.3.0: {}
|
||||
|
||||
type@2.7.3: {}
|
||||
|
||||
typescript@5.9.2: {}
|
||||
@ -3152,6 +3195,20 @@ snapshots:
|
||||
|
||||
vscode-uri@3.1.0: {}
|
||||
|
||||
vue-demi@0.13.11(vue@3.5.18(typescript@5.9.2)):
|
||||
dependencies:
|
||||
vue: 3.5.18(typescript@5.9.2)
|
||||
|
||||
vue-echarts@7.0.3(@vue/runtime-core@3.5.18)(echarts@5.6.0)(vue@3.5.18(typescript@5.9.2)):
|
||||
dependencies:
|
||||
echarts: 5.6.0
|
||||
vue: 3.5.18(typescript@5.9.2)
|
||||
vue-demi: 0.13.11(vue@3.5.18(typescript@5.9.2))
|
||||
optionalDependencies:
|
||||
'@vue/runtime-core': 3.5.18
|
||||
transitivePeerDependencies:
|
||||
- '@vue/composition-api'
|
||||
|
||||
vue-i18n@9.14.5(vue@3.5.18(typescript@5.9.2)):
|
||||
dependencies:
|
||||
'@intlify/core-base': 9.14.5
|
||||
@ -3209,3 +3266,7 @@ snapshots:
|
||||
yallist@3.1.1: {}
|
||||
|
||||
yoctocolors@2.1.1: {}
|
||||
|
||||
zrender@5.6.1:
|
||||
dependencies:
|
||||
tslib: 2.3.0
|
||||
|
32
src/main.ts
32
src/main.ts
@ -14,6 +14,35 @@ import '@/assets/fonts/庞门正道标题体3.0.ttf'
|
||||
import '@/assets/fonts/DouyinSansBold.otf'
|
||||
import '@/assets/fonts/Alibaba_PuHuiTi_2.0_55_Regular_85_Bold.ttf'
|
||||
|
||||
// ECharts 全局注册
|
||||
import VChart from 'vue-echarts'
|
||||
import { use } from 'echarts/core'
|
||||
import { CanvasRenderer } from 'echarts/renderers'
|
||||
import { LineChart, BarChart, PieChart, ScatterChart } from 'echarts/charts'
|
||||
import {
|
||||
TitleComponent,
|
||||
TooltipComponent,
|
||||
LegendComponent,
|
||||
GridComponent,
|
||||
DataZoomComponent,
|
||||
GraphicComponent
|
||||
} from 'echarts/components'
|
||||
|
||||
// 注册 ECharts 组件
|
||||
use([
|
||||
CanvasRenderer,
|
||||
LineChart,
|
||||
BarChart,
|
||||
PieChart,
|
||||
ScatterChart,
|
||||
TitleComponent,
|
||||
TooltipComponent,
|
||||
LegendComponent,
|
||||
GridComponent,
|
||||
DataZoomComponent,
|
||||
GraphicComponent
|
||||
])
|
||||
|
||||
// Naive UI
|
||||
import {
|
||||
create,
|
||||
@ -173,6 +202,9 @@ app.use(router)
|
||||
app.use(i18n)
|
||||
app.use(naive)
|
||||
|
||||
// 全局注册 VChart 组件
|
||||
app.component('v-chart', VChart)
|
||||
|
||||
// 初始化用户认证状态
|
||||
const userStore = useUserStore()
|
||||
|
||||
|
@ -52,7 +52,7 @@ import FileViewer from '@/views/teacher/course/FileViewer.vue'
|
||||
import FolderBrowser from '@/views/teacher/course/FolderBrowser.vue'
|
||||
import CertificateManagement from '@/views/teacher/certificate/CertificateManagement.vue'
|
||||
import DiscussionManagement from '@/views/teacher/course/DiscussionManagement.vue'
|
||||
import StatisticsManagement from '@/views/teacher/course/StatisticsManagement.vue'
|
||||
import StatisticsManagement from '@/views/teacher/statistics/StatisticsManagement.vue'
|
||||
import NotificationManagement from '@/views/teacher/course/NotificationManagement.vue'
|
||||
import GeneralManagement from '@/views/teacher/course/GeneralManagement.vue'
|
||||
|
||||
|
@ -1,36 +0,0 @@
|
||||
<template>
|
||||
<div class="statistics-management">
|
||||
<div class="content-placeholder">
|
||||
<h2>统计管理</h2>
|
||||
<p>统计管理功能正在开发中...</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// 统计管理逻辑
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.statistics-management {
|
||||
padding: 20px;
|
||||
background: #fff;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.content-placeholder {
|
||||
text-align: center;
|
||||
padding: 60px 20px;
|
||||
}
|
||||
|
||||
.content-placeholder h2 {
|
||||
font-size: 24px;
|
||||
color: #333;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.content-placeholder p {
|
||||
font-size: 16px;
|
||||
color: #666;
|
||||
}
|
||||
</style>
|
432
src/views/teacher/statistics/StatisticsManagement.vue
Normal file
432
src/views/teacher/statistics/StatisticsManagement.vue
Normal file
@ -0,0 +1,432 @@
|
||||
<template>
|
||||
<div class="statistics-management">
|
||||
<!-- 顶部区域:课程信息和图表 -->
|
||||
<div class="top-section">
|
||||
<div class="statistics-container">
|
||||
<!-- 左侧课程信息面板 -->
|
||||
<div class="course-info-panel">
|
||||
<div class="course-thumbnail">
|
||||
<img src="/images/teacher/fj.png" alt="课程封面" class="thumbnail-image" />
|
||||
</div>
|
||||
<div class="course-details">
|
||||
<h3 class="course-name">课程名称课程名称课</h3>
|
||||
<div class="course-meta">
|
||||
<p class="instructor">课程讲师: 王建国</p>
|
||||
<p class="activity">学生活跃度: 74</p>
|
||||
</div>
|
||||
<button class="course-details-btn" @click="goToCourseDetails">课程详情</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧活动图表面板 -->
|
||||
<div class="activity-chart-panel">
|
||||
<h3 class="chart-title">近7日课程活跃数: 20</h3>
|
||||
<div class="chart-container">
|
||||
<v-chart :option="chartOption" autoresize style="height: 100%;" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 中间区域:标签页 -->
|
||||
<div class="middle-section">
|
||||
<div class="tab-container">
|
||||
<div class="tab-bar">
|
||||
<div
|
||||
v-for="(tab, index) in tabs"
|
||||
:key="index"
|
||||
class="tab-item"
|
||||
:class="{ active: activeTab === index }"
|
||||
@click="switchTab(index)"
|
||||
>
|
||||
<span>{{ tab.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tab内容区域 -->
|
||||
<div class="tab-content">
|
||||
<transition name="tab-fade" mode="out-in">
|
||||
<component :is="currentTabComponent" :key="activeTab" />
|
||||
</transition>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import type { EChartsOption } from 'echarts'
|
||||
|
||||
// 导入tab组件
|
||||
import BasicData from './tab/BasicData.vue'
|
||||
import ClassroomReport from './tab/ClassroomReport.vue'
|
||||
import LearningStatistics from './tab/LearningStatistics.vue'
|
||||
import StudentGrades from './tab/StudentGrades.vue'
|
||||
import LearningMonitor from './tab/LearningMonitor.vue'
|
||||
|
||||
// 路由相关
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
|
||||
// Tab相关状态
|
||||
const activeTab = ref(0)
|
||||
|
||||
// Tab配置
|
||||
const tabs = [
|
||||
{ name: '基础数据', component: BasicData },
|
||||
{ name: '课堂报告', component: ClassroomReport },
|
||||
{ name: '学情统计', component: LearningStatistics },
|
||||
{ name: '学生成绩', component: StudentGrades },
|
||||
{ name: '学习监控', component: LearningMonitor }
|
||||
]
|
||||
|
||||
// 当前显示的tab组件
|
||||
const currentTabComponent = computed(() => {
|
||||
return tabs[activeTab.value].component
|
||||
})
|
||||
|
||||
// 切换tab
|
||||
const switchTab = (index: number) => {
|
||||
activeTab.value = index
|
||||
}
|
||||
|
||||
// 跳转到教师端课程详情页面
|
||||
const goToCourseDetails = () => {
|
||||
// 获取当前课程ID(从路由参数中获取)
|
||||
const courseId = route.params.id || '1' // 如果没有ID参数,使用默认值
|
||||
router.push(`/teacher/course-detail/${courseId}`)
|
||||
}
|
||||
|
||||
// ECharts配置
|
||||
const chartOption = ref<EChartsOption>({
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'line',
|
||||
lineStyle: {
|
||||
type: 'dashed',
|
||||
color: '#ccc'
|
||||
}
|
||||
},
|
||||
formatter: function(params: any) {
|
||||
return `<div style="padding: 8px;">
|
||||
<div style="font-size: 12px; color: #999; margin-bottom: 4px;">活跃数</div>
|
||||
<div style="font-size: 16px; font-weight: bold; color: #333;">${params[0].value}</div>
|
||||
</div>`
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
left: '2%',
|
||||
right: '6%',
|
||||
bottom: '15%',
|
||||
top: '15%',
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: ['2022-04-02', '2022-04-05', '2022-04-08', '2022-04-11', '2022-04-14', '2022-04-17'],
|
||||
axisLine: {
|
||||
show: false
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#666',
|
||||
fontSize: 9,
|
||||
margin: 8
|
||||
},
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
type: 'dashed',
|
||||
color: '#f0f0f0'
|
||||
}
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
min: 0,
|
||||
max: 14000,
|
||||
interval: 2000,
|
||||
axisLine: {
|
||||
show: false
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#666',
|
||||
fontSize: 9,
|
||||
margin: 8
|
||||
},
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
type: 'dashed',
|
||||
color: '#f0f0f0'
|
||||
}
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '活跃数',
|
||||
type: 'line',
|
||||
smooth: false,
|
||||
symbol: 'none',
|
||||
lineStyle: {
|
||||
color: '#2196F3',
|
||||
width: 1.5
|
||||
},
|
||||
areaStyle: {
|
||||
color: {
|
||||
type: 'linear',
|
||||
x: 0,
|
||||
y: 0,
|
||||
x2: 0,
|
||||
y2: 1,
|
||||
colorStops: [
|
||||
{
|
||||
offset: 0,
|
||||
color: 'rgba(33, 150, 243, 0.25)'
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: 'rgba(33, 150, 243, 0.02)'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
data: [2000, 10500, 12000, 9800, 11000, 7500]
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
console.log('CourseStatistics component loaded with ECharts and Tab functionality')
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.statistics-management {
|
||||
background: #fff;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
/* 顶部区域 */
|
||||
.top-section {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.statistics-container {
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 20px;
|
||||
margin: 0 auto;
|
||||
border-bottom: 1.5px solid #F1F3F4;
|
||||
}
|
||||
|
||||
/* 调整左右面板比例:左侧75%,右侧25% */
|
||||
.course-info-panel {
|
||||
flex: 0 0 60%;
|
||||
background: white;
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.activity-chart-panel {
|
||||
flex: 0 0 30%;
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
padding: 8px;
|
||||
/* 从12px减少到8px */
|
||||
}
|
||||
|
||||
/* 左侧课程信息面板样式 */
|
||||
|
||||
.course-thumbnail {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.thumbnail-image {
|
||||
width: 194px;
|
||||
height: 136px;
|
||||
object-fit: cover;
|
||||
background: linear-gradient(135deg, #4CAF50, #8BC34A, #FFEB3B);
|
||||
}
|
||||
|
||||
.course-details {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.course-name {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
margin: 0;
|
||||
line-height: 1.3;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.course-meta {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.instructor,
|
||||
.activity {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
line-height: 1.3;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.course-details-btn {
|
||||
background-color: #fff;
|
||||
align-self: flex-start;
|
||||
border: 1.5px solid #0C99DA;
|
||||
color: #0C99DA;
|
||||
padding: 6px 12px;
|
||||
border-radius: 2px;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.course-details-btn:hover {
|
||||
background: #BBDEFB;
|
||||
border-color: #1976D2;
|
||||
color: #1976D2;
|
||||
}
|
||||
|
||||
/* 右侧活动图表面板样式 */
|
||||
|
||||
.chart-title {
|
||||
padding-left: 40px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #666;
|
||||
margin: 0 0 16px 0;
|
||||
}
|
||||
|
||||
.chart-container {
|
||||
position: relative;
|
||||
height: 120px;
|
||||
/* 从160px减少到120px */
|
||||
}
|
||||
|
||||
/* ECharts容器样式 */
|
||||
.chart-container :deep(.echarts) {
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
}
|
||||
|
||||
/* 中间区域:标签页 */
|
||||
.middle-section {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.tab-container {
|
||||
display: flex;
|
||||
border-bottom: 1.5px solid #F1F3F4;
|
||||
padding-bottom: 24px;
|
||||
}
|
||||
|
||||
.tab-bar {
|
||||
display: flex;
|
||||
background: white;
|
||||
border: 1.5px solid #0C99DA;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
.tab-item {
|
||||
min-width: 151px;
|
||||
flex: 1;
|
||||
padding: 5px 10px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
text-align: center;
|
||||
background: white;
|
||||
color: #2196F3;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
border-right: 1.5px solid #0C99DA;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tab-item:last-child {
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.tab-item.active {
|
||||
background: #0C99DA;
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.tab-item:hover:not(.active) {
|
||||
background: #F5F9FF;
|
||||
color: #1976D2;
|
||||
}
|
||||
|
||||
/* Tab内容区域 */
|
||||
.tab-content {
|
||||
background: white;
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
/* Tab切换过渡动画 */
|
||||
.tab-fade-enter-active,
|
||||
.tab-fade-leave-active {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.tab-fade-enter-from {
|
||||
opacity: 0;
|
||||
transform: translateX(20px);
|
||||
}
|
||||
|
||||
.tab-fade-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateX(-20px);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 768px) {
|
||||
.statistics-container {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.course-info-panel {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.course-details-btn {
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.tab-bar {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.tab-item {
|
||||
flex: none;
|
||||
min-width: 120px;
|
||||
}
|
||||
}
|
||||
</style>
|
295
src/views/teacher/statistics/tab/BasicData.vue
Normal file
295
src/views/teacher/statistics/tab/BasicData.vue
Normal file
@ -0,0 +1,295 @@
|
||||
<template>
|
||||
<div class="basic-data">
|
||||
<!-- 顶部统计卡片区域 -->
|
||||
<div class="stats-cards">
|
||||
<div class="stats-row">
|
||||
<div class="stat-card">
|
||||
<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-card">
|
||||
<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-card">
|
||||
<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-card">
|
||||
<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-card">
|
||||
<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-card">
|
||||
<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-card">
|
||||
<div class="stat-label">证书</div>
|
||||
<div class="stat-value">
|
||||
<span class="stat-number">0</span>
|
||||
<span class="stat-unit">个</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 教学建设区域 -->
|
||||
<div class="teaching-construction">
|
||||
<h3 class="section-title">教学建设</h3>
|
||||
<div class="construction-grid">
|
||||
<!-- 课件/视频 -->
|
||||
<div class="construction-card blue" style="background-image: url('/images/teacher/teaching-construction1.png');">
|
||||
<div class="card-icon">
|
||||
<img src="/images/teacher/teaching-construction1.png" alt="课件/视频" />
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<div class="card-number">20</div>
|
||||
<div class="card-label">课件/视频</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 资料/文档 -->
|
||||
<div class="construction-card orange" style="background-image: url('/images/teacher/teaching-construction2.png');">
|
||||
<div class="card-icon">
|
||||
<img src="/images/teacher/teaching-construction2.png" alt="资料/文档" />
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<div class="card-number">139</div>
|
||||
<div class="card-label">资料/文档</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 题库总数 -->
|
||||
<div class="construction-card blue-gray" style="background-image: url('/images/teacher/teaching-construction3.png');">
|
||||
<div class="card-icon">
|
||||
<img src="/images/teacher/teaching-construction3.png" alt="题库总数" />
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<div class="card-number">862</div>
|
||||
<div class="card-label">题库总数</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 试卷总数 -->
|
||||
<div class="construction-card yellow" style="background-image: url('/images/teacher/teaching-construction4.png');">
|
||||
<div class="card-icon">
|
||||
<img src="/images/teacher/teaching-construction4.png" alt="试卷总数" />
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<div class="card-number">10</div>
|
||||
<div class="card-label">试卷总数</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
console.log('BasicData component loaded')
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.basic-data {
|
||||
padding: 0 30px;
|
||||
}
|
||||
|
||||
/* 顶部统计卡片区域 */
|
||||
.stats-cards {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.stats-row {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
justify-content: space-between;
|
||||
border: 1px solid #F1F3F4;
|
||||
background-color: #FCFCFC;
|
||||
border-radius: 2px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
min-height: 80px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 12px;
|
||||
color: #999999;
|
||||
margin-bottom: 8px;
|
||||
line-height: 1.2;
|
||||
white-space: nowrap;
|
||||
width: 50px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 2px;
|
||||
line-height: 1.2;
|
||||
white-space: nowrap;
|
||||
width: 50px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.stat-number {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.stat-unit {
|
||||
font-size: 10px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
/* 教学建设区域 */
|
||||
.teaching-construction {
|
||||
margin-top: 26px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
margin: 0 0 12px 0;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.construction-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 30px;
|
||||
}
|
||||
|
||||
.construction-card {
|
||||
background: white;
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
border-radius: 2px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 24px;
|
||||
transition: transform 0.3s ease;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
min-height: 95px;
|
||||
padding: 40px;
|
||||
}
|
||||
|
||||
.construction-card:hover {
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.card-icon {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.card-icon img {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
filter: brightness(0) invert(1); /* 使图标变为白色 */
|
||||
}
|
||||
|
||||
.card-content {
|
||||
text-align: left;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.card-number {
|
||||
font-size: 22px;
|
||||
font-weight: 500;
|
||||
color: #646464;
|
||||
margin-bottom: 10px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.card-label {
|
||||
font-size: 14px;
|
||||
color: #646464;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* 卡片颜色主题 */
|
||||
.construction-card.blue .card-icon {
|
||||
background: #2196F3;
|
||||
}
|
||||
|
||||
.construction-card.orange .card-icon {
|
||||
background: #FF9800;
|
||||
}
|
||||
|
||||
.construction-card.blue-gray .card-icon {
|
||||
background: #607D8B;
|
||||
}
|
||||
|
||||
.construction-card.yellow .card-icon {
|
||||
background: #FFC107;
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 768px) {
|
||||
.stats-row {
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
flex: 1 1 calc(50% - 6px);
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
.construction-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.stat-card {
|
||||
flex: 1 1 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
429
src/views/teacher/statistics/tab/ClassroomReport.vue
Normal file
429
src/views/teacher/statistics/tab/ClassroomReport.vue
Normal file
@ -0,0 +1,429 @@
|
||||
<template>
|
||||
<div class="classroom-report">
|
||||
<!-- 课程访问量图表 -->
|
||||
<div class="chart-section">
|
||||
<div class="chart-header">
|
||||
<h3 class="chart-title">课程访问量</h3>
|
||||
<div class="time-selector">
|
||||
<span
|
||||
class="time-option"
|
||||
:class="{ active: visitVolumeTimeRange === 'week' }"
|
||||
@click="switchVisitVolumeTimeRange('week')"
|
||||
>
|
||||
本周
|
||||
</span>
|
||||
<span
|
||||
class="time-option"
|
||||
:class="{ active: visitVolumeTimeRange === 'month' }"
|
||||
@click="switchVisitVolumeTimeRange('month')"
|
||||
>
|
||||
本月
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chart-container">
|
||||
<v-chart :option="visitVolumeOption" style="height: 100%;" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 课程互动图表 -->
|
||||
<div class="chart-section">
|
||||
<div class="chart-header chart-header2">
|
||||
<h3 class="chart-title">课程互动</h3>
|
||||
<div class="time-selector">
|
||||
<span
|
||||
class="time-option"
|
||||
:class="{ active: interactionTimeRange === 'week' }"
|
||||
@click="switchInteractionTimeRange('week')"
|
||||
>
|
||||
本周
|
||||
</span>
|
||||
<span
|
||||
class="time-option"
|
||||
:class="{ active: interactionTimeRange === 'month' }"
|
||||
@click="switchInteractionTimeRange('month')"
|
||||
>
|
||||
本月
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chart-wrapper">
|
||||
<div class="chart-legend">
|
||||
<div class="legend-item">
|
||||
<div class="legend-color" style="background-color: #81A2FF;"></div>
|
||||
<span>评论</span>
|
||||
</div>
|
||||
<div class="legend-item">
|
||||
<div class="legend-color" style="background-color: #3DC8F4;"></div>
|
||||
<span>弹幕</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chart-container">
|
||||
<v-chart :option="interactionOption" style="height: 100%;" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
import type { EChartsOption } from 'echarts'
|
||||
|
||||
// 时间范围选择
|
||||
const visitVolumeTimeRange = ref<'week' | 'month'>('week')
|
||||
const interactionTimeRange = ref<'week' | 'month'>('week')
|
||||
|
||||
const switchVisitVolumeTimeRange = (range: 'week' | 'month') => {
|
||||
visitVolumeTimeRange.value = range
|
||||
}
|
||||
|
||||
const switchInteractionTimeRange = (range: 'week' | 'month') => {
|
||||
interactionTimeRange.value = range
|
||||
}
|
||||
|
||||
// 模拟数据
|
||||
const weekData = {
|
||||
dates: ['7.11', '7.12', '7.13', '7.14', '7.15', '7.16', '7.18'],
|
||||
visitVolume: [280, 390, 180, 300, 130, 380, 250],
|
||||
comments: [240, 420, 260, 390, 240, 370, 220],
|
||||
bulletComments: [160, 300, 120, 200, 180, 280, 180]
|
||||
}
|
||||
|
||||
const monthData = {
|
||||
dates: ['7.1', '7.5', '7.10', '7.15', '7.20', '7.25', '7.30'],
|
||||
visitVolume: [200, 350, 280, 400, 320, 380, 300],
|
||||
comments: [180, 320, 250, 380, 300, 350, 280],
|
||||
bulletComments: [120, 250, 180, 280, 220, 300, 200]
|
||||
}
|
||||
|
||||
// 当前数据
|
||||
const visitVolumeData = computed(() => {
|
||||
return visitVolumeTimeRange.value === 'week' ? weekData : monthData
|
||||
})
|
||||
|
||||
const interactionData = computed(() => {
|
||||
return interactionTimeRange.value === 'week' ? weekData : monthData
|
||||
})
|
||||
|
||||
// 课程访问量图表配置(柱状图)
|
||||
const visitVolumeOption = computed<EChartsOption>(() => ({
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow'
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
left: '2%',
|
||||
right: '1%',
|
||||
top: '14%',
|
||||
bottom: '6%',
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: visitVolumeData.value.dates,
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#C0CEE7'
|
||||
}
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#BDC6D8',
|
||||
fontSize: 12
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
max: 400,
|
||||
interval: 100,
|
||||
axisLine: {
|
||||
show: false
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#BDC6D8',
|
||||
fontSize: 12
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: '#F5F5F5',
|
||||
type: 'dashed'
|
||||
}
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '背景',
|
||||
type: 'bar',
|
||||
data: [400, 400, 400, 400, 400, 400, 400],
|
||||
itemStyle: {
|
||||
color: '#F8F8FC'
|
||||
},
|
||||
barWidth: '8px',
|
||||
barGap: '-100%',
|
||||
silent: true
|
||||
},
|
||||
{
|
||||
name: '访问量',
|
||||
type: 'bar',
|
||||
data: visitVolumeData.value.visitVolume,
|
||||
itemStyle: {
|
||||
color: {
|
||||
type: 'linear',
|
||||
x: 0,
|
||||
y: 0,
|
||||
x2: 0,
|
||||
y2: 1,
|
||||
colorStops: [
|
||||
{ offset: 0, color: '#39E7E8' },
|
||||
{ offset: 1, color: '#0288D1' }
|
||||
]
|
||||
}
|
||||
},
|
||||
barWidth: '8px',
|
||||
emphasis: {
|
||||
itemStyle: {
|
||||
color: {
|
||||
type: 'linear',
|
||||
x: 0,
|
||||
y: 0,
|
||||
x2: 0,
|
||||
y2: 1,
|
||||
colorStops: [
|
||||
{ offset: 0, color: '#4FE8E9' },
|
||||
{ offset: 1, color: '#039BE5' }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}))
|
||||
|
||||
// 课程互动图表配置(面积图)
|
||||
const interactionOption = computed<EChartsOption>(() => ({
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'line'
|
||||
}
|
||||
},
|
||||
|
||||
grid: {
|
||||
left: '2%',
|
||||
right: '1%',
|
||||
bottom: '8%',
|
||||
top: '12%',
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: interactionData.value.dates,
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#C0CEE7'
|
||||
}
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#BDC6D8',
|
||||
fontSize: 12
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
max: 500,
|
||||
interval: 100,
|
||||
axisLine: {
|
||||
show: false
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#BDC6D8',
|
||||
fontSize: 12
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: '#F5F5F5',
|
||||
type: 'dashed'
|
||||
}
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '评论',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
data: interactionData.value.comments,
|
||||
lineStyle: {
|
||||
color: '#81A2FF',
|
||||
width: 2
|
||||
},
|
||||
areaStyle: {
|
||||
color: {
|
||||
type: 'linear',
|
||||
x: 0,
|
||||
y: 0,
|
||||
x2: 0,
|
||||
y2: 1,
|
||||
colorStops: [
|
||||
{ offset: 0, color: 'rgba(129, 162, 255, 0.3)' },
|
||||
{ offset: 1, color: 'rgba(129, 162, 255, 0.05)' }
|
||||
]
|
||||
}
|
||||
},
|
||||
itemStyle: {
|
||||
color: '#81A2FF'
|
||||
},
|
||||
symbol: 'none'
|
||||
},
|
||||
{
|
||||
name: '弹幕',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
data: interactionData.value.bulletComments,
|
||||
lineStyle: {
|
||||
color: '#3DC8F4',
|
||||
width: 2
|
||||
},
|
||||
areaStyle: {
|
||||
color: {
|
||||
type: 'linear',
|
||||
x: 0,
|
||||
y: 0,
|
||||
x2: 0,
|
||||
y2: 1,
|
||||
colorStops: [
|
||||
{ offset: 0, color: 'rgba(61, 200, 244, 0.2)' },
|
||||
{ offset: 1, color: 'rgba(61, 200, 244, 0.02)' }
|
||||
]
|
||||
}
|
||||
},
|
||||
itemStyle: {
|
||||
color: '#3DC8F4'
|
||||
},
|
||||
symbol: 'none'
|
||||
}
|
||||
]
|
||||
}))
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.classroom-report {
|
||||
padding: 0 30px 20px;
|
||||
}
|
||||
|
||||
.chart-section {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.chart-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.chart-header2 {
|
||||
margin-bottom: 35px;
|
||||
}
|
||||
|
||||
.chart-title {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.time-selector {
|
||||
display: flex;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.time-option {
|
||||
padding: 6px 16px;
|
||||
font-size: 16px;
|
||||
color: #333333;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.time-option.active {
|
||||
color: #0C99DA;
|
||||
}
|
||||
|
||||
.time-option:hover:not(.active) {
|
||||
background: #E3F2FD;
|
||||
color: #1976D2;
|
||||
}
|
||||
|
||||
.chart-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.chart-legend {
|
||||
position: absolute;
|
||||
top: -30px;
|
||||
left: 0;
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.legend-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.legend-color {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.chart-container {
|
||||
width: 100%;
|
||||
height: 210px;
|
||||
border: 1px solid #E6E6E6;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 768px) {
|
||||
.classroom-report {
|
||||
padding: 0 16px;
|
||||
}
|
||||
|
||||
.chart-section {
|
||||
padding: 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.chart-header {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.time-selector {
|
||||
align-self: flex-end;
|
||||
}
|
||||
}
|
||||
</style>
|
34
src/views/teacher/statistics/tab/LearningMonitor.vue
Normal file
34
src/views/teacher/statistics/tab/LearningMonitor.vue
Normal file
@ -0,0 +1,34 @@
|
||||
<template>
|
||||
<div class="learning-monitor">
|
||||
<div class="content-placeholder">
|
||||
<h3>学习监控</h3>
|
||||
<p>学习监控功能正在开发中...</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
console.log('LearningMonitor component loaded')
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.learning-monitor {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.content-placeholder {
|
||||
text-align: center;
|
||||
padding: 40px 20px;
|
||||
}
|
||||
|
||||
.content-placeholder h3 {
|
||||
font-size: 18px;
|
||||
color: #333;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.content-placeholder p {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
</style>
|
34
src/views/teacher/statistics/tab/LearningStatistics.vue
Normal file
34
src/views/teacher/statistics/tab/LearningStatistics.vue
Normal file
@ -0,0 +1,34 @@
|
||||
<template>
|
||||
<div class="learning-statistics">
|
||||
<div class="content-placeholder">
|
||||
<h3>学情统计</h3>
|
||||
<p>学情统计功能正在开发中...</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
console.log('LearningStatistics component loaded')
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.learning-statistics {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.content-placeholder {
|
||||
text-align: center;
|
||||
padding: 40px 20px;
|
||||
}
|
||||
|
||||
.content-placeholder h3 {
|
||||
font-size: 18px;
|
||||
color: #333;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.content-placeholder p {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
</style>
|
34
src/views/teacher/statistics/tab/StudentGrades.vue
Normal file
34
src/views/teacher/statistics/tab/StudentGrades.vue
Normal file
@ -0,0 +1,34 @@
|
||||
<template>
|
||||
<div class="student-grades">
|
||||
<div class="content-placeholder">
|
||||
<h3>学生成绩</h3>
|
||||
<p>学生成绩功能正在开发中...</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
console.log('StudentGrades component loaded')
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.student-grades {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.content-placeholder {
|
||||
text-align: center;
|
||||
padding: 40px 20px;
|
||||
}
|
||||
|
||||
.content-placeholder h3 {
|
||||
font-size: 18px;
|
||||
color: #333;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.content-placeholder p {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
</style>
|
Loading…
x
Reference in New Issue
Block a user