feat(student): 新增学生详情接口及相关服务层支持

- 优化ClassDOMapper,重命名查询方法为selectClassDOById,并移除多余CRUD方法
- 新增ClassService接口及ClassServiceImpl实现,用于通过ID查询班级信息
- 新增GradeDO及GradeDOMapper,实现根据班级ID查询年级信息
- 新增GradeService接口及GradeServiceImpl实现根据班级ID查询年级数据
- StudentDO增加isDeleted和startTime字段,补充学生实体
- StudentDOMapper新增selectStudentById方法实现单个学生信息查询
- StudentService及其实现类新增getStudentById方法提供学生单条数据查询
- StudentController新增/detail接口,实现学生详情查询,返回学生姓名、班级、年级等信息
- 创建FindStudentDetailReqVO和FindStudentDetailRspVO用于请求和响应数据传输
- enlish-vue端新增getStudentDetail接口调用 后台学生详情接口
- 修改ExamWordsDetailCard组件,展示学生姓名及其班级、年级信息,新增fetchStudent异步方法拉取学生详情数据并显示
This commit is contained in:
lbw
2025-12-14 16:51:45 +08:00
parent 6eb46f606e
commit 0ad8edbac1
20 changed files with 217 additions and 72 deletions

View File

@@ -1,12 +1,19 @@
package com.yinlihupo.enlish.service.controller; package com.yinlihupo.enlish.service.controller;
import com.yinlihupo.enlish.service.domain.dataobject.ClassDO;
import com.yinlihupo.enlish.service.domain.dataobject.GradeDO;
import com.yinlihupo.enlish.service.domain.dataobject.StudentDO; import com.yinlihupo.enlish.service.domain.dataobject.StudentDO;
import com.yinlihupo.enlish.service.model.vo.student.FindStudentDetailReqVO;
import com.yinlihupo.enlish.service.model.vo.student.FindStudentDetailRspVO;
import com.yinlihupo.enlish.service.model.vo.student.FindStudentsReqVO; import com.yinlihupo.enlish.service.model.vo.student.FindStudentsReqVO;
import com.yinlihupo.enlish.service.model.vo.student.StudentItemRspVO; import com.yinlihupo.enlish.service.model.vo.student.StudentItemRspVO;
import com.yinlihupo.enlish.service.service.ClassService;
import com.yinlihupo.enlish.service.service.GradeService;
import com.yinlihupo.enlish.service.service.StudentService; import com.yinlihupo.enlish.service.service.StudentService;
import com.yinlihupo.framework.biz.operationlog.aspect.ApiOperationLog; import com.yinlihupo.framework.biz.operationlog.aspect.ApiOperationLog;
import com.yinlihupo.framework.common.response.PageResponse; import com.yinlihupo.framework.common.response.PageResponse;
import com.yinlihupo.framework.common.response.Response;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
@@ -21,7 +28,10 @@ public class StudentController {
@Resource @Resource
private StudentService studentService; private StudentService studentService;
@Resource
private ClassService classService;
@Resource
private GradeService gradeService;
@PostMapping("/list") @PostMapping("/list")
@ApiOperationLog(description = "查询学生列表") @ApiOperationLog(description = "查询学生列表")
@@ -44,4 +54,23 @@ public class StudentController {
return PageResponse.success(studentItemRspVOS, pageNo, allStudents, pageSize); return PageResponse.success(studentItemRspVOS, pageNo, allStudents, pageSize);
} }
@PostMapping("/detail")
@ApiOperationLog(description = "查询学生详情")
public Response<FindStudentDetailRspVO> findStudentDetail(@RequestBody FindStudentDetailReqVO findStudentDetailReqVO) {
Integer studentId = findStudentDetailReqVO.getStudentId();
StudentDO studentById = studentService.getStudentById(studentId);
ClassDO classById = classService.findClassById(studentById.getClassId());
GradeDO byClassId = gradeService.findByClassId(studentById.getGradeId());
FindStudentDetailRspVO findStudentDetailRspVO = FindStudentDetailRspVO.builder()
.id(studentById.getId())
.name(studentById.getName())
.className(classById.getTitle())
.gradeName(byClassId.getTitle())
.build();
return Response.success(findStudentDetailRspVO);
}
} }

