hookehuyr

feat(teacher): 添加学生详情页相关API和功能实现

添加学生详情、打卡统计、作业记录和点评相关API
实现学生详情页数据绑定和交互逻辑
更新学生信息展示和点评状态处理
/*
* @Date: 2025-06-23 11:46:21
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-06-26 10:35:45
* @LastEditTime: 2025-06-26 16:15:15
* @FilePath: /mlaj/src/api/teacher.js
* @Description: 文件描述
*/
......@@ -12,6 +12,12 @@ const Api = {
TEACHER_FIND_SETTINGS: '/srv/?a=task&t=teacher_find_settings',
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_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=checkin_feedback&t=list',
ADD_CHECKIN_FEEDBACK: '/srv/?a=checkin_feedback&t=add',
DEL_CHECKIN_FEEDBACK: '/srv/?a=checkin_feedback&t=del',
}
/**
......@@ -55,3 +61,56 @@ export const setTeacherTaskAPI = (params) => fn(fetch.post(Api.TEACHER_ADD_TASK,
* @returns {Object} data { count, user_list[{id, name, avatar, mobile, class_list[{id, class_name}], last_checkin_time, last_checkin_time_desc}] }
*/
export const getStudentListAPI = (params) => fn(fetch.get(Api.STUDENT_LIST, params))
/**
* 获取学员详情
* @param {*} i 学员ID
* @returns {Object} data { id, name, avatar, mobile, grade_list[{id, grade_name, class_list[{id, class_name}]}], lesson_list[{id, title}] }
*/
export const getStudentDetailAPI = (params) => fn(fetch.get(Api.STUDENT_DETAIL, params))
/**
* 获取学员打卡统计
* @param {*} user_id 学员ID
* @param {*} group_id 课程ID
* @param {*} limit 条数
* @param {*} page 页码
* @returns {Object} data { date, time, serial_number, status }
*/
export const getStudentCheckinListAPI = (params) => fn(fetch.get(Api.STUDENT_CHECKIN_LIST, params))
/**
* 获取学员作业记录
* @param {*} user_id 学员ID
* @param {*} group_id 课程ID
* @param {*} limit 条数
* @param {*} page 页码
* @returns {Object} data
*/
export const getStudentUploadListAPI = (params) => fn(fetch.get(Api.STUDENT_UPLOAD_LIST, params))
/**
* 获取老师点评列表
* @param {*} user_id 学员ID
* @param {*} group_id 课程ID
* @param {*} limit 条数
* @param {*} page 页码
* @returns {Object} data
*/
export const getCheckinFeedbackListAPI = (params) => fn(fetch.get(Api.STUDENT_CHECKIN_FEEDBACK_LIST, params))
/**
* 老师点评
* @param {*} checkin_id 打卡ID
* @param {*} note 点评内容
* @param {*} rate 点评分数
* @returns {Object} data { id }
*/
export const addCheckinFeedbackAPI = (params) => fn(fetch.post(Api.ADD_CHECKIN_FEEDBACK, params))
/**
* 老师删除点评
* @param {*} id 点评ID
* @returns {Object} data { id }
*/
export const delCheckinFeedbackAPI = (params) => fn(fetch.post(Api.DEL_CHECKIN_FEEDBACK, 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-26 11:46:50
* @LastEditTime: 2025-06-26 16:36:01
* @FilePath: /mlaj/src/views/teacher/studentPage.vue
* @Description: 学生详情页面
-->
......@@ -17,19 +17,19 @@
<div class="flex-1">
<div class="flex items-center mb-2">
<h2 class="text-xl font-bold text-gray-800 mr-2">{{ studentInfo.name }}</h2>
<font-awesome-icon v-if="studentInfo.gender === 'male'" icon="venus" color="#3b82f6" class="mr-2" style="font-size: 0.85rem;" />
<font-awesome-icon v-else icon="mars" color="#ec4899" class="mr-2" style="font-size: 0.85rem;" />
<!-- <font-awesome-icon v-if="studentInfo.gender === 'male'" icon="venus" color="#3b82f6" class="mr-2" style="font-size: 0.85rem;" />
<font-awesome-icon v-else icon="mars" color="#ec4899" class="mr-2" style="font-size: 0.85rem;" /> -->
</div>
<div class="flex items-center mb-2">
<van-icon name="chat-o" size="16" color="#10b981" class="mr-1" />
<span class="text-sm text-gray-600 mr-4">{{ studentInfo.className }}</span>
<span class="text-sm text-gray-600 mr-4" v-for="(item, index) in studentInfo.class_list" :key="index">{{ item.class_name }}</span>
<van-icon name="phone-o" size="16" color="#10b981" class="mr-1" />
<span class="text-sm text-gray-600">{{ formatPhone(studentInfo.phone) }}</span>
<span class="text-sm text-gray-600">{{ formatPhone(studentInfo.mobile) }}</span>
</div>
<!-- 标签 -->
<div class="flex flex-wrap gap-2">
<van-tag v-for="tag in studentInfo.tags" :key="tag" type="success" size="large" plain>
{{ tag }}
<van-tag v-for="grade in studentInfo.grade_list" :key="grade.id" type="success" size="large" plain>
{{ grade.grade_name }}
</van-tag>
</div>
</div>
......@@ -43,12 +43,12 @@
<span class="text-sm font-medium text-gray-700">所学课程</span>
</div>
<div class="flex flex-wrap gap-2">
<van-tag v-for="course in studentInfo.courses" :key="course"
<van-tag v-for="course in studentInfo.lesson_list" :key="course.id"
:type="selectedCourses.includes(course) ? 'primary' : 'default'"
:color="selectedCourses.includes(course) ? '#10b981' : '#f0f0f0'"
:text-color="selectedCourses.includes(course) ? '#ffffff' : '#666666'" size="large"
@click="toggleCourseSelection(course)" class="cursor-pointer transition-all duration-200 hover:opacity-80">
{{ course }}
{{ course.title }}
</van-tag>
</div>
</div>
......@@ -256,13 +256,13 @@
<div class="flex items-center cursor-pointer" @click="openCommentPopup(post)">
<van-icon
name="comment-o"
:color="post.is_commented ? '#10b981' : '#999'"
:color="post.is_feedback ? '#10b981' : '#999'"
size="19"
class="mr-1"
style="margin-top: 0.2rem;"
/>
<span class="text-sm" :class="post.is_commented ? 'text-green-600' : 'text-gray-500'">
{{ post.is_commented ? '已点评' : '点评' }}
<span class="text-sm" :class="post.is_feedback ? 'text-green-600' : 'text-gray-500'">
{{ post.is_feedback ? '已点评' : '待点评' }}
</span>
</div>
</div>
......@@ -369,6 +369,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";
const router = useRouter()
......@@ -380,19 +381,10 @@ const themeVars = reactive({
})
// 学生信息
const studentInfo = ref({
id: 1,
name: '李华',
gender: 'female',
className: '高一(3)班',
phone: '13812345678',
avatar: 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg',
tags: ['亲子学堂2025级'],
courses: ['讲师训2025', '亲子学堂课程']
})
const studentInfo = ref({})
// 选中的课程列表(默认选中第一个课程)
const selectedCourses = ref([studentInfo.value.courses[0] || ''])
const selectedCourses = ref([])
// 统计数据
const studentStats = ref({
......@@ -469,7 +461,7 @@ const submitComment = async () => {
// 更新本地数据
if (currentCommentPost.value) {
currentCommentPost.value.is_commented = true
currentCommentPost.value.is_feedback = true
currentCommentPost.value.comment = {
rating: commentForm.value.rating,
content: commentForm.value.content,
......@@ -705,9 +697,12 @@ onMounted(async () => {
* 加载学生数据
* @param {string} studentId - 学生ID
*/
const loadStudentData = (studentId) => {
// 这里可以调用API获取实际数据
console.log('加载学生数据:', studentId)
const loadStudentData = async (studentId) => {
const { code, data } = await getStudentDetailAPI({ i: studentId })
if (code) {
studentInfo.value = data;
selectedCourses.value = [studentInfo.value.lesson_list[0] || '']
}
}
// 处理标签页切换
......@@ -985,7 +980,7 @@ const formatData = (data) => {
is_liked: item.is_like,
is_my: item.is_my,
file_type: item.file_type,
is_commented: item.is_commented || false, // 是否已点评
is_feedback: item.is_feedback || false, // 是否已点评
comment: item.comment || null, // 点评内容
}
})
......