hookehuyr

feat(teacher): 添加学员学习数据统计功能

添加新的API接口和学生详情页面的统计数据显示功能
移除测试成绩显示并调整出勤率和作业完成率的布局
/*
* @Date: 2025-06-23 11:46:21
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-06-27 09:55:12
* @LastEditTime: 2025-06-27 14:04:05
* @FilePath: /mlaj/src/api/teacher.js
* @Description: 文件描述
*/
......@@ -13,6 +13,7 @@ const Api = {
TEACHER_ADD_TASK: '/srv/?a=task&t=teacher_add',
STUDENT_LIST: '/srv/?a=user&t=student_list',
STUDENT_DETAIL: '/srv/?a=user&t=student_detail',
STUDENT_STAT: '/srv/?a=user&t=student_stat',
STUDENT_CHECKIN_LIST: '/srv/?a=checkin&t=student_checkin_list',
STUDENT_UPLOAD_LIST: '/srv/?a=checkin&t=student_upload_list',
STUDENT_CHECKIN_FEEDBACK_LIST: '/srv/?a=feedback&t=list',
......@@ -114,3 +115,11 @@ export const addCheckinFeedbackAPI = (params) => fn(fetch.post(Api.ADD_CHECKIN_F
* @returns {Object} data { id }
*/
export const delCheckinFeedbackAPI = (params) => fn(fetch.post(Api.DEL_CHECKIN_FEEDBACK, params))
/**
* 学员学习数据
* @param {*} i 学员ID
* @param {*} group_id 课程ID
* @returns {Object} data { need_checkin_count, real_checkin_count, need_upload_count, real_upload_count }
*/
export const getStudentStatAPI = (params) => fn(fetch.post(Api.STUDENT_STAT, params))
......
......@@ -2,7 +2,7 @@
* @Author: hookehuyr hookehuyr@gmail.com
* @Date: 2025-06-19 17:12:19
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-06-27 10:49:01
* @LastEditTime: 2025-06-27 14:39:13
* @FilePath: /mlaj/src/views/teacher/studentPage.vue
* @Description: 学生详情页面
-->
......@@ -57,35 +57,35 @@
<div class="mt-2">
<van-row>
<!-- 出勤率 -->
<van-col span="8">
<van-col span="12">
<div class="bg-white p-4 text-center">
<div class="relative w-16 h-16 mx-auto mb-2">
<van-circle v-model:current-rate="studentStats.attendanceRate" :rate="studentStats.attendanceRate"
:speed="100" :text="studentStats.attendanceRate + '%'" stroke-width="70" color="#10b981" size="64" />
<van-circle v-model:current-rate="checkinCount" :rate="checkinCount"
:text="`${checkinCountText}`" stroke-width="70" color="#10b981" size="64" />
</div>
<div class="text-sm text-gray-600">出勤率</div>
</div>
</van-col>
<!-- 作业完成率 -->
<van-col span="8">
<van-col span="12">
<div class="bg-white p-4 text-center">
<div class="relative w-16 h-16 mx-auto mb-2">
<van-circle v-model:current-rate="studentStats.homeworkRate" :rate="studentStats.homeworkRate"
:speed="100" :text="studentStats.homeworkRate + '%'" stroke-width="70" color="#3b82f6" size="64" />
<van-circle v-model:current-rate="uploadCount" :rate="uploadCount"
:text="`${uploadCountText}`" stroke-width="70" color="#3b82f6" size="64" />
</div>
<div class="text-sm text-gray-600">作业完成率</div>
</div>
</van-col>
<!-- 测验成绩 -->
<van-col span="8">
<!-- <van-col span="8">
<div class="bg-white p-4 text-center">
<div class="relative w-16 h-16 mx-auto mb-2">
<van-circle v-model:current-rate="studentStats.testScore" :rate="studentStats.testScore" :speed="100"
:text="studentStats.testScore + '%'" stroke-width="70" color="#f59e0b" size="64" />
:text="`${studentStats.testScore}%`" stroke-width="70" color="#f59e0b" size="64" />
</div>
<div class="text-sm text-gray-600">测验成绩</div>
</div>
</van-col>
</van-col> -->
</van-row>
</div>
......@@ -381,7 +381,7 @@ import { useTitle } from '@vueuse/core';
import dayjs from 'dayjs';
import { getCheckinTeacherListAPI, delUploadTaskInfoAPI, likeUploadTaskInfoAPI, dislikeUploadTaskInfoAPI } from "@/api/checkin";
import { getStudentDetailAPI, getStudentCheckinListAPI, getStudentUploadListAPI, getCheckinFeedbackListAPI, addCheckinFeedbackAPI, delCheckinFeedbackAPI } from "@/api/teacher";
import { getStudentDetailAPI, getStudentCheckinListAPI, getStudentUploadListAPI, getCheckinFeedbackListAPI, addCheckinFeedbackAPI, delCheckinFeedbackAPI, getStudentStatAPI } from "@/api/teacher";
const router = useRouter()
......@@ -398,13 +398,6 @@ const studentInfo = ref({})
// 选中的课程列表(默认选中第一个课程)
const selectedCourses = ref([])
// 统计数据
const studentStats = ref({
attendanceRate: 92,
homeworkRate: 88,
testScore: 85
})
// 当前选中的标签页
const activeTab = ref('homework')
......@@ -517,6 +510,8 @@ const toggleCourseSelection = (course) => {
resetAndReload()
resetAndReloadRecords()
resetAndReloadEvaluations()
// 重新获取统计数据以匹配当前选中的课程
getStatList()
}
// 状态选项
......@@ -678,15 +673,18 @@ onMounted(async () => {
// 这里可以根据studentId调用API获取学生详细信息
await loadStudentData(studentId)
// 加载统计数据
await getStatList()
// 加载作业记录
onLoad()
await onLoad()
// 加载签到记录
onRecordLoad()
await onRecordLoad()
// 加载班主任点评
onEvaluationLoad()
await onEvaluationLoad()
})
/**
......@@ -1026,6 +1024,28 @@ const resetAndReloadEvaluations = () => {
evaluationLoading.value = true;
onEvaluationLoad();
}
// 统计数据
const checkinCount = ref(0);
const checkinCountText = computed(() => checkinCount.value.toFixed(1) + '%');
const uploadCount = ref(0);
const uploadCountText = computed(() => uploadCount.value.toFixed(1) + '%');
const getStatList = async () => {
try {
const { code, data } = await getStudentStatAPI({
i: route.params.id,
group_id: selectedCourses.value.length ? selectedCourses.value[0]['id'] : '',
})
if (code) {
checkinCount.value = data.real_checkin_count/data.need_checkin_count * 100;
uploadCount.value = data.real_upload_count/data.need_upload_count * 100;
}
} catch (error) {
console.error('获取统计数据失败:', error);
}
}
</script>
<style lang="less">
......