View File

@@ -0,0 +1,22 @@
package com.yinlihupo.enlish.service.domain.dataobject;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
public class GradeDO {
private Integer id;
private String title;
private Date time;
}

View File

@@ -5,6 +5,8 @@ import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
@AllArgsConstructor @AllArgsConstructor
@NoArgsConstructor @NoArgsConstructor
@Data @Data
@@ -19,6 +21,10 @@ public class StudentDO {
private Integer gradeId; private Integer gradeId;
private Integer isDeleted;
private LocalDateTime startTime;
private Integer initialVocabularySize; private Integer initialVocabularySize;
private Integer currentVocabularySize; private Integer currentVocabularySize;

View File

@@ -4,15 +4,5 @@ import com.yinlihupo.enlish.service.domain.dataobject.ClassDO;
public interface ClassDOMapper { public interface ClassDOMapper {
int deleteByPrimaryKey(Integer id); ClassDO selectClassDOById(Integer id);
int insert(ClassDO record);
int insertSelective(ClassDO record);
ClassDO selectByPrimaryKey(Integer id);
int updateByPrimaryKeySelective(ClassDO record);
int updateByPrimaryKey(ClassDO record);
} }

View File

@@ -0,0 +1,8 @@
package com.yinlihupo.enlish.service.domain.mapper;
import com.yinlihupo.enlish.service.domain.dataobject.GradeDO;
public interface GradeDOMapper {
GradeDO selectById(Integer id);
}

View File

@@ -9,4 +9,6 @@ public interface StudentDOMapper {
List<StudentDO> selectStudentDOListByClassIdAndGradeId(Integer classId, Integer gradeId, Integer pageSize, Integer offset); List<StudentDO> selectStudentDOListByClassIdAndGradeId(Integer classId, Integer gradeId, Integer pageSize, Integer offset);
int selectStudentCount(); int selectStudentCount();
StudentDO selectStudentById(Integer id);
} }

View File

@@ -0,0 +1,15 @@
package com.yinlihupo.enlish.service.model.vo.student;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
public class FindStudentDetailReqVO {
private Integer studentId;
}

View File

@@ -0,0 +1,18 @@
package com.yinlihupo.enlish.service.model.vo.student;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
public class FindStudentDetailRspVO {
private Integer id;
private String name;
private String className;
private String gradeName;
}

View File

@@ -0,0 +1,8 @@
package com.yinlihupo.enlish.service.service;
import com.yinlihupo.enlish.service.domain.dataobject.ClassDO;
public interface ClassService {
ClassDO findClassById(Integer id);
}

View File

@@ -0,0 +1,8 @@
package com.yinlihupo.enlish.service.service;
import com.yinlihupo.enlish.service.domain.dataobject.GradeDO;
public interface GradeService {
GradeDO findByClassId(Integer classId);
}

View File

@@ -10,4 +10,6 @@ public interface StudentService {
List<StudentDO> getStudentsByClassIdAndGradeId(Integer classId, Integer gradeId, Integer pageNo, Integer pageSize); List<StudentDO> getStudentsByClassIdAndGradeId(Integer classId, Integer gradeId, Integer pageNo, Integer pageSize);
int getAllStudents(); int getAllStudents();
StudentDO getStudentById(Integer studentId);
} }

View File

@@ -0,0 +1,19 @@
package com.yinlihupo.enlish.service.service.classs;
import com.yinlihupo.enlish.service.domain.dataobject.ClassDO;
import com.yinlihupo.enlish.service.domain.mapper.ClassDOMapper;
import com.yinlihupo.enlish.service.service.ClassService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
@Service
public class ClassServiceImpl implements ClassService {
@Resource
private ClassDOMapper classDOMapper;
@Override
public ClassDO findClassById(Integer id) {
return classDOMapper.selectClassDOById(id);
}
}

