页面初始化
This commit is contained in:
475
src/pages/student/analysis.vue
Normal file
475
src/pages/student/analysis.vue
Normal file
@@ -0,0 +1,475 @@
|
||||
<template>
|
||||
<view class="learning-analysis-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="exportAnalysis">
|
||||
<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="timeRangeOptions"
|
||||
:value="timeRangeIndex"
|
||||
@change="onTimeRangeChange"
|
||||
class="picker"
|
||||
>
|
||||
<view class="picker-text">{{ timeRangeOptions[timeRangeIndex] }}</view>
|
||||
</picker>
|
||||
</view>
|
||||
</view>
|
||||
<view class="filter-item">
|
||||
<view class="filter-label">学员类型</view>
|
||||
<view class="filter-control">
|
||||
<picker
|
||||
:range="studentTypeOptions"
|
||||
:value="studentTypeIndex"
|
||||
@change="onStudentTypeChange"
|
||||
class="picker"
|
||||
>
|
||||
<view class="picker-text">{{ studentTypeOptions[studentTypeIndex] }}</view>
|
||||
</picker>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 核心数据 -->
|
||||
<view class="core-data-section">
|
||||
<view class="section-title">核心数据</view>
|
||||
<view class="data-card">
|
||||
<view class="data-row">
|
||||
<view class="data-item">
|
||||
<view class="data-value">{{ totalStudents }}</view>
|
||||
<view class="data-label">总学员数</view>
|
||||
</view>
|
||||
<view class="data-item">
|
||||
<view class="data-value">{{ activeStudents }}</view>
|
||||
<view class="data-label">活跃学员</view>
|
||||
</view>
|
||||
<view class="data-item">
|
||||
<view class="data-value">{{ memberStudents }}</view>
|
||||
<view class="data-label">会员学员</view>
|
||||
</view>
|
||||
<view class="data-item">
|
||||
<view class="data-value">{{ avgStudyTime }}</view>
|
||||
<view class="data-label">平均学习时长</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 学习趋势 -->
|
||||
<view class="trend-section">
|
||||
<view class="section-title">学习趋势</view>
|
||||
<view class="trend-card">
|
||||
<view class="chart-placeholder">
|
||||
<view class="chart-rect"></view>
|
||||
<view class="chart-text">学习时长趋势图</view>
|
||||
</view>
|
||||
<view class="trend-hint">
|
||||
近7天学员学习时长变化趋势
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 学习分布 -->
|
||||
<view class="distribution-section">
|
||||
<view class="section-title">学习分布</view>
|
||||
<view class="distribution-card">
|
||||
<view class="chart-placeholder">
|
||||
<view class="chart-rect"></view>
|
||||
<view class="chart-text">学习分布饼图</view>
|
||||
</view>
|
||||
<view class="distribution-hint">
|
||||
学员学习科目分布
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 学习排行 -->
|
||||
<view class="ranking-section">
|
||||
<view class="section-title">学习排行</view>
|
||||
<view class="ranking-card">
|
||||
<view class="ranking-header">
|
||||
<view class="header-item">排名</view>
|
||||
<view class="header-item">学员姓名</view>
|
||||
<view class="header-item">学习时长</view>
|
||||
<view class="header-item">完成题目</view>
|
||||
</view>
|
||||
<view class="ranking-list">
|
||||
<view
|
||||
v-for="(item, index) in rankingList"
|
||||
:key="index"
|
||||
class="ranking-item"
|
||||
>
|
||||
<view class="ranking-cell rank">{{ index + 1 }}</view>
|
||||
<view class="ranking-cell name">{{ item.name }}</view>
|
||||
<view class="ranking-cell time">{{ item.studyTime }}</view>
|
||||
<view class="ranking-cell count">{{ item.completedCount }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from "vue"
|
||||
|
||||
// 筛选条件
|
||||
const timeRangeOptions = ['最近7天', '最近30天', '最近90天', '本学期', '自定义']
|
||||
const timeRangeIndex = ref(0)
|
||||
|
||||
const studentTypeOptions = ['全部学员', '普通学员', '会员学员', '分销员学员']
|
||||
const studentTypeIndex = ref(0)
|
||||
|
||||
// 核心数据
|
||||
const totalStudents = ref(1200)
|
||||
const activeStudents = ref(850)
|
||||
const memberStudents = ref(450)
|
||||
const avgStudyTime = ref('2.5小时')
|
||||
|
||||
// 学习排行
|
||||
const rankingList = ref([
|
||||
{
|
||||
name: '张三',
|
||||
studyTime: '15.5小时',
|
||||
completedCount: 120
|
||||
},
|
||||
{
|
||||
name: '李四',
|
||||
studyTime: '12.3小时',
|
||||
completedCount: 98
|
||||
},
|
||||
{
|
||||
name: '王五',
|
||||
studyTime: '10.8小时',
|
||||
completedCount: 85
|
||||
},
|
||||
{
|
||||
name: '赵六',
|
||||
studyTime: '9.2小时',
|
||||
completedCount: 75
|
||||
},
|
||||
{
|
||||
name: '钱七',
|
||||
studyTime: '8.5小时',
|
||||
completedCount: 68
|
||||
}
|
||||
])
|
||||
|
||||
onMounted(() => {
|
||||
// 实际项目中应从接口获取学情数据
|
||||
// loadLearningData()
|
||||
})
|
||||
|
||||
// 返回上一页
|
||||
function goBack() {
|
||||
uni.navigateBack({ delta: 1 })
|
||||
}
|
||||
|
||||
// 导出分析
|
||||
function exportAnalysis() {
|
||||
uni.showModal({
|
||||
title: '导出分析报告',
|
||||
content: '确定要导出当前分析报告吗?',
|
||||
success: function(res) {
|
||||
if (res.confirm) {
|
||||
uni.showLoading({ title: '导出中...' })
|
||||
|
||||
setTimeout(() => {
|
||||
uni.hideLoading()
|
||||
uni.showToast({
|
||||
title: '导出成功',
|
||||
icon: 'success'
|
||||
})
|
||||
// 实际项目中应调用接口导出分析报告
|
||||
// exportAnalysisReport()
|
||||
}, 1500)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 时间范围变更
|
||||
function onTimeRangeChange(e) {
|
||||
const value = e.detail.value
|
||||
timeRangeIndex.value = value
|
||||
// 实际项目中应根据时间范围筛选数据
|
||||
// filterLearningData()
|
||||
}
|
||||
|
||||
// 学员类型变更
|
||||
function onStudentTypeChange(e) {
|
||||
const value = e.detail.value
|
||||
studentTypeIndex.value = value
|
||||
// 实际项目中应根据学员类型筛选数据
|
||||
// filterLearningData()
|
||||
}
|
||||
</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 */
|
||||
|
||||
.learning-analysis-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: 24rpx;
|
||||
color: #409eff;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* 通用部分样式 */
|
||||
.filter-section,
|
||||
.core-data-section,
|
||||
.trend-section,
|
||||
.distribution-section,
|
||||
.ranking-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;
|
||||
}
|
||||
|
||||
/* 筛选条件 */
|
||||
.filter-row {
|
||||
display: flex;
|
||||
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;
|
||||
}
|
||||
|
||||
/* 核心数据 */
|
||||
.data-card {
|
||||
background-color: #f9f9f9;
|
||||
border-radius: 12rpx;
|
||||
padding: 24rpx;
|
||||
}
|
||||
|
||||
.data-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.data-item {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 8rpx;
|
||||
}
|
||||
|
||||
.data-value {
|
||||
font-size: 28rpx;
|
||||
font-weight: bold;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.data-label {
|
||||
font-size: 18rpx;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
/* 学习趋势 */
|
||||
.trend-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.chart-placeholder {
|
||||
background-color: #f9f9f9;
|
||||
border-radius: 12rpx;
|
||||
padding: 48rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.chart-rect {
|
||||
width: 100%;
|
||||
height: 300rpx;
|
||||
background-color: #e0e0e0;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
.chart-text {
|
||||
font-size: 24rpx;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.trend-hint {
|
||||
font-size: 20rpx;
|
||||
color: #606266;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* 学习分布 */
|
||||
.distribution-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.distribution-hint {
|
||||
font-size: 20rpx;
|
||||
color: #606266;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* 学习排行 */
|
||||
.ranking-card {
|
||||
background-color: #f9f9f9;
|
||||
border-radius: 12rpx;
|
||||
padding: 24rpx;
|
||||
}
|
||||
|
||||
.ranking-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 16rpx;
|
||||
padding-bottom: 16rpx;
|
||||
border-bottom: 1rpx solid #e0e0e0;
|
||||
}
|
||||
|
||||
.header-item {
|
||||
flex: 1;
|
||||
font-size: 20rpx;
|
||||
font-weight: bold;
|
||||
color: #606266;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.ranking-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.ranking-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 16rpx;
|
||||
background-color: #fff;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
.ranking-cell {
|
||||
flex: 1;
|
||||
font-size: 20rpx;
|
||||
color: #303133;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.ranking-cell.rank {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.ranking-cell.time {
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
.ranking-cell.count {
|
||||
color: #67c23a;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user