2026-01-29 18:29:34 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<view class="student-stats-container">
|
|
|
|
|
|
<!-- 页面标题 -->
|
|
|
|
|
|
<view class="page-header">
|
|
|
|
|
|
<view class="header-left" @click="goBack">
|
|
|
|
|
|
<view class="back-icon">←</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="header-title">学员学情统计</view>
|
|
|
|
|
|
<view class="header-right" @click="exportData">
|
|
|
|
|
|
<view class="export-btn">导出</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 筛选条件 -->
|
|
|
|
|
|
<view class="filter-section">
|
|
|
|
|
|
<view class="filter-row">
|
|
|
|
|
|
<view class="filter-item">
|
|
|
|
|
|
<view class="filter-label">时间范围</view>
|
|
|
|
|
|
<view class="filter-control">
|
|
|
|
|
|
<picker
|
|
|
|
|
|
:range="dateOptions"
|
|
|
|
|
|
:value="dateIndex"
|
|
|
|
|
|
@change="onDateChange"
|
|
|
|
|
|
class="picker"
|
|
|
|
|
|
>
|
|
|
|
|
|
<view class="picker-text">{{ dateOptions[dateIndex] }}</view>
|
|
|
|
|
|
</picker>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="filter-item">
|
|
|
|
|
|
<view class="filter-label">班级</view>
|
|
|
|
|
|
<view class="filter-control">
|
|
|
|
|
|
<picker
|
|
|
|
|
|
:range="classOptions"
|
|
|
|
|
|
:value="classIndex"
|
|
|
|
|
|
@change="onClassChange"
|
|
|
|
|
|
class="picker"
|
|
|
|
|
|
>
|
|
|
|
|
|
<view class="picker-text">{{ classOptions[classIndex] }}</view>
|
|
|
|
|
|
</picker>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 核心指标 -->
|
|
|
|
|
|
<view class="metrics-section">
|
|
|
|
|
|
<view class="metrics-grid">
|
|
|
|
|
|
<view class="metric-card">
|
|
|
|
|
|
<view class="metric-icon">🎓</view>
|
|
|
|
|
|
<view class="metric-content">
|
|
|
|
|
|
<view class="metric-value">{{ metrics.totalStudents }}</view>
|
|
|
|
|
|
<view class="metric-label">总学员数</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="metric-card">
|
|
|
|
|
|
<view class="metric-icon">👥</view>
|
|
|
|
|
|
<view class="metric-content">
|
|
|
|
|
|
<view class="metric-value">{{ metrics.memberStudents }}</view>
|
|
|
|
|
|
<view class="metric-label">会员学员</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="metric-card">
|
|
|
|
|
|
<view class="metric-icon">📊</view>
|
|
|
|
|
|
<view class="metric-content">
|
|
|
|
|
|
<view class="metric-value">{{ metrics.avgCorrectRate }}</view>
|
|
|
|
|
|
<view class="metric-label">平均正确率</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="metric-card">
|
|
|
|
|
|
<view class="metric-icon">✏️</view>
|
|
|
|
|
|
<view class="metric-content">
|
|
|
|
|
|
<view class="metric-value">{{ metrics.avgExamScore }}</view>
|
|
|
|
|
|
<view class="metric-label">平均模考分</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 学习趋势 -->
|
|
|
|
|
|
<view class="chart-section">
|
|
|
|
|
|
<view class="section-title">学习趋势</view>
|
|
|
|
|
|
<view class="chart-container">
|
|
|
|
|
|
<!-- 模拟图表,实际项目中应使用图表库 -->
|
|
|
|
|
|
<view class="mock-chart">
|
|
|
|
|
|
<view class="chart-header">
|
|
|
|
|
|
<view class="chart-title">近30天学习时长趋势</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="chart-body">
|
|
|
|
|
|
<view class="chart-bars">
|
|
|
|
|
|
<view v-for="(day, index) in trendData" :key="index" class="chart-bar">
|
|
|
|
|
|
<view class="bar-container">
|
|
|
|
|
|
<view class="bar" :style="{ height: day.value + '%' }"></view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="bar-label">{{ day.date }}</view>
|
|
|
|
|
|
<view class="bar-value">{{ day.hours }}h</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 学习情况分布 -->
|
|
|
|
|
|
<view class="distribution-section">
|
|
|
|
|
|
<view class="section-title">学习情况分布</view>
|
|
|
|
|
|
<view class="distribution-grid">
|
|
|
|
|
|
<view
|
|
|
|
|
|
v-for="(item, index) in learningDistribution"
|
|
|
|
|
|
:key="index"
|
|
|
|
|
|
class="distribution-card"
|
|
|
|
|
|
>
|
|
|
|
|
|
<view class="distribution-icon">{{ item.icon }}</view>
|
|
|
|
|
|
<view class="distribution-content">
|
|
|
|
|
|
<view class="distribution-title">{{ item.level }}</view>
|
|
|
|
|
|
<view class="distribution-stats">
|
|
|
|
|
|
<view class="stat-item">
|
|
|
|
|
|
<view class="stat-label">人数:</view>
|
|
|
|
|
|
<view class="stat-value">{{ item.count }}</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="stat-item">
|
|
|
|
|
|
<view class="stat-label">占比:</view>
|
|
|
|
|
|
<view class="stat-value">{{ item.percentage }}</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 学员列表 -->
|
|
|
|
|
|
<view class="student-section">
|
|
|
|
|
|
<view class="section-title">学员列表</view>
|
|
|
|
|
|
<view class="student-list">
|
|
|
|
|
|
<view
|
|
|
|
|
|
v-for="(student, index) in studentList"
|
|
|
|
|
|
:key="index"
|
|
|
|
|
|
class="student-item"
|
|
|
|
|
|
@click="viewStudentDetail(student.id)"
|
|
|
|
|
|
>
|
|
|
|
|
|
<view class="student-info">
|
|
|
|
|
|
<view class="student-name">{{ student.name }}</view>
|
|
|
|
|
|
<view class="student-meta">
|
|
|
|
|
|
<view class="meta-item">
|
|
|
|
|
|
<view class="meta-label">班级:</view>
|
|
|
|
|
|
<view class="meta-value">{{ student.class }}</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="meta-item">
|
|
|
|
|
|
<view class="meta-label">会员:</view>
|
|
|
|
|
|
<view class="meta-value" :class="{ 'member': student.isMember }">{{ student.isMember ? '是' : '否' }}</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="student-stats">
|
|
|
|
|
|
<view class="stat-item">
|
|
|
|
|
|
<view class="stat-label">正确率:</view>
|
|
|
|
|
|
<view class="stat-value">{{ student.correctRate }}</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="stat-item">
|
|
|
|
|
|
<view class="stat-label">模考分:</view>
|
|
|
|
|
|
<view class="stat-value">{{ student.examScore }}</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="student-arrow">
|
|
|
|
|
|
→
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="load-more" @click="loadMoreStudents">
|
|
|
|
|
|
加载更多
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup>
|
|
|
|
|
|
import { ref, onMounted } from "vue"
|
|
|
|
|
|
|
|
|
|
|
|
// 筛选条件
|
|
|
|
|
|
const dateOptions = ['近7天', '近30天', '近90天', '今年', '全部']
|
|
|
|
|
|
const dateIndex = ref(0)
|
|
|
|
|
|
|
|
|
|
|
|
const classOptions = ['全部班级', '一班', '二班', '三班', '四班']
|
|
|
|
|
|
const classIndex = ref(0)
|
|
|
|
|
|
|
|
|
|
|
|
// 核心指标
|
|
|
|
|
|
const metrics = ref({
|
|
|
|
|
|
totalStudents: 1234,
|
|
|
|
|
|
memberStudents: 890,
|
|
|
|
|
|
avgCorrectRate: '78.5%',
|
|
|
|
|
|
avgExamScore: '82.3'
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 学习趋势数据
|
|
|
|
|
|
const trendData = ref([
|
|
|
|
|
|
{ date: '1/20', hours: 2.5, value: 30 },
|
|
|
|
|
|
{ date: '1/21', hours: 3.2, value: 40 },
|
|
|
|
|
|
{ date: '1/22', hours: 2.8, value: 35 },
|
|
|
|
|
|
{ date: '1/23', hours: 4.5, value: 60 },
|
|
|
|
|
|
{ date: '1/24', hours: 3.8, value: 50 },
|
|
|
|
|
|
{ date: '1/25', hours: 4.2, value: 55 },
|
|
|
|
|
|
{ date: '1/26', hours: 3.5, value: 45 }
|
|
|
|
|
|
])
|
|
|
|
|
|
|
|
|
|
|
|
// 学习情况分布
|
|
|
|
|
|
const learningDistribution = ref([
|
|
|
|
|
|
{
|
|
|
|
|
|
level: '优秀',
|
|
|
|
|
|
icon: '🏆',
|
|
|
|
|
|
count: 345,
|
|
|
|
|
|
percentage: '28.0%'
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
level: '良好',
|
|
|
|
|
|
icon: '📈',
|
|
|
|
|
|
count: 456,
|
|
|
|
|
|
percentage: '37.0%'
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
level: '一般',
|
|
|
|
|
|
icon: '📊',
|
|
|
|
|
|
count: 321,
|
|
|
|
|
|
percentage: '26.0%'
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
level: '待提高',
|
|
|
|
|
|
icon: '⚠️',
|
|
|
|
|
|
count: 112,
|
|
|
|
|
|
percentage: '9.0%'
|
|
|
|
|
|
}
|
|
|
|
|
|
])
|
|
|
|
|
|
|
|
|
|
|
|
// 学员列表
|
|
|
|
|
|
const studentList = ref([
|
|
|
|
|
|
{
|
|
|
|
|
|
id: 1,
|
|
|
|
|
|
name: '张**',
|
|
|
|
|
|
class: '一班',
|
|
|
|
|
|
isMember: true,
|
|
|
|
|
|
correctRate: '92.5%',
|
|
|
|
|
|
examScore: '95'
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
id: 2,
|
|
|
|
|
|
name: '李**',
|
|
|
|
|
|
class: '二班',
|
|
|
|
|
|
isMember: true,
|
|
|
|
|
|
correctRate: '88.2%',
|
|
|
|
|
|
examScore: '90'
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
id: 3,
|
|
|
|
|
|
name: '王**',
|
|
|
|
|
|
class: '一班',
|
|
|
|
|
|
isMember: false,
|
|
|
|
|
|
correctRate: '76.8%',
|
|
|
|
|
|
examScore: '82'
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
id: 4,
|
|
|
|
|
|
name: '刘**',
|
|
|
|
|
|
class: '三班',
|
|
|
|
|
|
isMember: true,
|
|
|
|
|
|
correctRate: '94.3%',
|
|
|
|
|
|
examScore: '97'
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
id: 5,
|
|
|
|
|
|
name: '陈**',
|
|
|
|
|
|
class: '二班',
|
|
|
|
|
|
isMember: false,
|
|
|
|
|
|
correctRate: '72.1%',
|
|
|
|
|
|
examScore: '78'
|
|
|
|
|
|
}
|
|
|
|
|
|
])
|
|
|
|
|
|
|
|
|
|
|
|
// 返回上一页
|
|
|
|
|
|
function goBack() {
|
|
|
|
|
|
uni.navigateBack({ delta: 1 })
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 导出数据
|
|
|
|
|
|
function exportData() {
|
|
|
|
|
|
uni.showModal({
|
|
|
|
|
|
title: '导出数据',
|
|
|
|
|
|
content: '是否导出当前统计数据?',
|
|
|
|
|
|
success: function(res) {
|
|
|
|
|
|
if (res.confirm) {
|
|
|
|
|
|
uni.showLoading({ title: '导出中...' })
|
|
|
|
|
|
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
uni.hideLoading()
|
|
|
|
|
|
uni.showToast({ title: '导出成功', icon: 'success' })
|
|
|
|
|
|
}, 1500)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 日期变化
|
|
|
|
|
|
function onDateChange(e) {
|
|
|
|
|
|
const value = e.detail.value
|
|
|
|
|
|
dateIndex.value = value
|
|
|
|
|
|
// 实际项目中应根据选择的日期重新获取数据
|
|
|
|
|
|
refreshData()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 班级变化
|
|
|
|
|
|
function onClassChange(e) {
|
|
|
|
|
|
const value = e.detail.value
|
|
|
|
|
|
classIndex.value = value
|
|
|
|
|
|
// 实际项目中应根据选择的班级重新获取数据
|
|
|
|
|
|
refreshData()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 刷新数据
|
|
|
|
|
|
function refreshData() {
|
|
|
|
|
|
uni.showLoading({ title: '加载中...' })
|
|
|
|
|
|
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
uni.hideLoading()
|
|
|
|
|
|
// 实际项目中应从接口获取数据
|
|
|
|
|
|
}, 1000)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 查看学员详情
|
|
|
|
|
|
function viewStudentDetail(studentId) {
|
|
|
|
|
|
uni.navigateTo({
|
|
|
|
|
|
url: `/pages/student/detail?id=${studentId}`
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 加载更多学员
|
|
|
|
|
|
function loadMoreStudents() {
|
|
|
|
|
|
uni.showLoading({ title: '加载中...' })
|
|
|
|
|
|
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
uni.hideLoading()
|
|
|
|
|
|
// 实际项目中应从接口获取更多学员数据
|
|
|
|
|
|
uni.showToast({ title: '已加载全部数据', icon: 'none' })
|
|
|
|
|
|
}, 1000)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
|
// 实际项目中应从接口获取数据
|
|
|
|
|
|
// loadStatsData()
|
|
|
|
|
|
})
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
|
/* #ifndef APP-NVUE */
|
|
|
|
|
|
page {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
|
background-color: #f5f7fa;
|
|
|
|
|
|
min-height: 100%;
|
|
|
|
|
|
height: auto;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
view {
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
line-height: inherit;
|
|
|
|
|
|
}
|
|
|
|
|
|
/* #endif */
|
|
|
|
|
|
|
|
|
|
|
|
.student-stats-container {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 页面头部 */
|
|
|
|
|
|
.page-header {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
height: 120rpx;
|
|
|
|
|
|
background-color: #fff;
|
|
|
|
|
|
padding: 0 32rpx;
|
|
|
|
|
|
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.header-left {
|
|
|
|
|
|
width: 60rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.back-icon {
|
|
|
|
|
|
font-size: 40rpx;
|
|
|
|
|
|
color: #303133;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.header-title {
|
|
|
|
|
|
font-size: 32rpx;
|
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
|
color: #303133;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.header-right {
|
|
|
|
|
|
width: 60rpx;
|
|
|
|
|
|
text-align: right;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.export-btn {
|
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
color: #409eff;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 筛选条件 */
|
|
|
|
|
|
.filter-section {
|
|
|
|
|
|
padding: 24rpx 32rpx;
|
|
|
|
|
|
background-color: #fff;
|
|
|
|
|
|
margin: 16rpx;
|
|
|
|
|
|
border-radius: 16rpx;
|
|
|
|
|
|
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.filter-row {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
gap: 16rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.filter-item {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.filter-label {
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
color: #606266;
|
|
|
|
|
|
margin-bottom: 8rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.filter-control {
|
|
|
|
|
|
background-color: #f9f9f9;
|
|
|
|
|
|
border: 1rpx solid #dcdfe6;
|
|
|
|
|
|
border-radius: 8rpx;
|
|
|
|
|
|
padding: 16rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.picker {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.picker-text {
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
color: #303133;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 核心指标 */
|
|
|
|
|
|
.metrics-section {
|
|
|
|
|
|
padding: 32rpx;
|
|
|
|
|
|
background-color: #fff;
|
|
|
|
|
|
margin: 0 16rpx 16rpx;
|
|
|
|
|
|
border-radius: 16rpx;
|
|
|
|
|
|
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.metrics-grid {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
grid-template-columns: repeat(2, 1fr);
|
|
|
|
|
|
gap: 16rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.metric-card {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
padding: 24rpx;
|
|
|
|
|
|
background-color: #f9f9f9;
|
|
|
|
|
|
border-radius: 12rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.metric-icon {
|
|
|
|
|
|
font-size: 48rpx;
|
|
|
|
|
|
margin-right: 24rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.metric-content {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.metric-value {
|
|
|
|
|
|
font-size: 32rpx;
|
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
|
color: #303133;
|
|
|
|
|
|
margin-bottom: 8rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.metric-label {
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
color: #606266;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 图表区域 */
|
|
|
|
|
|
.chart-section {
|
|
|
|
|
|
padding: 32rpx;
|
|
|
|
|
|
background-color: #fff;
|
|
|
|
|
|
margin: 0 16rpx 16rpx;
|
|
|
|
|
|
border-radius: 16rpx;
|
|
|
|
|
|
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.section-title {
|
|
|
|
|
|
font-size: 32rpx;
|
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
|
color: #303133;
|
|
|
|
|
|
margin-bottom: 24rpx;
|
|
|
|
|
|
padding-left: 12rpx;
|
|
|
|
|
|
border-left: 8rpx solid #409eff;
|
|
|
|
|
|
line-height: 1.2;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.chart-container {
|
|
|
|
|
|
background-color: #f9f9f9;
|
|
|
|
|
|
border-radius: 12rpx;
|
|
|
|
|
|
padding: 24rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.mock-chart {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.chart-header {
|
|
|
|
|
|
margin-bottom: 24rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.chart-title {
|
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
color: #303133;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.chart-bars {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
align-items: flex-end;
|
|
|
|
|
|
height: 300rpx;
|
|
|
|
|
|
gap: 16rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.chart-bar {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.bar-container {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: flex-end;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
margin-bottom: 12rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.bar {
|
|
|
|
|
|
width: 40rpx;
|
|
|
|
|
|
background-color: #409eff;
|
|
|
|
|
|
border-radius: 4rpx 4rpx 0 0;
|
|
|
|
|
|
transition: height 0.5s ease;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.bar-label {
|
|
|
|
|
|
font-size: 20rpx;
|
|
|
|
|
|
color: #606266;
|
|
|
|
|
|
margin-bottom: 8rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.bar-value {
|
|
|
|
|
|
font-size: 20rpx;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
color: #303133;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 学习情况分布 */
|
|
|
|
|
|
.distribution-section {
|
|
|
|
|
|
padding: 32rpx;
|
|
|
|
|
|
background-color: #fff;
|
|
|
|
|
|
margin: 0 16rpx 16rpx;
|
|
|
|
|
|
border-radius: 16rpx;
|
|
|
|
|
|
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.distribution-grid {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
grid-template-columns: repeat(4, 1fr);
|
|
|
|
|
|
gap: 16rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.distribution-card {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
padding: 24rpx;
|
|
|
|
|
|
background-color: #f9f9f9;
|
|
|
|
|
|
border-radius: 12rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.distribution-icon {
|
|
|
|
|
|
font-size: 48rpx;
|
|
|
|
|
|
margin-bottom: 16rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.distribution-content {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.distribution-title {
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
color: #303133;
|
|
|
|
|
|
margin-bottom: 16rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.distribution-stats {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
gap: 8rpx;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.stat-item {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.stat-label {
|
|
|
|
|
|
font-size: 20rpx;
|
|
|
|
|
|
color: #606266;
|
|
|
|
|
|
margin-right: 8rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.stat-value {
|
|
|
|
|
|
font-size: 20rpx;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
color: #303133;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 学员列表 */
|
|
|
|
|
|
.student-section {
|
|
|
|
|
|
padding: 32rpx;
|
|
|
|
|
|
background-color: #fff;
|
|
|
|
|
|
margin: 0 16rpx 32rpx;
|
|
|
|
|
|
border-radius: 16rpx;
|
|
|
|
|
|
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.student-list {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
gap: 16rpx;
|
|
|
|
|
|
margin-bottom: 24rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.student-item {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
padding: 24rpx;
|
|
|
|
|
|
background-color: #f9f9f9;
|
|
|
|
|
|
border-radius: 12rpx;
|
|
|
|
|
|
transition: all 0.3s ease;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.student-item:active {
|
|
|
|
|
|
transform: translateY(2rpx);
|
|
|
|
|
|
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.student-info {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
margin-right: 24rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.student-name {
|
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
color: #303133;
|
|
|
|
|
|
margin-bottom: 8rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.student-meta {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
gap: 32rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.meta-item {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.meta-label {
|
|
|
|
|
|
font-size: 20rpx;
|
|
|
|
|
|
color: #606266;
|
|
|
|
|
|
margin-right: 8rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.meta-value {
|
|
|
|
|
|
font-size: 20rpx;
|
|
|
|
|
|
color: #303133;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.meta-value.member {
|
|
|
|
|
|
color: #67c23a;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.student-stats {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
gap: 8rpx;
|
|
|
|
|
|
margin-right: 24rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.student-arrow {
|
|
|
|
|
|
font-size: 32rpx;
|
|
|
|
|
|
color: #909399;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.load-more {
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
padding: 24rpx;
|
|
|
|
|
|
background-color: #f9f9f9;
|
|
|
|
|
|
border-radius: 12rpx;
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
color: #409eff;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-30 14:08:23 +08:00
|
|
|
|
/* 平板响应式 */
|
|
|
|
|
|
@media screen and (min-width: 768px) {
|
2026-01-29 18:29:34 +08:00
|
|
|
|
.student-stats-container {
|
|
|
|
|
|
max-width: 900px;
|
|
|
|
|
|
margin: 0 auto;
|
2026-01-30 14:08:23 +08:00
|
|
|
|
width: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.page-header {
|
|
|
|
|
|
height: 140rpx;
|
|
|
|
|
|
padding: 0 48rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.header-title {
|
|
|
|
|
|
font-size: 36rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.back-icon {
|
|
|
|
|
|
font-size: 48rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.export-btn {
|
|
|
|
|
|
font-size: 32rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.filter-section {
|
|
|
|
|
|
margin: 24rpx;
|
|
|
|
|
|
padding: 32rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.filter-row {
|
|
|
|
|
|
gap: 24rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.filter-label {
|
|
|
|
|
|
font-size: 26rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.filter-control {
|
|
|
|
|
|
padding: 20rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.picker-text {
|
|
|
|
|
|
font-size: 26rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.metrics-section,
|
|
|
|
|
|
.chart-section,
|
|
|
|
|
|
.distribution-section,
|
|
|
|
|
|
.student-section {
|
|
|
|
|
|
margin: 0 24rpx 24rpx;
|
|
|
|
|
|
padding: 40rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.section-title {
|
|
|
|
|
|
font-size: 36rpx;
|
|
|
|
|
|
margin-bottom: 32rpx;
|
2026-01-29 18:29:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.metrics-grid {
|
|
|
|
|
|
grid-template-columns: repeat(4, 1fr);
|
2026-01-30 14:08:23 +08:00
|
|
|
|
gap: 24rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.metric-card {
|
|
|
|
|
|
padding: 32rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.metric-icon {
|
|
|
|
|
|
font-size: 56rpx;
|
|
|
|
|
|
margin-right: 32rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.metric-value {
|
|
|
|
|
|
font-size: 36rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.metric-label {
|
|
|
|
|
|
font-size: 26rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.chart-container {
|
|
|
|
|
|
padding: 32rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.chart-title {
|
|
|
|
|
|
font-size: 32rpx;
|
2026-01-29 18:29:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.chart-bars {
|
|
|
|
|
|
height: 400rpx;
|
2026-01-30 14:08:23 +08:00
|
|
|
|
gap: 24rpx;
|
2026-01-29 18:29:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.bar {
|
|
|
|
|
|
width: 60rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-30 14:08:23 +08:00
|
|
|
|
.bar-label,
|
|
|
|
|
|
.bar-value {
|
|
|
|
|
|
font-size: 22rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.distribution-grid {
|
|
|
|
|
|
gap: 24rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.distribution-card {
|
|
|
|
|
|
padding: 32rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.distribution-icon {
|
|
|
|
|
|
font-size: 56rpx;
|
|
|
|
|
|
margin-bottom: 24rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.distribution-title {
|
|
|
|
|
|
font-size: 26rpx;
|
|
|
|
|
|
margin-bottom: 24rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.stat-label,
|
|
|
|
|
|
.stat-value {
|
|
|
|
|
|
font-size: 22rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-29 18:29:34 +08:00
|
|
|
|
.student-item {
|
|
|
|
|
|
padding: 32rpx;
|
|
|
|
|
|
}
|
2026-01-30 14:08:23 +08:00
|
|
|
|
|
|
|
|
|
|
.student-name {
|
|
|
|
|
|
font-size: 32rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.student-meta {
|
|
|
|
|
|
gap: 40rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.meta-label,
|
|
|
|
|
|
.meta-value {
|
|
|
|
|
|
font-size: 22rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.student-arrow {
|
|
|
|
|
|
font-size: 36rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.load-more {
|
|
|
|
|
|
padding: 32rpx;
|
|
|
|
|
|
font-size: 26rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 大屏设备响应式 */
|
|
|
|
|
|
@media screen and (min-width: 1024px) {
|
|
|
|
|
|
.student-stats-container {
|
|
|
|
|
|
max-width: 1000px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.page-header {
|
|
|
|
|
|
height: 160rpx;
|
|
|
|
|
|
padding: 0 64rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.header-title {
|
|
|
|
|
|
font-size: 40rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.back-icon {
|
|
|
|
|
|
font-size: 56rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.export-btn {
|
|
|
|
|
|
font-size: 36rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.filter-section {
|
|
|
|
|
|
padding: 40rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.filter-label {
|
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.filter-control {
|
|
|
|
|
|
padding: 24rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.picker-text {
|
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.metrics-section,
|
|
|
|
|
|
.chart-section,
|
|
|
|
|
|
.distribution-section,
|
|
|
|
|
|
.student-section {
|
|
|
|
|
|
padding: 48rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.section-title {
|
|
|
|
|
|
font-size: 40rpx;
|
|
|
|
|
|
margin-bottom: 40rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.metrics-grid {
|
|
|
|
|
|
gap: 32rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.metric-card {
|
|
|
|
|
|
padding: 40rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.metric-icon {
|
|
|
|
|
|
font-size: 64rpx;
|
|
|
|
|
|
margin-right: 40rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.metric-value {
|
|
|
|
|
|
font-size: 40rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.metric-label {
|
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.chart-container {
|
|
|
|
|
|
padding: 40rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.chart-title {
|
|
|
|
|
|
font-size: 36rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.chart-bars {
|
|
|
|
|
|
height: 450rpx;
|
|
|
|
|
|
gap: 32rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.bar {
|
|
|
|
|
|
width: 72rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.bar-label,
|
|
|
|
|
|
.bar-value {
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.distribution-card {
|
|
|
|
|
|
padding: 40rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.distribution-icon {
|
|
|
|
|
|
font-size: 64rpx;
|
|
|
|
|
|
margin-bottom: 32rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.distribution-title {
|
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
margin-bottom: 32rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.stat-label,
|
|
|
|
|
|
.stat-value {
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.student-item {
|
|
|
|
|
|
padding: 40rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.student-name {
|
|
|
|
|
|
font-size: 36rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.student-meta {
|
|
|
|
|
|
gap: 48rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.meta-label,
|
|
|
|
|
|
.meta-value {
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.student-arrow {
|
|
|
|
|
|
font-size: 40rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.load-more {
|
|
|
|
|
|
padding: 40rpx;
|
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
}
|
2026-01-29 18:29:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
</style>
|