View File

@@ -0,0 +1,19 @@
package com.yinlihupo.enlish.service.service.grade;
import com.yinlihupo.enlish.service.domain.dataobject.GradeDO;
import com.yinlihupo.enlish.service.domain.mapper.GradeDOMapper;
import com.yinlihupo.enlish.service.service.GradeService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
@Service
public class GradeServiceImpl implements GradeService {
@Resource
private GradeDOMapper gradeDOMapper;
@Override
public GradeDO findByClassId(Integer classId) {
return gradeDOMapper.selectById(classId);
}
}

View File

@@ -25,4 +25,9 @@ public class StudentServiceImpl implements StudentService {
public int getAllStudents() { public int getAllStudents() {
return studentDOMapper.selectStudentCount(); return studentDOMapper.selectStudentCount();
} }
@Override
public StudentDO getStudentById(Integer studentId) {
return studentDOMapper.selectStudentById(studentId);
}
} }

View File

@@ -45,7 +45,7 @@
targetProject="src/main/java"/> targetProject="src/main/java"/>
<!-- 需要生成的表-实体类 --> <!-- 需要生成的表-实体类 -->
<table tableName="word_mastery_log" domainObjectName="WordMasteryLogDO" <table tableName="grade" domainObjectName="GradeDO"
enableCountByExample="false" enableCountByExample="false"
enableUpdateByExample="false" enableUpdateByExample="false"
enableDeleteByExample="false" enableDeleteByExample="false"

View File

@@ -6,60 +6,11 @@
<result column="title" jdbcType="VARCHAR" property="title" /> <result column="title" jdbcType="VARCHAR" property="title" />
</resultMap> </resultMap>
<sql id="Base_Column_List"> <select id="selectClassDOById" resultType="com.yinlihupo.enlish.service.domain.dataobject.ClassDO">
id, title select *
</sql> from `class`
where id = #{id}
<select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from class
where id = #{id,jdbcType=INTEGER}
</select> </select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
delete from class
where id = #{id,jdbcType=INTEGER}
</delete>
<insert id="insert" parameterType="com.yinlihupo.enlish.service.domain.dataobject.ClassDO">
insert into class (id, title)
values (#{id,jdbcType=INTEGER}, #{title,jdbcType=VARCHAR})
</insert>
<insert id="insertSelective" parameterType="com.yinlihupo.enlish.service.domain.dataobject.ClassDO">
insert into class
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">
id,
</if>
<if test="title != null">
title,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
#{id,jdbcType=INTEGER},
</if>
<if test="title != null">
#{title,jdbcType=VARCHAR},
</if>
</trim>
</insert>
<update id="updateByPrimaryKeySelective" parameterType="com.yinlihupo.enlish.service.domain.dataobject.ClassDO">
update class
<set>
<if test="title != null">
title = #{title,jdbcType=VARCHAR},
</if>
</set>
where id = #{id,jdbcType=INTEGER}
</update>
<update id="updateByPrimaryKey" parameterType="com.yinlihupo.enlish.service.domain.dataobject.ClassDO">
update class
set title = #{title,jdbcType=VARCHAR}
where id = #{id,jdbcType=INTEGER}
</update>
</mapper> </mapper>

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yinlihupo.enlish.service.domain.mapper.GradeDOMapper">
<resultMap id="BaseResultMap" type="com.yinlihupo.enlish.service.domain.dataobject.GradeDO">
<id column="id" jdbcType="INTEGER" property="id" />
<result column="title" jdbcType="VARCHAR" property="title" />
<result column="time" jdbcType="TIMESTAMP" property="time" />
</resultMap>
<select id="selectById" resultMap="BaseResultMap">
select *
from grade
where id = #{id}
</select>
</mapper>

View File

@@ -8,12 +8,10 @@
<result column="grade_id" jdbcType="INTEGER" property="gradeId" /> <result column="grade_id" jdbcType="INTEGER" property="gradeId" />
<result column="initial_vocabulary_size" jdbcType="INTEGER" property="initialVocabularySize" /> <result column="initial_vocabulary_size" jdbcType="INTEGER" property="initialVocabularySize" />
<result column="current_vocabulary_size" jdbcType="INTEGER" property="currentVocabularySize" /> <result column="current_vocabulary_size" jdbcType="INTEGER" property="currentVocabularySize" />
<result column="is_deleted" jdbcType="INTEGER" property="isDeleted"/>
<result column="start_time" jdbcType="TIMESTAMP" property="startTime" />
</resultMap> </resultMap>
<sql id="Base_Column_List">
id, `name`, class_id, grade_id, initial_vocabulary_size, current_vocabulary_size
</sql>
<select id="selectStudentDOListByClassIdAndGradeId" resultMap="BaseResultMap"> <select id="selectStudentDOListByClassIdAndGradeId" resultMap="BaseResultMap">
select * select *
from student from student
@@ -31,4 +29,10 @@
select count(1) select count(1)
from student from student
</select> </select>
<select id="selectStudentById" resultMap="BaseResultMap">
select *
from student
where id = #{id}
</select>
</mapper> </mapper>

View File

@@ -0,0 +1,7 @@
import axios from "@/axios";
export function getStudentDetail(id) {
return axios.post('/student/detail', {
studentId: id
})
}

View File

@@ -8,8 +8,13 @@
<div class="text-base font-medium">{{ detail?.id ?? '-' }}</div> <div class="text-base font-medium">{{ detail?.id ?? '-' }}</div>
</div> </div>
<div> <div>
<div class="text-gray-500 text-sm">学生ID</div> <div class="text-gray-500 text-sm">学生</div>
<div class="text-base font-medium">{{ detail?.studentId ?? '-' }}</div> <div class="text-base font-medium">
{{ studentDetail?.name ?? '-' }}
</div>
<div class="text-gray-500 text-xs mt-1">
班级{{ studentDetail?.className ?? '-' }} 年级{{ studentDetail?.gradeName ?? '-' }}
</div>
</div> </div>
<div> <div>
<div class="text-gray-500 text-sm">试题ID</div> <div class="text-gray-500 text-sm">试题ID</div>
@@ -76,6 +81,7 @@
<script setup> <script setup>
import { ref, computed, watch } from 'vue' import { ref, computed, watch } from 'vue'
import { getExamWordsDetailResult } from '@/api/exam' import { getExamWordsDetailResult } from '@/api/exam'
import { getStudentDetail } from '@/api/student'
import { getWordsListByIds } from '@/api/words' import { getWordsListByIds } from '@/api/words'
const props = defineProps({ const props = defineProps({
@@ -94,6 +100,7 @@ const detail = ref(null)
const activeNames = ref(['correct', 'wrong']) const activeNames = ref(['correct', 'wrong'])
const correctTitles = ref([]) const correctTitles = ref([])
const wrongTitles = ref([]) const wrongTitles = ref([])
const studentDetail = ref(null)
async function fetchDetail() { async function fetchDetail() {
if (!props.id && props.id !== 0) return if (!props.id && props.id !== 0) return
@@ -103,6 +110,7 @@ async function fetchDetail() {
const d = res?.data?.data ?? null const d = res?.data?.data ?? null
detail.value = d detail.value = d
await fetchTitles() await fetchTitles()
await fetchStudent()
} finally { } finally {
loading.value = false loading.value = false
} }
@@ -133,6 +141,14 @@ async function fetchTitles() {
} }
} }
async function fetchStudent() {
studentDetail.value = null
const sid = detail.value?.studentId
if (!sid && sid !== 0) return
const res = await getStudentDetail(Number(sid))
studentDetail.value = res?.data?.data ?? null
}
watch( watch(
() => props.modelValue, () => props.modelValue,
(v) => { (v) => {