diff --git a/backend/pom.xml b/backend/pom.xml index ba23e7a0..a99a54ce 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -400,6 +400,12 @@ ruoyi-aqbw ${revision} + + + org.dromara + ruoyi-xljk + ${revision} + diff --git a/backend/ruoyi-admin/pom.xml b/backend/ruoyi-admin/pom.xml index ddf8f8a1..6e1fa000 100644 --- a/backend/ruoyi-admin/pom.xml +++ b/backend/ruoyi-admin/pom.xml @@ -128,6 +128,12 @@ org.dromara ruoyi-aqbw + + + org.dromara + ruoyi-xljk + ${revision} + de.codecentric diff --git a/backend/ruoyi-admin/src/main/resources/application-dev.yml b/backend/ruoyi-admin/src/main/resources/application-dev.yml index bab18e76..1f2c6cf2 100644 --- a/backend/ruoyi-admin/src/main/resources/application-dev.yml +++ b/backend/ruoyi-admin/src/main/resources/application-dev.yml @@ -72,9 +72,9 @@ spring: driverClassName: com.mysql.cj.jdbc.Driver # jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562 # rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题) - url: jdbc:mysql://47.99.164.66:3306/hzdyjs_xg?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true + url: jdbc:mysql://localhost:3306/hzdyjs_xg?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true username: root - password: hn02le.34lkdLKD + password: 'DP@xp117' # # 从库数据源 # slave: # lazy: true diff --git a/backend/ruoyi-admin/src/main/resources/application.yml b/backend/ruoyi-admin/src/main/resources/application.yml index fb347bc4..246b5071 100644 --- a/backend/ruoyi-admin/src/main/resources/application.yml +++ b/backend/ruoyi-admin/src/main/resources/application.yml @@ -137,6 +137,8 @@ tenant: - sys_user_role - sys_client - sys_oss_config + - xljk_evaluation + - xljk_evaluation_detail # MyBatisPlus配置 # https://baomidou.com/config/ diff --git a/backend/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-dev.yml b/backend/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-dev.yml index 5dd063ff..ba89bde5 100644 --- a/backend/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-dev.yml +++ b/backend/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-dev.yml @@ -2,9 +2,9 @@ spring: datasource: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.cj.jdbc.Driver - url: jdbc:mysql://47.99.164.66:3306/hzdyjs_xg?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true + url: jdbc:mysql://localhost:3306/hzdyjs_xg?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true username: root - password: hn02le.34lkdLKD + password: "DP@xp117" hikari: connection-timeout: 30000 validation-timeout: 5000 diff --git a/backend/ruoyi-modules/pom.xml b/backend/ruoyi-modules/pom.xml index 290bf1e5..6dfc9f47 100644 --- a/backend/ruoyi-modules/pom.xml +++ b/backend/ruoyi-modules/pom.xml @@ -9,18 +9,19 @@ 4.0.0 - ruoyi-demo + ruoyi-system ruoyi-generator ruoyi-job - ruoyi-system + ruoyi-demo ruoyi-workflow - ruoyi-hq - ruoyi-rs - ruoyi-cw - ruoyi-aqbw - ruoyi-zsjy ruoyi-xg ruoyi-xg-xx + ruoyi-zsjy + ruoyi-hq + ruoyi-aqbw + ruoyi-cw + ruoyi-rs + ruoyi-xljk ruoyi-modules diff --git a/backend/ruoyi-modules/ruoyi-xljk/pom.xml b/backend/ruoyi-modules/ruoyi-xljk/pom.xml new file mode 100644 index 00000000..cc47738b --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-xljk/pom.xml @@ -0,0 +1,81 @@ + + + + ruoyi-modules + org.dromara + ${revision} + + 4.0.0 + + ruoyi-xljk + + + 心理健康管理模块 + + + + + + org.dromara + ruoyi-common-core + + + + + org.dromara + ruoyi-common-security + + + + + org.dromara + ruoyi-common-web + + + + + org.dromara + ruoyi-common-excel + + + + + org.dromara + ruoyi-common-mybatis + + + + + org.dromara + ruoyi-common-tenant + + + + + org.dromara + ruoyi-common-idempotent + + + + + org.dromara + ruoyi-common-log + + + + + org.dromara + ruoyi-common-oss + + + + + org.dromara + ruoyi-common-translation + + + + + \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-xljk/src/main/java/org/dromara/xljk/controller/XljkEvaluationController.java b/backend/ruoyi-modules/ruoyi-xljk/src/main/java/org/dromara/xljk/controller/XljkEvaluationController.java new file mode 100644 index 00000000..2da53664 --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-xljk/src/main/java/org/dromara/xljk/controller/XljkEvaluationController.java @@ -0,0 +1,217 @@ +package org.dromara.xljk.controller; + +import java.util.List; +import java.util.Map; + +import lombok.RequiredArgsConstructor; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.*; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.web.core.BaseController; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.xljk.domain.vo.XljkEvaluationVo; +import org.dromara.xljk.domain.bo.XljkEvaluationBo; +import org.dromara.xljk.service.IXljkEvaluationService; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 心理健康测评Controller + * + * @author Cursor AI + * @date 2025-07-02 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/xljk/evaluation") +public class XljkEvaluationController extends BaseController { + + private final IXljkEvaluationService evaluationService; + + /** + * 查询心理健康测评列表 + */ + @SaCheckPermission("xljk:evaluation:list") + @GetMapping("/list") + public TableDataInfo list(XljkEvaluationBo bo, PageQuery pageQuery) { + return evaluationService.queryPageList(bo, pageQuery); + } + + /** + * 导出心理健康测评列表 + */ + @SaCheckPermission("xljk:evaluation:export") + @Log(title = "心理健康测评", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(XljkEvaluationBo bo, HttpServletResponse response) { + List list = evaluationService.queryList(bo); + ExcelUtil.exportExcel(list, "心理健康测评", XljkEvaluationVo.class, response); + } + + /** + * 获取心理健康测评详细信息 + */ + @SaCheckPermission("xljk:evaluation:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") @PathVariable Long id) { + return R.ok(evaluationService.queryById(id)); + } + + /** + * 新增心理健康测评 + */ + @SaCheckPermission("xljk:evaluation:add") + @Log(title = "心理健康测评", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody XljkEvaluationBo bo) { + boolean success = evaluationService.insertByBo(bo); + if (success) { + return R.ok(bo.getId()); + } else { + return R.fail("新增心理健康测评失败"); + } + } + + /** + * 修改心理健康测评 + */ + @SaCheckPermission("xljk:evaluation:edit") + @Log(title = "心理健康测评", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody XljkEvaluationBo bo) { + return toAjax(evaluationService.updateByBo(bo)); + } + + /** + * 删除心理健康测评 + */ + @SaCheckPermission("xljk:evaluation:remove") + @Log(title = "心理健康测评", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] ids) { + return toAjax(evaluationService.deleteWithValidByIds(List.of(ids), true)); + } + + /** + * 获取院系选项 + */ + @SaCheckPermission("xljk:evaluation:query") + @GetMapping("/options/department") + public R>> getDepartmentOptions() { + return R.ok(evaluationService.getDepartmentOptions()); + } + + /** + * 获取专业和班级选项 + */ + @SaCheckPermission("xljk:evaluation:query") + @GetMapping("/options/majorAndClass") + public R>>> getMajorAndClassOptions( + @RequestParam(required = false) Long departmentId + ) { + return R.ok(evaluationService.getMajorAndClassOptions(departmentId)); + } + + /** + * 获取学期选项 + */ + @SaCheckPermission("xljk:evaluation:query") + @GetMapping("/options/semester") + public R> getSemesterOptions() { + return R.ok(evaluationService.getSemesterOptions()); + } + + /** + * 发布测评 + */ + @SaCheckPermission("xljk:evaluation:publish") + @Log(title = "发布测评", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping("/{id}/publish") + public R publishEvaluation(@NotNull(message = "测评ID不能为空") @PathVariable Long id) { + return toAjax(evaluationService.publishEvaluation(id)); + } + + /** + * 完成测评 + */ + @SaCheckPermission("xljk:evaluation:complete") + @Log(title = "完成测评", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping("/{id}/complete") + public R completeEvaluation(@NotNull(message = "测评ID不能为空") @PathVariable Long id) { + return toAjax(evaluationService.completeEvaluation(id)); + } + + /** + * 获取测评统计数据 + */ + @SaCheckPermission("xljk:evaluation:statistics") + @GetMapping("/{id}/statistics") + public R> getEvaluationStatistics(@NotNull(message = "测评ID不能为空") @PathVariable Long id) { + return R.ok(evaluationService.getEvaluationStatistics(id)); + } + + /** + * 获取重点关注学生统计 + */ + @SaCheckPermission("xljk:evaluation:statistics") + @GetMapping("/statistics/focus") + public R> getFocusStudentsStatistics(XljkEvaluationBo bo) { + return R.ok(evaluationService.getFocusStudentsStatistics(bo)); + } + + /** + * 获取院系列表 + */ + @SaCheckPermission("xljk:evaluation:query") + @GetMapping("/options/colleges") + public R>> getCollegeOptions() { + return R.ok(evaluationService.getCollegeOptions()); + } + + /** + * 获取专业列表 + */ + @SaCheckPermission("xljk:evaluation:query") + @GetMapping("/options/majors") + public R>> getMajorOptions(@RequestParam(required = false) String collegeName) { + return R.ok(evaluationService.getMajorOptions(collegeName)); + } + + /** + * 获取班级列表 + */ + @SaCheckPermission("xljk:evaluation:query") + @GetMapping("/options/classes") + public R>> getClassOptions( + @RequestParam(required = false) String collegeName, + @RequestParam(required = false) String majorName + ) { + return R.ok(evaluationService.getClassOptions(collegeName, majorName)); + } + + /** + * 获取班级学生列表 + */ + @SaCheckPermission("xljk:evaluation:query") + @GetMapping("/students") + public R>> getStudentsByClass( + @RequestParam(required = false) String collegeName, + @RequestParam(required = false) String majorName, + @RequestParam(required = false) String className + ) { + return R.ok(evaluationService.getStudentsByClass(collegeName, majorName, className)); + } +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-xljk/src/main/java/org/dromara/xljk/controller/XljkEvaluationDetailController.java b/backend/ruoyi-modules/ruoyi-xljk/src/main/java/org/dromara/xljk/controller/XljkEvaluationDetailController.java new file mode 100644 index 00000000..8d2be76e --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-xljk/src/main/java/org/dromara/xljk/controller/XljkEvaluationDetailController.java @@ -0,0 +1,154 @@ +package org.dromara.xljk.controller; + +import java.util.List; +import java.util.Map; + +import lombok.RequiredArgsConstructor; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.*; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.web.core.BaseController; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.xljk.domain.vo.XljkEvaluationDetailVo; +import org.dromara.xljk.domain.bo.XljkEvaluationDetailBo; +import org.dromara.xljk.service.IXljkEvaluationDetailService; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 心理健康测评明细Controller + * + * @author Cursor AI + * @date 2025-07-02 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/xljk/evaluation/detail") +public class XljkEvaluationDetailController extends BaseController { + + private final IXljkEvaluationDetailService detailService; + + /** + * 查询心理健康测评明细列表 + */ + @SaCheckPermission("xljk:evaluation:list") + @GetMapping("/list") + public TableDataInfo list(XljkEvaluationDetailBo bo, PageQuery pageQuery) { + return detailService.queryPageList(bo, pageQuery); + } + + /** + * 导出心理健康测评明细列表 + */ + @SaCheckPermission("xljk:evaluation:export") + @Log(title = "心理健康测评明细", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(XljkEvaluationDetailBo bo, HttpServletResponse response) { + List list = detailService.queryList(bo); + ExcelUtil.exportExcel(list, "心理健康测评明细", XljkEvaluationDetailVo.class, response); + } + + /** + * 获取心理健康测评明细详细信息 + */ + @SaCheckPermission("xljk:evaluation:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") @PathVariable Long id) { + return R.ok(detailService.queryById(id)); + } + + /** + * 新增心理健康测评明细 + */ + @SaCheckPermission("xljk:evaluation:add") + @Log(title = "心理健康测评明细", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody XljkEvaluationDetailBo bo) { + boolean success = detailService.insertByBo(bo); + if (success) { + return R.ok(bo.getId()); + } else { + return R.fail("新增心理健康测评明细失败"); + } + } + + /** + * 批量新增心理健康测评明细 + */ + @SaCheckPermission("xljk:evaluation:add") + @Log(title = "批量新增心理健康测评明细", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/batch") + public R addBatch(@RequestBody List bos) { + return toAjax(detailService.insertBatch(bos)); + } + + /** + * 修改心理健康测评明细 + */ + @SaCheckPermission("xljk:evaluation:edit") + @Log(title = "心理健康测评明细", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody XljkEvaluationDetailBo bo) { + return toAjax(detailService.updateByBo(bo)); + } + + /** + * 删除心理健康测评明细 + */ + @SaCheckPermission("xljk:evaluation:remove") + @Log(title = "心理健康测评明细", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] ids) { + return toAjax(detailService.deleteWithValidByIds(List.of(ids), true)); + } + + /** + * 根据测评ID查询明细列表 + */ + @SaCheckPermission("xljk:evaluation:query") + @GetMapping("/evaluation/{evaluationId}") + public R> getDetailsByEvaluationId(@NotNull(message = "测评ID不能为空") @PathVariable Long evaluationId) { + return R.ok(detailService.queryByEvaluationId(evaluationId)); + } + + /** + * 获取学生信息 + */ + @SaCheckPermission("xljk:evaluation:query") + @GetMapping("/students/{classId}") + public R>> getStudentsByClassId(@NotNull(message = "班级ID不能为空") @PathVariable Long classId) { + return R.ok(detailService.getStudentsByClassId(classId)); + } + + /** + * 批量更新学生心理状态 + */ + @SaCheckPermission("xljk:evaluation:edit") + @Log(title = "批量更新心理状态", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping("/batch/mentalStatus") + public R batchUpdateMentalStatus(@RequestBody List bos) { + return toAjax(detailService.batchUpdateMentalStatus(bos)); + } + + /** + * 获取重点关注学生列表 + */ + @SaCheckPermission("xljk:evaluation:query") + @GetMapping("/focus") + public TableDataInfo getFocusStudents(XljkEvaluationDetailBo bo, PageQuery pageQuery) { + return detailService.queryFocusStudents(bo, pageQuery); + } +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-xljk/src/main/java/org/dromara/xljk/domain/XljkEvaluation.java b/backend/ruoyi-modules/ruoyi-xljk/src/main/java/org/dromara/xljk/domain/XljkEvaluation.java new file mode 100644 index 00000000..2f97facf --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-xljk/src/main/java/org/dromara/xljk/domain/XljkEvaluation.java @@ -0,0 +1,85 @@ +package org.dromara.xljk.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import org.dromara.common.tenant.core.TenantEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.Date; + +/** + * 心理健康测评对象 xljk_evaluation + * + * @author Cursor AI + * @date 2025-07-02 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("xljk_evaluation") +public class XljkEvaluation extends TenantEntity { + + private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + @TableId(value = "id") + private Long id; + + /** + * 院系ID + */ + private Long departmentId; + + /** + * 院系名称 + */ + private String departmentName; + + /** + * 测评名称 + */ + private String evaluationName; + + /** + * 专业ID + */ + private Long majorId; + + /** + * 专业名称 + */ + private String majorName; + + /** + * 班级ID + */ + private Long classId; + + /** + * 班级名称 + */ + private String className; + + /** + * 学期(如2024上学期) + */ + private String semester; + + /** + * 状态(0-草稿,1-已发布,2-已完成) + */ + private String status; + + /** + * 创建者姓名 + */ + private String createName; + + /** + * 备注 + */ + private String remark; + +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-xljk/src/main/java/org/dromara/xljk/domain/XljkEvaluationDetail.java b/backend/ruoyi-modules/ruoyi-xljk/src/main/java/org/dromara/xljk/domain/XljkEvaluationDetail.java new file mode 100644 index 00000000..4758c22a --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-xljk/src/main/java/org/dromara/xljk/domain/XljkEvaluationDetail.java @@ -0,0 +1,80 @@ +package org.dromara.xljk.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import org.dromara.common.tenant.core.TenantEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.Date; + +/** + * 心理健康测评明细对象 xljk_evaluation_detail + * + * @author Cursor AI + * @date 2025-07-02 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("xljk_evaluation_detail") +public class XljkEvaluationDetail extends TenantEntity { + + private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + @TableId(value = "id") + private Long id; + + /** + * 测评表ID + */ + private Long evaluationId; + + /** + * 学生ID + */ + private Long studentId; + + /** + * 学号 + */ + private String studentNo; + + /** + * 学生姓名 + */ + private String studentName; + + /** + * 性别(0-男,1-女,2-未知) + */ + private String gender; + + /** + * 出生日期 + */ + private Date birthDate; + + /** + * 联系电话 + */ + private String phone; + + /** + * 心理状态(1-健康,2-良好,3-重点关注) + */ + private String mentalStatus; + + /** + * 分数(仅重点关注时填写) + */ + private Integer score; + + /** + * 备注 + */ + private String remark; + +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-xljk/src/main/java/org/dromara/xljk/domain/bo/XljkEvaluationBo.java b/backend/ruoyi-modules/ruoyi-xljk/src/main/java/org/dromara/xljk/domain/bo/XljkEvaluationBo.java new file mode 100644 index 00000000..616562e8 --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-xljk/src/main/java/org/dromara/xljk/domain/bo/XljkEvaluationBo.java @@ -0,0 +1,108 @@ +package org.dromara.xljk.domain.bo; + +import org.dromara.xljk.domain.XljkEvaluation; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import jakarta.validation.constraints.*; +import java.util.Date; +import java.util.List; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 心理健康测评业务对象 xljk_evaluation + * + * @author Cursor AI + * @date 2025-07-02 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = XljkEvaluation.class, reverseConvertGenerate = false) +public class XljkEvaluationBo extends BaseEntity { + + /** + * 主键ID + */ + @NotNull(message = "主键ID不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 测评名称 + */ + @NotBlank(message = "测评名称不能为空", groups = { AddGroup.class, EditGroup.class }) + private String evaluationName; + + /** + * 专业ID + */ + @NotNull(message = "专业ID不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long majorId; + + /** + * 专业名称 + */ + @NotBlank(message = "专业名称不能为空", groups = { AddGroup.class, EditGroup.class }) + private String majorName; + + /** + * 班级ID + */ + @NotNull(message = "班级ID不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long classId; + + /** + * 班级名称 + */ + @NotBlank(message = "班级名称不能为空", groups = { AddGroup.class, EditGroup.class }) + private String className; + + /** + * 学期(如2024上学期) + */ + @NotBlank(message = "学期不能为空", groups = { AddGroup.class, EditGroup.class }) + private String semester; + + /** + * 状态(0-草稿,1-已发布,2-已完成) + */ + private String status; + + /** + * 创建者姓名 + */ + private String createName; + + /** + * 备注 + */ + private String remark; + + /** + * 状态IN查询(用于状态过滤) + */ + private List statusIn; + + /** + * 专业ID IN查询(用于专业过滤) + */ + private List majorIdIn; + + /** + * 班级ID IN查询(用于班级过滤) + */ + private List classIdIn; + + /** + * 学期IN查询(用于学期过滤) + */ + private List semesterIn; + + /** + * 创建者ID IN查询(用于权限过滤) + */ + private List createByIn; + +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-xljk/src/main/java/org/dromara/xljk/domain/bo/XljkEvaluationDetailBo.java b/backend/ruoyi-modules/ruoyi-xljk/src/main/java/org/dromara/xljk/domain/bo/XljkEvaluationDetailBo.java new file mode 100644 index 00000000..3f21bd42 --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-xljk/src/main/java/org/dromara/xljk/domain/bo/XljkEvaluationDetailBo.java @@ -0,0 +1,108 @@ +package org.dromara.xljk.domain.bo; + +import org.dromara.xljk.domain.XljkEvaluationDetail; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import jakarta.validation.constraints.*; +import java.util.Date; +import java.util.List; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 心理健康测评明细业务对象 xljk_evaluation_detail + * + * @author Cursor AI + * @date 2025-07-02 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = XljkEvaluationDetail.class, reverseConvertGenerate = false) +public class XljkEvaluationDetailBo extends BaseEntity { + + /** + * 主键ID + */ + @NotNull(message = "主键ID不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 测评表ID + */ + @NotNull(message = "测评表ID不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long evaluationId; + + /** + * 学生ID + */ + @NotNull(message = "学生ID不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long studentId; + + /** + * 学号 + */ + @NotBlank(message = "学号不能为空", groups = { AddGroup.class, EditGroup.class }) + private String studentNo; + + /** + * 学生姓名 + */ + @NotBlank(message = "学生姓名不能为空", groups = { AddGroup.class, EditGroup.class }) + private String studentName; + + /** + * 性别(0-男,1-女,2-未知) + */ + private String gender; + + /** + * 出生日期 + */ + @JsonFormat(pattern = "yyyy-MM-dd") + private Date birthDate; + + /** + * 联系电话 + */ + private String phone; + + /** + * 心理状态(1-健康,2-良好,3-重点关注) + */ + @NotBlank(message = "心理状态不能为空", groups = { AddGroup.class, EditGroup.class }) + private String mentalStatus; + + /** + * 分数(仅重点关注时填写) + */ + private Integer score; + + /** + * 备注 + */ + private String remark; + + /** + * 测评ID IN查询(用于批量查询) + */ + private List evaluationIdIn; + + /** + * 学生ID IN查询(用于批量查询) + */ + private List studentIdIn; + + /** + * 心理状态IN查询(用于状态过滤) + */ + private List mentalStatusIn; + + /** + * 批量学生数据(用于批量保存) + */ + private List studentList; + +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-xljk/src/main/java/org/dromara/xljk/domain/vo/XljkEvaluationDetailVo.java b/backend/ruoyi-modules/ruoyi-xljk/src/main/java/org/dromara/xljk/domain/vo/XljkEvaluationDetailVo.java new file mode 100644 index 00000000..66f21831 --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-xljk/src/main/java/org/dromara/xljk/domain/vo/XljkEvaluationDetailVo.java @@ -0,0 +1,144 @@ +package org.dromara.xljk.domain.vo; + +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; +import org.dromara.xljk.domain.XljkEvaluationDetail; +import cn.idev.excel.annotation.ExcelIgnoreUnannotated; +import cn.idev.excel.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 心理健康测评明细视图对象 xljk_evaluation_detail + * + * @author Cursor AI + * @date 2025-07-02 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = XljkEvaluationDetail.class) +public class XljkEvaluationDetailVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + @ExcelProperty(value = "主键ID") + private Long id; + + /** + * 测评表ID + */ + @ExcelProperty(value = "测评表ID") + private Long evaluationId; + + /** + * 学生ID + */ + @ExcelProperty(value = "学生ID") + private Long studentId; + + /** + * 学号 + */ + @ExcelProperty(value = "学号") + private String studentNo; + + /** + * 学生姓名 + */ + @ExcelProperty(value = "学生姓名") + private String studentName; + + /** + * 性别(0-男,1-女,2-未知) + */ + @ExcelProperty(value = "性别", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_user_sex") + private String gender; + + /** + * 出生日期 + */ + @ExcelProperty(value = "出生日期") + @JsonFormat(pattern = "yyyy-MM-dd") + private Date birthDate; + + /** + * 联系电话 + */ + @ExcelProperty(value = "联系电话") + private String phone; + + /** + * 心理状态(1-健康,2-良好,3-重点关注) + */ + @ExcelProperty(value = "心理状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "xljk_mental_status") + private String mentalStatus; + + /** + * 分数(仅重点关注时填写) + */ + @ExcelProperty(value = "分数") + private Integer score; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 测评名称(非数据库字段) + */ + @ExcelProperty(value = "测评名称") + private String evaluationName; + + /** + * 班级名称(非数据库字段) + */ + @ExcelProperty(value = "班级名称") + private String className; + + /** + * 专业名称(非数据库字段) + */ + @ExcelProperty(value = "专业名称") + private String majorName; + + /** + * 学期(非数据库字段) + */ + @ExcelProperty(value = "学期") + private String semester; + + /** + * 创建者 + */ + private Long createBy; + + /** + * 创建时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + /** + * 更新者 + */ + private Long updateBy; + + /** + * 更新时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-xljk/src/main/java/org/dromara/xljk/domain/vo/XljkEvaluationVo.java b/backend/ruoyi-modules/ruoyi-xljk/src/main/java/org/dromara/xljk/domain/vo/XljkEvaluationVo.java new file mode 100644 index 00000000..a1218523 --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-xljk/src/main/java/org/dromara/xljk/domain/vo/XljkEvaluationVo.java @@ -0,0 +1,136 @@ +package org.dromara.xljk.domain.vo; + +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; +import org.dromara.xljk.domain.XljkEvaluation; +import cn.idev.excel.annotation.ExcelIgnoreUnannotated; +import cn.idev.excel.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 心理健康测评视图对象 xljk_evaluation + * + * @author Cursor AI + * @date 2025-07-02 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = XljkEvaluation.class) +public class XljkEvaluationVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + @ExcelProperty(value = "主键ID") + private Long id; + + /** + * 院系ID + */ + @ExcelProperty(value = "院系ID") + private Long departmentId; + + /** + * 院系名称 + */ + @ExcelProperty(value = "院系名称") + private String departmentName; + + /** + * 测评名称 + */ + @ExcelProperty(value = "测评名称") + private String evaluationName; + + /** + * 专业ID + */ + @ExcelProperty(value = "专业ID") + private Long majorId; + + /** + * 专业名称 + */ + @ExcelProperty(value = "专业名称") + private String majorName; + + /** + * 班级ID + */ + @ExcelProperty(value = "班级ID") + private Long classId; + + /** + * 班级名称 + */ + @ExcelProperty(value = "班级名称") + private String className; + + /** + * 学期(如2024上学期) + */ + @ExcelProperty(value = "学期") + private String semester; + + /** + * 状态(0-草稿,1-已发布,2-已完成) + */ + @ExcelProperty(value = "状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "xljk_evaluation_status") + private String status; + + /** + * 创建者姓名 + */ + @ExcelProperty(value = "创建者姓名") + private String createName; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 学生数量(非数据库字段) + */ + @ExcelProperty(value = "学生数量") + private Integer studentCount; + + /** + * 重点关注数量(非数据库字段) + */ + @ExcelProperty(value = "重点关注数量") + private Integer focusCount; + + /** + * 创建者 + */ + private Long createBy; + + /** + * 创建时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + /** + * 更新者 + */ + private Long updateBy; + + /** + * 更新时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date updateTime; +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-xljk/src/main/java/org/dromara/xljk/mapper/XljkEvaluationDetailMapper.java b/backend/ruoyi-modules/ruoyi-xljk/src/main/java/org/dromara/xljk/mapper/XljkEvaluationDetailMapper.java new file mode 100644 index 00000000..c1417fcd --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-xljk/src/main/java/org/dromara/xljk/mapper/XljkEvaluationDetailMapper.java @@ -0,0 +1,15 @@ +package org.dromara.xljk.mapper; + +import org.dromara.xljk.domain.XljkEvaluationDetail; +import org.dromara.xljk.domain.vo.XljkEvaluationDetailVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 心理健康测评明细Mapper接口 + * + * @author Cursor AI + * @date 2025-07-02 + */ +public interface XljkEvaluationDetailMapper extends BaseMapperPlus { + +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-xljk/src/main/java/org/dromara/xljk/mapper/XljkEvaluationMapper.java b/backend/ruoyi-modules/ruoyi-xljk/src/main/java/org/dromara/xljk/mapper/XljkEvaluationMapper.java new file mode 100644 index 00000000..637cc461 --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-xljk/src/main/java/org/dromara/xljk/mapper/XljkEvaluationMapper.java @@ -0,0 +1,15 @@ +package org.dromara.xljk.mapper; + +import org.dromara.xljk.domain.XljkEvaluation; +import org.dromara.xljk.domain.vo.XljkEvaluationVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 心理健康测评Mapper接口 + * + * @author Cursor AI + * @date 2025-07-02 + */ +public interface XljkEvaluationMapper extends BaseMapperPlus { + +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-xljk/src/main/java/org/dromara/xljk/service/IXljkEvaluationDetailService.java b/backend/ruoyi-modules/ruoyi-xljk/src/main/java/org/dromara/xljk/service/IXljkEvaluationDetailService.java new file mode 100644 index 00000000..15129b48 --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-xljk/src/main/java/org/dromara/xljk/service/IXljkEvaluationDetailService.java @@ -0,0 +1,119 @@ +package org.dromara.xljk.service; + +import org.dromara.xljk.domain.vo.XljkEvaluationDetailVo; +import org.dromara.xljk.domain.bo.XljkEvaluationDetailBo; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 心理健康测评明细Service接口 + * + * @author Cursor AI + * @date 2025-07-02 + */ +public interface IXljkEvaluationDetailService { + + /** + * 查询心理健康测评明细 + * + * @param id 主键 + * @return 心理健康测评明细 + */ + XljkEvaluationDetailVo queryById(Long id); + + /** + * 分页查询心理健康测评明细列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 心理健康测评明细分页列表 + */ + TableDataInfo queryPageList(XljkEvaluationDetailBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的心理健康测评明细列表 + * + * @param bo 查询条件 + * @return 心理健康测评明细列表 + */ + List queryList(XljkEvaluationDetailBo bo); + + /** + * 新增心理健康测评明细 + * + * @param bo 心理健康测评明细 + * @return 是否新增成功 + */ + Boolean insertByBo(XljkEvaluationDetailBo bo); + + /** + * 批量新增心理健康测评明细 + * + * @param bos 心理健康测评明细列表 + * @return 是否新增成功 + */ + Boolean insertBatch(List bos); + + /** + * 修改心理健康测评明细 + * + * @param bo 心理健康测评明细 + * @return 是否修改成功 + */ + Boolean updateByBo(XljkEvaluationDetailBo bo); + + /** + * 校验并批量删除心理健康测评明细信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 根据测评ID查询明细列表 + * + * @param evaluationId 测评ID + * @return 明细列表 + */ + List queryByEvaluationId(Long evaluationId); + + /** + * 根据测评ID删除明细 + * + * @param evaluationId 测评ID + * @return 是否删除成功 + */ + Boolean deleteByEvaluationId(Long evaluationId); + + /** + * 获取学生信息(从学生信息管理模块) + * + * @param classId 班级ID + * @return 学生信息列表 + */ + List> getStudentsByClassId(Long classId); + + /** + * 批量更新学生心理状态 + * + * @param bos 学生心理状态数据 + * @return 是否更新成功 + */ + Boolean batchUpdateMentalStatus(List bos); + + /** + * 获取重点关注学生列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 重点关注学生列表 + */ + TableDataInfo queryFocusStudents(XljkEvaluationDetailBo bo, PageQuery pageQuery); + +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-xljk/src/main/java/org/dromara/xljk/service/IXljkEvaluationService.java b/backend/ruoyi-modules/ruoyi-xljk/src/main/java/org/dromara/xljk/service/IXljkEvaluationService.java new file mode 100644 index 00000000..7b4bd67a --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-xljk/src/main/java/org/dromara/xljk/service/IXljkEvaluationService.java @@ -0,0 +1,167 @@ +package org.dromara.xljk.service; + +import org.dromara.xljk.domain.vo.XljkEvaluationVo; +import org.dromara.xljk.domain.bo.XljkEvaluationBo; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 心理健康测评Service接口 + * + * @author Cursor AI + * @date 2025-07-02 + */ +public interface IXljkEvaluationService { + + /** + * 查询心理健康测评 + * + * @param id 主键 + * @return 心理健康测评 + */ + XljkEvaluationVo queryById(Long id); + + /** + * 分页查询心理健康测评列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 心理健康测评分页列表 + */ + TableDataInfo queryPageList(XljkEvaluationBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的心理健康测评列表 + * + * @param bo 查询条件 + * @return 心理健康测评列表 + */ + List queryList(XljkEvaluationBo bo); + + /** + * 新增心理健康测评 + * + * @param bo 心理健康测评 + * @return 是否新增成功 + */ + Boolean insertByBo(XljkEvaluationBo bo); + + /** + * 修改心理健康测评 + * + * @param bo 心理健康测评 + * @return 是否修改成功 + */ + Boolean updateByBo(XljkEvaluationBo bo); + + /** + * 校验并批量删除心理健康测评信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取院系选项 + * + * @return 院系选项数据 + */ + List> getCollegeOptions(); + + /** + * 获取专业选项 + * + * @param collegeName 院系名称,可为空 + * @return 专业选项数据 + */ + List> getMajorOptions(String collegeName); + + /** + * 获取班级选项 + * + * @param collegeName 院系名称,可为空 + * @param majorName 专业名称,可为空 + * @return 班级选项数据 + */ + List> getClassOptions(String collegeName, String majorName); + + /** + * 获取学生列表 + * + * @param collegeName 院系名称,可为空 + * @param majorName 专业名称,可为空 + * @param className 班级名称,可为空 + * @return 学生列表数据 + */ + List> getStudentsByClass(String collegeName, String majorName, String className); + + /** + * 获取院系选项 + * + * @return 院系选项数据 + */ + List> getDepartmentOptions(); + + /** + * 获取专业和班级选项 + * + * @param departmentId 院系ID,可为空 + * @return 专业和班级选项数据 + */ + Map>> getMajorAndClassOptions(Long departmentId); + + /** + * 获取专业和班级选项(兼容旧方法) + * + * @return 专业和班级选项数据 + */ + default Map>> getMajorAndClassOptions() { + return getMajorAndClassOptions(null); + } + + /** + * 获取学期选项 + * + * @return 学期选项列表 + */ + List getSemesterOptions(); + + /** + * 发布测评 + * + * @param id 测评ID + * @return 是否成功 + */ + Boolean publishEvaluation(Long id); + + /** + * 完成测评 + * + * @param id 测评ID + * @return 是否成功 + */ + Boolean completeEvaluation(Long id); + + /** + * 获取测评统计数据 + * + * @param id 测评ID + * @return 统计数据 + */ + Map getEvaluationStatistics(Long id); + + /** + * 获取重点关注学生统计 + * + * @param bo 查询条件 + * @return 统计数据 + */ + Map getFocusStudentsStatistics(XljkEvaluationBo bo); + +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-xljk/src/main/java/org/dromara/xljk/service/impl/XljkEvaluationDetailServiceImpl.java b/backend/ruoyi-modules/ruoyi-xljk/src/main/java/org/dromara/xljk/service/impl/XljkEvaluationDetailServiceImpl.java new file mode 100644 index 00000000..2f69b37c --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-xljk/src/main/java/org/dromara/xljk/service/impl/XljkEvaluationDetailServiceImpl.java @@ -0,0 +1,460 @@ +package org.dromara.xljk.service.impl; + +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import cn.hutool.core.collection.CollUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.dromara.xljk.domain.bo.XljkEvaluationDetailBo; +import org.dromara.xljk.domain.vo.XljkEvaluationDetailVo; +import org.dromara.xljk.domain.XljkEvaluationDetail; +import org.dromara.xljk.domain.XljkEvaluation; +import org.dromara.xljk.mapper.XljkEvaluationDetailMapper; +import org.dromara.xljk.mapper.XljkEvaluationMapper; +import org.dromara.xljk.service.IXljkEvaluationDetailService; +import org.dromara.common.core.exception.ServiceException; + +import java.util.*; + +/** + * 心理健康测评明细Service业务层处理 + * + * @author Cursor AI + * @date 2025-07-02 + */ +@Slf4j +@RequiredArgsConstructor +@Service +public class XljkEvaluationDetailServiceImpl implements IXljkEvaluationDetailService { + + private final XljkEvaluationDetailMapper baseMapper; + private final XljkEvaluationMapper evaluationMapper; + + /** + * 查询心理健康测评明细 + * + * @param id 主键 + * @return 心理健康测评明细 + */ + @Override + public XljkEvaluationDetailVo queryById(Long id) { + XljkEvaluationDetailVo vo = baseMapper.selectVoById(id); + if (vo != null) { + // 查询测评信息 + XljkEvaluation evaluation = evaluationMapper.selectById(vo.getEvaluationId()); + if (evaluation != null) { + vo.setEvaluationName(evaluation.getEvaluationName()); + vo.setClassName(evaluation.getClassName()); + vo.setMajorName(evaluation.getMajorName()); + vo.setSemester(evaluation.getSemester()); + } + } + return vo; + } + + /** + * 分页查询心理健康测评明细列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 心理健康测评明细分页列表 + */ + @Override + public TableDataInfo queryPageList(XljkEvaluationDetailBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + + // 补充测评信息 + if (result.getRecords().size() > 0) { + // 获取所有测评ID + Set evaluationIds = new HashSet<>(); + for (XljkEvaluationDetailVo vo : result.getRecords()) { + evaluationIds.add(vo.getEvaluationId()); + } + + // 批量查询测评信息 + LambdaQueryWrapper evalLqw = Wrappers.lambdaQuery(); + evalLqw.in(XljkEvaluation::getId, evaluationIds); + List evaluations = evaluationMapper.selectList(evalLqw); + Map evaluationMap = new HashMap<>(); + for (XljkEvaluation evaluation : evaluations) { + evaluationMap.put(evaluation.getId(), evaluation); + } + + // 填充测评信息 + for (XljkEvaluationDetailVo vo : result.getRecords()) { + XljkEvaluation evaluation = evaluationMap.get(vo.getEvaluationId()); + if (evaluation != null) { + vo.setEvaluationName(evaluation.getEvaluationName()); + vo.setClassName(evaluation.getClassName()); + vo.setMajorName(evaluation.getMajorName()); + vo.setSemester(evaluation.getSemester()); + } + } + } + + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的心理健康测评明细列表 + * + * @param bo 查询条件 + * @return 心理健康测评明细列表 + */ + @Override + public List queryList(XljkEvaluationDetailBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(XljkEvaluationDetailBo bo) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(bo.getEvaluationId() != null, XljkEvaluationDetail::getEvaluationId, bo.getEvaluationId()); + lqw.eq(bo.getStudentId() != null, XljkEvaluationDetail::getStudentId, bo.getStudentId()); + lqw.like(StringUtils.isNotBlank(bo.getStudentNo()), XljkEvaluationDetail::getStudentNo, bo.getStudentNo()); + lqw.like(StringUtils.isNotBlank(bo.getStudentName()), XljkEvaluationDetail::getStudentName, bo.getStudentName()); + lqw.eq(StringUtils.isNotBlank(bo.getGender()), XljkEvaluationDetail::getGender, bo.getGender()); + lqw.eq(StringUtils.isNotBlank(bo.getMentalStatus()), XljkEvaluationDetail::getMentalStatus, bo.getMentalStatus()); + lqw.in(CollUtil.isNotEmpty(bo.getEvaluationIdIn()), XljkEvaluationDetail::getEvaluationId, bo.getEvaluationIdIn()); + lqw.in(CollUtil.isNotEmpty(bo.getStudentIdIn()), XljkEvaluationDetail::getStudentId, bo.getStudentIdIn()); + lqw.in(CollUtil.isNotEmpty(bo.getMentalStatusIn()), XljkEvaluationDetail::getMentalStatus, bo.getMentalStatusIn()); + return lqw; + } + + /** + * 新增心理健康测评明细 + * + * @param bo 心理健康测评明细 + * @return 是否新增成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean insertByBo(XljkEvaluationDetailBo bo) { + XljkEvaluationDetail add = MapstructUtils.convert(bo, XljkEvaluationDetail.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 批量新增心理健康测评明细 + * + * @param bos 心理健康测评明细列表 + * @return 是否新增成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean insertBatch(List bos) { + if (CollUtil.isEmpty(bos)) { + return false; + } + + List entities = new ArrayList<>(); + for (XljkEvaluationDetailBo bo : bos) { + XljkEvaluationDetail entity = MapstructUtils.convert(bo, XljkEvaluationDetail.class); + validEntityBeforeSave(entity); + entities.add(entity); + } + + return baseMapper.insertBatch(entities); + } + + /** + * 修改心理健康测评明细 + * + * @param bo 心理健康测评明细 + * @return 是否修改成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean updateByBo(XljkEvaluationDetailBo bo) { + XljkEvaluationDetail update = MapstructUtils.convert(bo, XljkEvaluationDetail.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + * + * @param entity 实体类数据 + */ + private void validEntityBeforeSave(XljkEvaluationDetail entity) { + // 校验评测状态 + if (entity.getEvaluationId() != null) { + XljkEvaluation evaluation = evaluationMapper.selectById(entity.getEvaluationId()); + if (evaluation != null && "2".equals(evaluation.getStatus())) { + throw new ServiceException("测评已完成,不能修改"); + } + } + + // 校验分数 + if ("3".equals(entity.getMentalStatus()) && entity.getScore() == null) { + throw new ServiceException("重点关注状态必须填写分数"); + } + } + + /** + * 校验并批量删除心理健康测评明细信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if (isValid) { + // 校验是否允许删除 + for (Long id : ids) { + XljkEvaluationDetail detail = baseMapper.selectById(id); + if (detail != null) { + XljkEvaluation evaluation = evaluationMapper.selectById(detail.getEvaluationId()); + if (evaluation != null && !"0".equals(evaluation.getStatus())) { + throw new ServiceException("测评已发布或已完成,不能删除"); + } + } + } + } + return baseMapper.deleteBatchIds(ids) > 0; + } + + /** + * 根据测评ID查询明细列表 + * + * @param evaluationId 测评ID + * @return 明细列表 + */ + @Override + public List queryByEvaluationId(Long evaluationId) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(XljkEvaluationDetail::getEvaluationId, evaluationId); + return baseMapper.selectVoList(lqw); + } + + /** + * 根据测评ID删除明细 + * + * @param evaluationId 测评ID + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteByEvaluationId(Long evaluationId) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(XljkEvaluationDetail::getEvaluationId, evaluationId); + return baseMapper.delete(lqw) >= 0; + } + + /** + * 获取学生信息(从学生信息管理模块) + * + * @param classId 班级ID + * @return 学生信息列表 + */ + @Override + public List> getStudentsByClassId(Long classId) { + // 模拟数据,实际项目中应该从学生信息管理模块获取 + List> students = new ArrayList<>(); + + if (classId == 1001) { + // 计算机2301班 + for (int i = 1; i <= 5; i++) { + Map student = new HashMap<>(); + student.put("id", 10000 + i); + student.put("studentNo", "2024" + String.format("%03d", i)); + student.put("studentName", getStudentName(i)); + student.put("gender", i % 2 == 0 ? "1" : "0"); + student.put("birthDate", "2005-" + (6 + i % 7) + "-" + (10 + i % 20)); + student.put("phone", "1380013800" + i); + students.add(student); + } + } else if (classId == 1002) { + // 电子2302班 + for (int i = 1; i <= 5; i++) { + Map student = new HashMap<>(); + student.put("id", 20000 + i); + student.put("studentNo", "2302" + String.format("%03d", i)); + student.put("studentName", getStudentName(i + 5)); + student.put("gender", i % 2 == 0 ? "1" : "0"); + student.put("birthDate", "2005-" + (i % 12 + 1) + "-" + (i % 28 + 1)); + student.put("phone", "1390013900" + i); + students.add(student); + } + } else if (classId == 1003) { + // 会计2303班 + for (int i = 1; i <= 5; i++) { + Map student = new HashMap<>(); + student.put("id", 30000 + i); + student.put("studentNo", "2303" + String.format("%03d", i)); + student.put("studentName", getStudentName(i + 10)); + student.put("gender", i % 2 == 0 ? "1" : "0"); + student.put("birthDate", "2005-" + (i % 12 + 1) + "-" + (i % 28 + 1)); + student.put("phone", "1370013700" + i); + students.add(student); + } + } + + return students; + } + + /** + * 获取学生姓名 + */ + private String getStudentName(int index) { + String[] names = {"张三", "李四", "王五", "赵六", "钱七", "孙八", "周九", "吴十", + "郑一", "王二", "陈三", "林四", "黄五", "赵六", "吴七"}; + return names[(index - 1) % names.length]; + } + + /** + * 批量更新学生心理状态 + * + * @param bos 批量更新请求 + * @return 是否成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean batchUpdateMentalStatus(List bos) { + if (CollUtil.isEmpty(bos)) { + return false; + } + + // 获取测评ID + Long evaluationId = bos.get(0).getEvaluationId(); + log.info("批量更新心理状态 - 接收到的测评ID: {}, 类型: {}", evaluationId, evaluationId != null ? evaluationId.getClass().getName() : "null"); + + // 获取测评信息 + XljkEvaluation evaluation = evaluationMapper.selectById(evaluationId); + if (evaluation == null) { + log.error("测评不存在 - 查询ID: {}", evaluationId); + throw new ServiceException("测评不存在"); + } + + log.info("成功找到测评记录 - ID: {}, 名称: {}", evaluation.getId(), evaluation.getEvaluationName()); + + if (!"0".equals(evaluation.getStatus())) { + throw new ServiceException("只能修改草稿状态的测评"); + } + + try { + // 分类处理 + for (XljkEvaluationDetailBo bo : bos) { + // 校验数据 + if ("3".equals(bo.getMentalStatus()) && bo.getScore() == null) { + throw new ServiceException("重点关注状态必须填写分数"); + } + + // 判断是新增还是更新 + if (bo.getId() != null) { + // 更新 + XljkEvaluationDetail entity = MapstructUtils.convert(bo, XljkEvaluationDetail.class); + baseMapper.updateById(entity); + } else { + // 新增 + XljkEvaluationDetail entity = MapstructUtils.convert(bo, XljkEvaluationDetail.class); + baseMapper.insert(entity); + } + } + + // 更新测评主表的学生总数和重点关注学生数 + updateEvaluationStatistics(evaluationId); + + return true; + } catch (Exception e) { + log.error("批量更新学生心理状态异常", e); + throw new ServiceException("批量更新失败:" + e.getMessage()); + } + } + + /** + * 更新测评主表的统计信息 + * + * @param evaluationId 测评ID + */ + private void updateEvaluationStatistics(Long evaluationId) { + try { + // 查询总学生数 + LambdaQueryWrapper countQuery = Wrappers.lambdaQuery(); + countQuery.eq(XljkEvaluationDetail::getEvaluationId, evaluationId); + long studentCount = baseMapper.selectCount(countQuery); + + // 查询重点关注学生数 + LambdaQueryWrapper focusQuery = Wrappers.lambdaQuery(); + focusQuery.eq(XljkEvaluationDetail::getEvaluationId, evaluationId) + .eq(XljkEvaluationDetail::getMentalStatus, "3"); + long focusCount = baseMapper.selectCount(focusQuery); + + // 更新测评主表 + XljkEvaluation evaluation = new XljkEvaluation(); + evaluation.setId(evaluationId); + // 使用额外字段存储统计信息 + // 注意:需要确保XljkEvaluation实体类中有这些字段 + + // TODO: 如果XljkEvaluation实体类中没有这些字段,需要通过其他方式更新 + // 例如:使用自定义SQL更新或者在XljkEvaluation实体类中添加这些字段 + + evaluationMapper.updateById(evaluation); + + log.info("更新测评统计信息成功 - 测评ID: {}, 学生总数: {}, 重点关注学生数: {}", evaluationId, studentCount, focusCount); + } catch (Exception e) { + log.error("更新测评统计信息失败", e); + } + } + + /** + * 获取重点关注学生列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 重点关注学生列表 + */ + @Override + public TableDataInfo queryFocusStudents(XljkEvaluationDetailBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + // 只查询重点关注的学生 + lqw.eq(XljkEvaluationDetail::getMentalStatus, "3"); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + + // 补充测评信息 + if (result.getRecords().size() > 0) { + // 获取所有测评ID + Set evaluationIds = new HashSet<>(); + for (XljkEvaluationDetailVo vo : result.getRecords()) { + evaluationIds.add(vo.getEvaluationId()); + } + + // 批量查询测评信息 + LambdaQueryWrapper evalLqw = Wrappers.lambdaQuery(); + evalLqw.in(XljkEvaluation::getId, evaluationIds); + List evaluations = evaluationMapper.selectList(evalLqw); + Map evaluationMap = new HashMap<>(); + for (XljkEvaluation evaluation : evaluations) { + evaluationMap.put(evaluation.getId(), evaluation); + } + + // 填充测评信息 + for (XljkEvaluationDetailVo vo : result.getRecords()) { + XljkEvaluation evaluation = evaluationMap.get(vo.getEvaluationId()); + if (evaluation != null) { + vo.setEvaluationName(evaluation.getEvaluationName()); + vo.setClassName(evaluation.getClassName()); + vo.setMajorName(evaluation.getMajorName()); + vo.setSemester(evaluation.getSemester()); + } + } + } + + return TableDataInfo.build(result); + } +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-xljk/src/main/java/org/dromara/xljk/service/impl/XljkEvaluationServiceImpl.java b/backend/ruoyi-modules/ruoyi-xljk/src/main/java/org/dromara/xljk/service/impl/XljkEvaluationServiceImpl.java new file mode 100644 index 00000000..21e2948d --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-xljk/src/main/java/org/dromara/xljk/service/impl/XljkEvaluationServiceImpl.java @@ -0,0 +1,953 @@ +package org.dromara.xljk.service.impl; + +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.date.DateUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.dromara.xljk.domain.bo.XljkEvaluationBo; +import org.dromara.xljk.domain.vo.XljkEvaluationVo; +import org.dromara.xljk.domain.XljkEvaluation; +import org.dromara.xljk.domain.XljkEvaluationDetail; +import org.dromara.xljk.mapper.XljkEvaluationMapper; +import org.dromara.xljk.mapper.XljkEvaluationDetailMapper; +import org.dromara.xljk.service.IXljkEvaluationService; +import org.dromara.xljk.service.IXljkEvaluationDetailService; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.service.UserService; + +import java.util.*; +import java.sql.*; +import javax.sql.DataSource; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * 心理健康测评Service业务层处理 + * + * @author Cursor AI + * @date 2025-07-02 + */ +@Slf4j +@RequiredArgsConstructor +@Service +public class XljkEvaluationServiceImpl implements IXljkEvaluationService { + + private final XljkEvaluationMapper baseMapper; + private final XljkEvaluationDetailMapper detailMapper; + private final IXljkEvaluationDetailService detailService; + private final UserService userService; + @Autowired + private DataSource dataSource; + + /** + * 查询心理健康测评 + * + * @param id 主键 + * @return 心理健康测评 + */ + @Override + public XljkEvaluationVo queryById(Long id) { + XljkEvaluationVo vo = baseMapper.selectVoById(id); + if (vo != null) { + // 查询学生数量和重点关注数量 + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(XljkEvaluationDetail::getEvaluationId, id); + int studentCount = detailMapper.selectCount(lqw).intValue(); + vo.setStudentCount(studentCount); + + lqw.clear(); + lqw.eq(XljkEvaluationDetail::getEvaluationId, id) + .eq(XljkEvaluationDetail::getMentalStatus, "3"); + int focusCount = detailMapper.selectCount(lqw).intValue(); + vo.setFocusCount(focusCount); + } + return vo; + } + + /** + * 分页查询心理健康测评列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 心理健康测评分页列表 + */ + @Override + public TableDataInfo queryPageList(XljkEvaluationBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + + // 查询学生数量和重点关注数量 + for (XljkEvaluationVo vo : result.getRecords()) { + LambdaQueryWrapper detailLqw = Wrappers.lambdaQuery(); + detailLqw.eq(XljkEvaluationDetail::getEvaluationId, vo.getId()); + int studentCount = detailMapper.selectCount(detailLqw).intValue(); + vo.setStudentCount(studentCount); + + detailLqw.clear(); + detailLqw.eq(XljkEvaluationDetail::getEvaluationId, vo.getId()) + .eq(XljkEvaluationDetail::getMentalStatus, "3"); + int focusCount = detailMapper.selectCount(detailLqw).intValue(); + vo.setFocusCount(focusCount); + } + + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的心理健康测评列表 + * + * @param bo 查询条件 + * @return 心理健康测评列表 + */ + @Override + public List queryList(XljkEvaluationBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(XljkEvaluationBo bo) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.like(StringUtils.isNotBlank(bo.getEvaluationName()), XljkEvaluation::getEvaluationName, bo.getEvaluationName()); + lqw.eq(bo.getMajorId() != null, XljkEvaluation::getMajorId, bo.getMajorId()); + lqw.eq(bo.getClassId() != null, XljkEvaluation::getClassId, bo.getClassId()); + lqw.eq(StringUtils.isNotBlank(bo.getSemester()), XljkEvaluation::getSemester, bo.getSemester()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), XljkEvaluation::getStatus, bo.getStatus()); + lqw.in(CollUtil.isNotEmpty(bo.getStatusIn()), XljkEvaluation::getStatus, bo.getStatusIn()); + lqw.in(CollUtil.isNotEmpty(bo.getMajorIdIn()), XljkEvaluation::getMajorId, bo.getMajorIdIn()); + lqw.in(CollUtil.isNotEmpty(bo.getClassIdIn()), XljkEvaluation::getClassId, bo.getClassIdIn()); + lqw.in(CollUtil.isNotEmpty(bo.getSemesterIn()), XljkEvaluation::getSemester, bo.getSemesterIn()); + lqw.in(CollUtil.isNotEmpty(bo.getCreateByIn()), XljkEvaluation::getCreateBy, bo.getCreateByIn()); + + // 数据权限过滤 + addDataPermissionFilter(lqw); + + return lqw; + } + + /** + * 添加数据权限过滤 + * + * @param lqw 查询条件 + */ + private void addDataPermissionFilter(LambdaQueryWrapper lqw) { + try { + // 获取当前登录用户信息 + var loginUser = LoginHelper.getLoginUser(); + if (loginUser == null) { + return; + } + + Long userId = loginUser.getUserId(); + + // 超级管理员不过滤数据 + if (LoginHelper.isSuperAdmin()) { + return; + } + + // 班主任只能看到自己创建的测评 + lqw.eq(XljkEvaluation::getCreateBy, userId); + + } catch (Exception e) { + log.error("数据权限过滤异常", e); + } + } + + /** + * 填充创建者信息 + */ + private void fillCreatorInfo(XljkEvaluation evaluation) { + try { + // 获取当前登录用户信息 + var loginUser = LoginHelper.getLoginUser(); + if (loginUser != null) { + evaluation.setCreateName(loginUser.getUsername()); + // 设置所属部门 + Long deptId = loginUser.getDeptId(); + if (deptId != null) { + evaluation.setCreateDept(deptId); + } else { + // 如果没有部门信息,使用默认值 + evaluation.setCreateDept(100L); // 使用杭州第一技师学院作为默认值 + } + } else { + // 如果无法获取用户信息,提供默认值 + evaluation.setCreateDept(100L); // 使用杭州第一技师学院作为默认值 + } + } catch (Exception e) { + log.error("获取用户信息异常", e); + // 确保在异常情况下也设置默认值 + evaluation.setCreateDept(100L); // 使用杭州第一技师学院作为默认值 + } + } + + /** + * 新增心理健康测评 + * + * @param bo 心理健康测评 + * @return 是否新增成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean insertByBo(XljkEvaluationBo bo) { + XljkEvaluation add = MapstructUtils.convert(bo, XljkEvaluation.class); + + // 设置初始状态为草稿 + if (StringUtils.isEmpty(add.getStatus())) { + add.setStatus("0"); + } + + // 确保department_id字段有值,如果前端传入0则使用对应院系的ID + if (add.getDepartmentId() == null || add.getDepartmentId() == 0) { + // 查找是否有对应院系的部门ID + String collegeName = add.getDepartmentName(); + if (StringUtils.isNotEmpty(collegeName)) { + // 尝试从部门表中查找对应的ID + Long deptId = getDeptIdByName(collegeName); + if (deptId != null) { + add.setDepartmentId(deptId); + } else { + // 如果找不到,使用默认值 + add.setDepartmentId(103L); // 默认使用智能控制学院的ID + } + } else { + // 如果院系名称为空,使用默认值 + add.setDepartmentId(103L); // 默认使用智能控制学院的ID + add.setDepartmentName("智能控制学院"); // 确保department_name有值 + } + } + + // 确保departmentName字段有值 + if (StringUtils.isEmpty(add.getDepartmentName())) { + // 如果departmentName为空但departmentId有值,尝试查询对应的名称 + if (add.getDepartmentId() != null && add.getDepartmentId() > 0) { + String deptName = getDeptNameById(add.getDepartmentId()); + if (StringUtils.isNotEmpty(deptName)) { + add.setDepartmentName(deptName); + } else { + add.setDepartmentName("智能控制学院"); // 默认值 + } + } else { + add.setDepartmentName("智能控制学院"); // 默认值 + } + } + + // 设置创建者姓名 + fillCreatorInfo(add); + + // 验证是否重复 + validEntityBeforeSave(add); + + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 根据院系名称查找对应的部门ID + * @param collegeName 院系名称 + * @return 部门ID,如果找不到则返回null + */ + private Long getDeptIdByName(String collegeName) { + try (Connection conn = dataSource.getConnection()) { + String sql = "SELECT dept_id FROM sys_dept WHERE dept_name = ? AND status = '0' LIMIT 1"; + try (PreparedStatement stmt = conn.prepareStatement(sql)) { + stmt.setString(1, collegeName); + try (ResultSet rs = stmt.executeQuery()) { + if (rs.next()) { + return rs.getLong("dept_id"); + } + } + } + } catch (Exception e) { + log.error("查询部门ID异常", e); + } + return null; + } + + /** + * 根据部门ID查找对应的部门名称 + * @param deptId 部门ID + * @return 部门名称,如果找不到则返回null + */ + private String getDeptNameById(Long deptId) { + try (Connection conn = dataSource.getConnection()) { + String sql = "SELECT dept_name FROM sys_dept WHERE dept_id = ? AND status = '0' LIMIT 1"; + try (PreparedStatement stmt = conn.prepareStatement(sql)) { + stmt.setLong(1, deptId); + try (ResultSet rs = stmt.executeQuery()) { + if (rs.next()) { + return rs.getString("dept_name"); + } + } + } + } catch (Exception e) { + log.error("查询部门名称异常", e); + } + return null; + } + + /** + * 修改心理健康测评 + * + * @param bo 心理健康测评 + * @return 是否修改成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean updateByBo(XljkEvaluationBo bo) { + XljkEvaluation update = MapstructUtils.convert(bo, XljkEvaluation.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + * + * @param entity 实体类数据 + */ + private void validEntityBeforeSave(XljkEvaluation entity) { + // 校验是否存在相同的测评 + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(XljkEvaluation::getClassId, entity.getClassId()) + .eq(XljkEvaluation::getSemester, entity.getSemester()) + .eq(XljkEvaluation::getEvaluationName, entity.getEvaluationName()); + + // 排除自身 + if (entity.getId() != null) { + lqw.ne(XljkEvaluation::getId, entity.getId()); + } + + long count = baseMapper.selectCount(lqw); + if (count > 0) { + throw new ServiceException("已存在相同班级、学期的测评"); + } + } + + /** + * 校验并批量删除心理健康测评信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if (isValid) { + // 校验是否允许删除 + for (Long id : ids) { + XljkEvaluation evaluation = baseMapper.selectById(id); + if (evaluation != null && !"0".equals(evaluation.getStatus())) { + throw new ServiceException("只能删除草稿状态的测评"); + } + } + } + + // 删除测评明细 + for (Long id : ids) { + detailService.deleteByEvaluationId(id); + } + + return baseMapper.deleteBatchIds(ids) > 0; + } + + /** + * 获取院系选项 + * + * @return 院系选项数据 + */ + @Override + public List> getDepartmentOptions() { + // 重定向到新方法 + return getCollegeOptions(); + } + + /** + * 获取院系选项 + * + * @return 院系选项数据 + */ + @Override + public List> getCollegeOptions() { + // 从学生信息表中查询唯一院系列表 + String sql = "SELECT DISTINCT college_name as name FROM xg_student_info WHERE college_name IS NOT NULL"; + + List> result = new ArrayList<>(); + try { + // 使用原生SQL查询 + List list = baseMapper.selectList(new LambdaQueryWrapper().last("LIMIT 1")); + + // 执行SQL查询院系数据 + Connection conn = dataSource.getConnection(); + try (PreparedStatement stmt = conn.prepareStatement(sql); + ResultSet rs = stmt.executeQuery()) { + + while (rs.next()) { + Map option = new HashMap<>(); + option.put("name", rs.getString("name")); + result.add(option); + } + } + conn.close(); + } catch (Exception e) { + log.error("获取院系选项异常", e); + } + + return result; + } + + /** + * 获取专业选项 + * + * @param collegeName 院系名称,可为空 + * @return 专业选项数据 + */ + @Override + public List> getMajorOptions(String collegeName) { + StringBuilder sql = new StringBuilder("SELECT DISTINCT major_name as name FROM xg_student_info WHERE major_name IS NOT NULL"); + List params = new ArrayList<>(); + + if (StringUtils.isNotEmpty(collegeName)) { + sql.append(" AND college_name = ?"); + params.add(collegeName); + } + + List> result = new ArrayList<>(); + try { + // 执行SQL查询专业数据 + Connection conn = dataSource.getConnection(); + try (PreparedStatement stmt = conn.prepareStatement(sql.toString())) { + + // 设置参数 + for (int i = 0; i < params.size(); i++) { + stmt.setObject(i + 1, params.get(i)); + } + + try (ResultSet rs = stmt.executeQuery()) { + while (rs.next()) { + Map option = new HashMap<>(); + option.put("name", rs.getString("name")); + result.add(option); + } + } + } + conn.close(); + } catch (Exception e) { + log.error("获取专业选项异常", e); + } + + return result; + } + + /** + * 获取班级选项 + * + * @param collegeName 院系名称,可为空 + * @param majorName 专业名称,可为空 + * @return 班级选项数据 + */ + @Override + public List> getClassOptions(String collegeName, String majorName) { + StringBuilder sql = new StringBuilder("SELECT DISTINCT class_name as name FROM xg_student_info WHERE class_name IS NOT NULL"); + List params = new ArrayList<>(); + + if (StringUtils.isNotEmpty(collegeName)) { + sql.append(" AND college_name = ?"); + params.add(collegeName); + } + + if (StringUtils.isNotEmpty(majorName)) { + sql.append(" AND major_name = ?"); + params.add(majorName); + } + + List> result = new ArrayList<>(); + try { + // 执行SQL查询班级数据 + Connection conn = dataSource.getConnection(); + try (PreparedStatement stmt = conn.prepareStatement(sql.toString())) { + + // 设置参数 + for (int i = 0; i < params.size(); i++) { + stmt.setObject(i + 1, params.get(i)); + } + + try (ResultSet rs = stmt.executeQuery()) { + while (rs.next()) { + Map option = new HashMap<>(); + option.put("name", rs.getString("name")); + result.add(option); + } + } + } + conn.close(); + } catch (Exception e) { + log.error("获取班级选项异常", e); + } + + return result; + } + + /** + * 获取学生列表 + * + * @param collegeName 院系名称,可为空 + * @param majorName 专业名称,可为空 + * @param className 班级名称,可为空 + * @return 学生列表数据 + */ + @Override + public List> getStudentsByClass(String collegeName, String majorName, String className) { + StringBuilder sql = new StringBuilder("SELECT id as studentId, student_no as studentNo, name as studentName, gender, birth_date as birthDate, phone " + + "FROM xg_student_info WHERE 1=1"); + List params = new ArrayList<>(); + + // 主要匹配班级名称,因为不同的表可能使用不同的院系名称 + if (StringUtils.isNotEmpty(className)) { + sql.append(" AND class_name = ?"); + params.add(className); + } else { + // 如果没有班级名称,才使用院系和专业筛选 + if (StringUtils.isNotEmpty(collegeName)) { + sql.append(" AND (college_name = ? OR college_name LIKE ?)"); + params.add(collegeName); + params.add("%" + collegeName + "%"); + } + + if (StringUtils.isNotEmpty(majorName)) { + sql.append(" AND major_name = ?"); + params.add(majorName); + } + } + + log.info("获取学生列表SQL: {}, 参数: {}", sql.toString(), params); + + List> result = new ArrayList<>(); + try { + // 执行SQL查询学生数据 + Connection conn = dataSource.getConnection(); + try (PreparedStatement stmt = conn.prepareStatement(sql.toString())) { + + // 设置参数 + for (int i = 0; i < params.size(); i++) { + stmt.setObject(i + 1, params.get(i)); + } + + try (ResultSet rs = stmt.executeQuery()) { + while (rs.next()) { + Map student = new HashMap<>(); + student.put("studentId", rs.getLong("studentId")); + student.put("studentNo", rs.getString("studentNo")); + student.put("studentName", rs.getString("studentName")); + student.put("gender", rs.getString("gender")); + student.put("birthDate", rs.getDate("birthDate")); + student.put("phone", rs.getString("phone")); + result.add(student); + } + } + } + conn.close(); + } catch (Exception e) { + log.error("获取学生列表异常", e); + } + + log.info("获取学生列表结果数量: {}", result.size()); + return result; + } + + /** + * 获取专业和班级选项 + * + * @param departmentId 院系ID,可为空 + * @return 专业和班级选项数据 + */ + @Override + public Map>> getMajorAndClassOptions(Long departmentId) { + // 模拟数据,实际项目中应该从学生信息管理模块获取 + Map>> result = new HashMap<>(); + + // 专业选项 + List> majors = new ArrayList<>(); + + // 按院系过滤专业 + if (departmentId != null) { + if (departmentId.equals(103L)) { // 智能控制学院 + Map major1 = new HashMap<>(); + major1.put("id", 101); + major1.put("name", "计算机应用技术"); + major1.put("departmentId", 103); + majors.add(major1); + + Map major2 = new HashMap<>(); + major2.put("id", 104); + major2.put("name", "自动化技术"); + major2.put("departmentId", 103); + majors.add(major2); + } else if (departmentId.equals(104L)) { // 智能制造学院 + Map major2 = new HashMap<>(); + major2.put("id", 102); + major2.put("name", "电子商务"); + major2.put("departmentId", 104); + majors.add(major2); + + Map major3 = new HashMap<>(); + major3.put("id", 105); + major3.put("name", "机械设计"); + major3.put("departmentId", 104); + majors.add(major3); + } else if (departmentId.equals(105L)) { // 医药健康学院 + Map major3 = new HashMap<>(); + major3.put("id", 103); + major3.put("name", "会计"); + major3.put("departmentId", 105); + majors.add(major3); + + Map major4 = new HashMap<>(); + major4.put("id", 106); + major4.put("name", "护理"); + major4.put("departmentId", 105); + majors.add(major4); + } + } else { + // 如果没有选择院系,返回所有专业 + Map major1 = new HashMap<>(); + major1.put("id", 101); + major1.put("name", "计算机应用技术"); + major1.put("departmentId", 103); + majors.add(major1); + + Map major2 = new HashMap<>(); + major2.put("id", 102); + major2.put("name", "电子商务"); + major2.put("departmentId", 104); + majors.add(major2); + + Map major3 = new HashMap<>(); + major3.put("id", 103); + major3.put("name", "会计"); + major3.put("departmentId", 105); + majors.add(major3); + } + + // 班级选项 + List> classes = new ArrayList<>(); + + for (Map major : majors) { + Long majorId = Long.valueOf(major.get("id").toString()); + if (majorId.equals(101L)) { + Map class1 = new HashMap<>(); + class1.put("id", 1001); + class1.put("name", "计算机2301班"); + class1.put("majorId", 101); + classes.add(class1); + + Map class2 = new HashMap<>(); + class2.put("id", 1004); + class2.put("name", "计算机2302班"); + class2.put("majorId", 101); + classes.add(class2); + } else if (majorId.equals(102L)) { + Map class2 = new HashMap<>(); + class2.put("id", 1002); + class2.put("name", "电子2301班"); + class2.put("majorId", 102); + classes.add(class2); + + Map class3 = new HashMap<>(); + class3.put("id", 1005); + class3.put("name", "电子2302班"); + class3.put("majorId", 102); + classes.add(class3); + } else if (majorId.equals(103L)) { + Map class3 = new HashMap<>(); + class3.put("id", 1003); + class3.put("name", "会计2301班"); + class3.put("majorId", 103); + classes.add(class3); + + Map class4 = new HashMap<>(); + class4.put("id", 1006); + class4.put("name", "会计2302班"); + class4.put("majorId", 103); + classes.add(class4); + } + } + + result.put("majors", majors); + result.put("classes", classes); + + return result; + } + + /** + * 获取学期选项 + * + * @return 学期选项列表 + */ + @Override + public List getSemesterOptions() { + List options = new ArrayList<>(); + options.add("2023上学期"); + options.add("2023下学期"); + options.add("2024上学期"); + options.add("2024下学期"); + options.add("2025上学期"); + options.add("2025下学期"); + return options; + } + + /** + * 发布测评 + * + * @param id 测评ID + * @return 是否成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean publishEvaluation(Long id) { + XljkEvaluation evaluation = baseMapper.selectById(id); + if (evaluation == null) { + throw new ServiceException("测评不存在"); + } + + if (!"0".equals(evaluation.getStatus())) { + throw new ServiceException("只能发布草稿状态的测评"); + } + + // 检查是否有学生数据 + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(XljkEvaluationDetail::getEvaluationId, id); + long count = detailMapper.selectCount(lqw); + if (count == 0) { + throw new ServiceException("测评没有学生数据,无法发布"); + } + + // 更新状态为已发布 + evaluation.setStatus("1"); + return baseMapper.updateById(evaluation) > 0; + } + + /** + * 完成测评 + * + * @param id 测评ID + * @return 是否成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean completeEvaluation(Long id) { + XljkEvaluation evaluation = baseMapper.selectById(id); + if (evaluation == null) { + throw new ServiceException("测评不存在"); + } + + if (!"1".equals(evaluation.getStatus())) { + throw new ServiceException("只能完成已发布状态的测评"); + } + + // 检查是否所有学生都已评估 + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(XljkEvaluationDetail::getEvaluationId, id) + .isNull(XljkEvaluationDetail::getMentalStatus); + long count = detailMapper.selectCount(lqw); + if (count > 0) { + throw new ServiceException("还有" + count + "名学生未完成评估"); + } + + // 更新状态为已完成 + evaluation.setStatus("2"); + return baseMapper.updateById(evaluation) > 0; + } + + /** + * 获取测评统计数据 + * + * @param id 测评ID + * @return 统计数据 + */ + @Override + public Map getEvaluationStatistics(Long id) { + Map result = new HashMap<>(); + + // 获取测评信息 + XljkEvaluationVo evaluation = queryById(id); + if (evaluation == null) { + throw new ServiceException("测评不存在"); + } + + result.put("evaluationName", evaluation.getEvaluationName()); + result.put("className", evaluation.getClassName()); + result.put("semester", evaluation.getSemester()); + result.put("createName", evaluation.getCreateName()); + result.put("createTime", evaluation.getCreateTime()); + + // 统计各状态人数 + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(XljkEvaluationDetail::getEvaluationId, id); + List details = detailMapper.selectList(lqw); + + int totalCount = details.size(); + int healthyCount = 0; + int goodCount = 0; + int focusCount = 0; + + for (XljkEvaluationDetail detail : details) { + if ("1".equals(detail.getMentalStatus())) { + healthyCount++; + } else if ("2".equals(detail.getMentalStatus())) { + goodCount++; + } else if ("3".equals(detail.getMentalStatus())) { + focusCount++; + } + } + + result.put("totalCount", totalCount); + result.put("healthyCount", healthyCount); + result.put("goodCount", goodCount); + result.put("focusCount", focusCount); + + if (totalCount > 0) { + result.put("healthyPercent", Math.round(healthyCount * 100.0 / totalCount * 10) / 10.0); + result.put("goodPercent", Math.round(goodCount * 100.0 / totalCount * 10) / 10.0); + result.put("focusPercent", Math.round(focusCount * 100.0 / totalCount * 10) / 10.0); + } else { + result.put("healthyPercent", 0); + result.put("goodPercent", 0); + result.put("focusPercent", 0); + } + + // 性别分布 + int maleCount = 0; + int femaleCount = 0; + int maleFocusCount = 0; + int femaleFocusCount = 0; + + for (XljkEvaluationDetail detail : details) { + if ("0".equals(detail.getGender())) { + maleCount++; + if ("3".equals(detail.getMentalStatus())) { + maleFocusCount++; + } + } else if ("1".equals(detail.getGender())) { + femaleCount++; + if ("3".equals(detail.getMentalStatus())) { + femaleFocusCount++; + } + } + } + + result.put("maleCount", maleCount); + result.put("femaleCount", femaleCount); + result.put("maleFocusCount", maleFocusCount); + result.put("femaleFocusCount", femaleFocusCount); + + return result; + } + + /** + * 获取重点关注学生统计 + * + * @param bo 查询条件 + * @return 统计数据 + */ + @Override + public Map getFocusStudentsStatistics(XljkEvaluationBo bo) { + Map result = new HashMap<>(); + + // 查询所有符合条件的测评 + List evaluations = queryList(bo); + + int totalStudentCount = 0; + int totalFocusCount = 0; + + // 按班级统计 + Map classFocusMap = new HashMap<>(); + Map classStudentMap = new HashMap<>(); + + // 按学期统计 + Map semesterFocusMap = new HashMap<>(); + Map semesterStudentMap = new HashMap<>(); + + for (XljkEvaluationVo evaluation : evaluations) { + // 查询该测评的学生数和重点关注数 + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(XljkEvaluationDetail::getEvaluationId, evaluation.getId()); + int studentCount = detailMapper.selectCount(lqw).intValue(); + + lqw.clear(); + lqw.eq(XljkEvaluationDetail::getEvaluationId, evaluation.getId()) + .eq(XljkEvaluationDetail::getMentalStatus, "3"); + int focusCount = detailMapper.selectCount(lqw).intValue(); + + totalStudentCount += studentCount; + totalFocusCount += focusCount; + + // 按班级统计 + String className = evaluation.getClassName(); + classStudentMap.put(className, classStudentMap.getOrDefault(className, 0) + studentCount); + classFocusMap.put(className, classFocusMap.getOrDefault(className, 0) + focusCount); + + // 按学期统计 + String semester = evaluation.getSemester(); + semesterStudentMap.put(semester, semesterStudentMap.getOrDefault(semester, 0) + studentCount); + semesterFocusMap.put(semester, semesterFocusMap.getOrDefault(semester, 0) + focusCount); + } + + // 计算总体关注率 + double totalFocusRate = totalStudentCount > 0 ? + Math.round(totalFocusCount * 100.0 / totalStudentCount * 10) / 10.0 : 0; + + result.put("totalStudentCount", totalStudentCount); + result.put("totalFocusCount", totalFocusCount); + result.put("totalFocusRate", totalFocusRate); + + // 班级统计数据 + List> classStats = new ArrayList<>(); + for (String className : classStudentMap.keySet()) { + Map classStat = new HashMap<>(); + int studentCount = classStudentMap.get(className); + int focusCount = classFocusMap.getOrDefault(className, 0); + double focusRate = studentCount > 0 ? + Math.round(focusCount * 100.0 / studentCount * 10) / 10.0 : 0; + + classStat.put("className", className); + classStat.put("studentCount", studentCount); + classStat.put("focusCount", focusCount); + classStat.put("focusRate", focusRate); + + classStats.add(classStat); + } + result.put("classStats", classStats); + + // 学期统计数据 + List> semesterStats = new ArrayList<>(); + for (String semester : semesterStudentMap.keySet()) { + Map semesterStat = new HashMap<>(); + int studentCount = semesterStudentMap.get(semester); + int focusCount = semesterFocusMap.getOrDefault(semester, 0); + double focusRate = studentCount > 0 ? + Math.round(focusCount * 100.0 / studentCount * 10) / 10.0 : 0; + + semesterStat.put("semester", semester); + semesterStat.put("studentCount", studentCount); + semesterStat.put("focusCount", focusCount); + semesterStat.put("focusRate", focusRate); + + semesterStats.add(semesterStat); + } + result.put("semesterStats", semesterStats); + + return result; + } +} \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-xljk/src/main/resources/mapper/XljkEvaluationDetailMapper.xml b/backend/ruoyi-modules/ruoyi-xljk/src/main/resources/mapper/XljkEvaluationDetailMapper.xml new file mode 100644 index 00000000..fd152e0c --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-xljk/src/main/resources/mapper/XljkEvaluationDetailMapper.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-xljk/src/main/resources/mapper/XljkEvaluationMapper.xml b/backend/ruoyi-modules/ruoyi-xljk/src/main/resources/mapper/XljkEvaluationMapper.xml new file mode 100644 index 00000000..4751a511 --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-xljk/src/main/resources/mapper/XljkEvaluationMapper.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/原型文件/学工/心理咨询/01-心理健康测评管理.html b/docs/原型文件/学工/心理咨询/01-心理健康测评管理.html new file mode 100644 index 00000000..9b9a0631 --- /dev/null +++ b/docs/原型文件/学工/心理咨询/01-心理健康测评管理.html @@ -0,0 +1,1144 @@ + + + + + + 心理健康测评管理 - 杭州第一技师学院 + + + + + + + + +
+ + + +
+
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ + +
+
+
+
+
+
+
+ + +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + + + + + +
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + 测评名称专业班级学期学生人数创建时间状态操作
+ + 2024年秋季心理健康测评计算机应用技术计算机2301班2024-2025学年第一学期352024-09-15 09:00:00已完成 +
+ +
+
+ +
+
+ +
+
+ + 2024年春季心理健康测评机械制造与自动化机械2301班2023-2024学年第二学期282024-03-10 14:30:00已发布 +
+ +
+
+ +
+
+ +
+
+ + 电气专业心理健康评估电气自动化技术电气2302班2024-2025学年第一学期302024-10-01 10:00:00草稿 +
+ +
+
+ +
+
+ +
+
+
+ +
+
+ + 第 1 页,共 3 页 + +
+
+
+
+ + +
+
+
+

创建心理健康测评

+ × +
+
+
+ 提示:创建测评后,系统将自动加载所选专业和班级的学生信息,包括学号、姓名、性别、出生日期、联系电话等。 +
+ +
+
+ +
+ +
+
+ +
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+
+
+ +
+
+ + +
+
+
+

查看测评详情

+ × +
+
+
+
+

测评基本信息

+
+
+
+
+ +

2024年秋季心理健康测评

+
+
+ +

计算机应用技术 - 计算机2301班

+
+
+
+
+ +

2024-2025学年第一学期

+
+
+ +

2024-09-15 09:00:00

+
+
+
+
+ +
+
+

学生测评结果

+
+
+
+
+
+
张三
+
学号:2023001 | 男 | 2005-03-15 | 13812345678
+
+
+ 健康 +
+
+
+
+
李四
+
学号:2023002 | 女 | 2005-07-22 | 13987654321
+
+
+ 良好 +
+
+
+
+
王五
+
学号:2023003 | 男 | 2005-11-08 | 13765432109
+
+
+ 重点关注 + 评分:65 +
+
+
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/原型文件/学工/心理咨询/02-心理咨询预约管理.html b/docs/原型文件/学工/心理咨询/02-心理咨询预约管理.html new file mode 100644 index 00000000..0e3f6d74 --- /dev/null +++ b/docs/原型文件/学工/心理咨询/02-心理咨询预约管理.html @@ -0,0 +1,946 @@ + + + + + + 心理咨询预约管理 - 杭州第一技师学院 + + + + + + + + +
+ + + +
+
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ + +
+
+
+
+
+
+
+ + +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + + + + + +
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + 学生姓名学号手机号专业班级咨询师预约日期预约时段预约状态到访情况申请时间操作
+ + 张三202400113800138001计算机应用技术2024-1班张心理老师2025-01-10上午 09:00-11:00待处理-2025-01-08 14:30 +
+ +
+
+ +
+
+ +
+
+ + 李四202400213800138002电子商务2024-2班李心理老师2025-01-11下午 14:00-17:00已确认-2025-01-07 16:20 +
+ +
+
+ +
+
+ + 王五202400313800138003机械制造与自动化2024-3班王心理老师2025-01-08上午 09:00-11:00已完成已到访2025-01-06 10:15 +
+ +
+
+ +
+
+ + 赵六202400413800138004汽车检测与维修2024-1班张心理老师2025-01-07下午 14:00-17:00已完成未到访2025-01-05 09:30 +
+ +
+
+ +
+
+
+ +
+
+ + 第 1 页,共 5 页 + +
+
+
+
+ + +
+
+
+

处理预约申请

+ × +
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+ +
+ +
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/原型文件/学工/心理咨询/03-预约时段配置管理.html b/docs/原型文件/学工/心理咨询/03-预约时段配置管理.html new file mode 100644 index 00000000..58e6f5d7 --- /dev/null +++ b/docs/原型文件/学工/心理咨询/03-预约时段配置管理.html @@ -0,0 +1,1416 @@ + + + + + + 预约时段配置管理 - 杭州第一技师学院 + + + + + + + + +
+ + + +
+
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ + +
+
+
+
+
+
+
+ + +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + + + + + +
+
+
+ + +
+
+

2025年1月

+
+ + + +
+
+ +
+
日
+
一
+
二
+
三
+
四
+
五
+
六
+ + +
+
29
+
+
+
30
+
+
+
31
+
+
+
1
+
+
上午 09:00-11:00
+
下午 14:00-17:00
+
+
+
+
2
+
+
上午 09:00-11:00
+
下午已满
+
+
+
+
3
+
+
下午 14:00-17:00
+
+
+
+
4
+
+ + +
+
5
+
+
+
6
+
+
上午 09:00-11:00
+
下午 14:00-17:00
+
+
+
+
7
+
+
上午 09:00-11:00
+
+
+
+
8
+
+
上午 09:00-11:00
+
下午 14:00-17:00
+
+
+
+
9
+
+
下午 14:00-17:00
+
+
+
+
10
+
+
上午 09:00-11:00
+
下午 14:00-17:00
+
+
+
+
11
+
+ + +
+
12
+
+
+
13
+
+
上午 09:00-11:00
+
+
+
+
14
+
+
下午 14:00-17:00
+
+
+
+
15
+
+
上午 09:00-11:00
+
下午 14:00-17:00
+
+
+
+
16
+
+
+
17
+
+
+
18
+
+
+
+ + + + + +
+
+ + 第 1 页,共 2 页 + +
+
+
+
+ + +
+
+
+

新增预约时段

+ × +
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+ + +
+
+ +
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+ +
+
+ + +
+

时段预览

+
+ 上午 09:00-11:00 + 可预约 +
+
+ 下午 14:00-17:00 + 可预约 +
+
+
+ +
+
+ + +
+
+
+

2025-01-08 时段详情

+ × +
+
+
+

时段配置

+
+ 上午 09:00-11:00 + 预约数: 2/10 + 可预约 +
+
+ 下午 14:00-17:00 + 预约数: 1/10 + 可预约 +
+
+ +
+

当日预约列表

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
学生姓名学号预约时段状态
张三2024001上午 09:00-11:00已确认
李四2024002上午 09:00-11:00已确认
王五2024003下午 14:00-17:00已确认
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/docs/原型文件/学工/心理咨询/README.md b/docs/原型文件/学工/心理咨询/README.md new file mode 100644 index 00000000..0519ecba --- /dev/null +++ b/docs/原型文件/学工/心理咨询/README.md @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/变更管理/code-adjust-record-2025-07-02-lixuming.md b/docs/变更管理/code-adjust-record-2025-07-02-lixuming.md new file mode 100644 index 00000000..ea32f10a --- /dev/null +++ b/docs/变更管理/code-adjust-record-2025-07-02-lixuming.md @@ -0,0 +1,227 @@ +# 心理健康测评模块数据库表字段调整记录 + +**日期**:2025-07-02 +**操作人**:lixuming + +## 变更内容 + +### 1. 问题描述 + +在访问心理健康测评模块时,系统报错: +``` +Error querying database. Cause: java.sql.SQLSyntaxErrorException: Unknown column 'create_dept' in 'field list' +``` + +经分析,问题是数据库表字段与实体类定义不一致。实体类通过继承 `BaseEntity` 包含 `createDept` 字段,但数据库表中不存在对应的 `create_dept` 列。 + +### 2. 解决方案 + +在数据库表中添加缺失的 `create_dept` 字段,并设置初始值。 + +### 3. 执行的SQL语句 + +```sql +-- 向xljk_evaluation表添加create_dept字段 +ALTER TABLE xljk_evaluation ADD COLUMN create_dept bigint NOT NULL COMMENT '创建部门' AFTER tenant_id; + +-- 向xljk_evaluation_detail表添加create_dept字段 +ALTER TABLE xljk_evaluation_detail ADD COLUMN create_dept bigint NOT NULL COMMENT '创建部门' AFTER tenant_id; + +-- 设置初始值:使用create_by字段的值作为create_dept的值 +UPDATE xljk_evaluation SET create_dept = create_by; +UPDATE xljk_evaluation_detail SET create_dept = create_by; +``` + +### 4. 变更结果 + +两个表都成功添加了 `create_dept` 字段,并设置了初始值。 + +### 5. 影响范围 + +此变更使数据库表结构与实体类定义一致,解决了因字段缺失导致的SQL查询错误,使心理健康测评模块可以正常访问和使用。 + +## 相关文档 + +- 实体类: `org.dromara.xljk.domain.XljkEvaluation` 继承自 `TenantEntity`,后者继承自 `BaseEntity` +- `BaseEntity` 类包含 `createDept` 字段,对应数据库中的 `create_dept` 列 + +--- + +# 心理健康测评模块添加院系字段 + +**日期**:2025-07-02 +**操作人**:lixuming + +## 变更内容 + +### 1. 需求描述 + +在心理健康测评新增界面中,需要在专业字段上方增加一个院系字段,实现院系-专业的两级联动。 + +### 2. 解决方案 + +在数据库表中添加院系ID和院系名称字段,并为已有数据设置默认值。 + +### 3. 执行的SQL语句 + +```sql +-- 在心理健康测评表中添加院系ID和院系名称字段 +ALTER TABLE xljk_evaluation +ADD COLUMN department_id bigint NOT NULL COMMENT '院系ID' AFTER id, +ADD COLUMN department_name varchar(100) NOT NULL COMMENT '院系名称' AFTER department_id; + +-- 更新已有数据,设置默认值 +UPDATE xljk_evaluation SET department_id = 103, department_name = '智能控制学院' WHERE 1=1; + +-- 为院系ID字段添加索引以提高查询效率 +ALTER TABLE xljk_evaluation ADD INDEX idx_department_id (department_id); +``` + +### 4. 变更结果 + +成功添加了院系字段,并为已有数据设置了默认值。 + +### 5. 后续工作 + +需要更新以下组件以支持院系字段: + +1. 前端类型定义和API接口 +2. 新增和编辑表单界面 +3. 列表和详情页面 +4. 后端实体类、VO类和Mapper文件 + +## 相关文档 + +- SQL脚本: `docs/设计文档/database/心理健康测评/xljk_add_department_fields.sql` +- 参考院系数据: 来自系统 `sys_dept` 表,其中二级学院ID为101 + +--- + +# 心理健康测评功能增强:院系-专业联动实现 + +**日期**:2025-07-02 +**操作人**:lixuming + +## 变更内容 + +### 1. 需求实现 + +完成了心理健康测评模块的院系-专业两级联动功能,使得用户可以先选择院系,再选择该院系下的专业和班级。主要变更内容如下: + +### 2. 后端实现 + +1. 在实体类和VO类中添加院系ID和院系名称字段 +2. 添加获取院系列表的API接口 +3. 修改获取专业班级API接口,支持按院系过滤 +4. 在XML映射文件中添加院系字段映射 + +### 3. 前端实现 + +1. 添加院系相关的类型定义 + - 添加`DepartmentOption`接口 + - 在`XljkEvaluationVO`和`XljkEvaluationForm`中添加院系字段 + +2. 添加院系相关的API接口 + - 添加`getDepartmentOptions`函数获取院系列表 + - 更新`getMajorClassOptions`函数支持院系过滤 + +3. 界面实现 + - 在新增和编辑页面的专业字段上方添加院系选择 + - 在列表页面查询条件和表格中添加院系字段 + - 实现院系选择后联动刷新专业选项 + +### 4. 数据关联和联动 + +- 院系选择变化时,清空专业和班级选项,并重新加载该院系下的专业 +- 专业选择变化时,清空班级选项,并加载该专业下的班级 +- 列表查询时可按院系、专业、班级多级筛选 + +## 文件变更 + +1. **后端文件**: + - `XljkEvaluation.java` - 添加院系字段 + - `XljkEvaluationVo.java` - 添加院系字段 + - `XljkEvaluationMapper.xml` - 添加字段映射 + - `XljkEvaluationController.java` - 添加院系API + - `IXljkEvaluationService.java` - 添加院系服务接口 + - `XljkEvaluationServiceImpl.java` - 实现院系数据获取 + +2. **前端文件**: + - `types.ts` - 添加院系相关类型 + - `index.ts` - 添加院系API接口 + - `add.vue` - 添加院系选择和联动 + - `edit.vue` - 添加院系字段 + - `index.vue` - 添加院系查询和显示 + +## 效果总结 + +通过添加院系字段和实现联动,使心理健康测评的数据组织更符合学校管理结构,提高了数据管理的层次性和使用体验。用户可以按院系-专业-班级的自然组织结构进行操作,提升了系统易用性。 + +--- + +# 心理健康测评模块与学生信息管理关联适配 + +**日期**:2025-07-02 +**操作人**:lixuming + +## 变更内容 + +### 1. 需求背景 + +由于学生信息管理模块尚未完全开发完成,需要关联现有的xg_student_info表数据用于心理健康测评的业务验证。主要调整内容包括: +- 将院系字段关联至xg_student_info.college_name +- 将专业字段关联至xg_student_info.major_name +- 将班级字段关联至xg_student_info.class_name +- 学期字段由下拉选择改为手动填写 + +### 2. 后端实现 + +1. 添加获取学生信息数据的API接口: + - GET /xljk/evaluation/options/colleges - 获取院系列表 + - GET /xljk/evaluation/options/majors - 获取专业列表 + - GET /xljk/evaluation/options/classes - 获取班级列表 + - GET /xljk/evaluation/students - 获取学生列表 + +2. 实现数据查询方法: + - 通过SQL直接查询xg_student_info表,获取所需数据 + - 实现层级过滤:根据院系过滤专业,根据院系和专业过滤班级,根据院系、专业、班级获取学生信息 + +### 3. 前端实现 + +1. 类型定义调整: + - 替换原有的院系、专业、班级相关类型定义 + - 新增CollegeOption、MajorOption、ClassOption类型 + - 调整StudentInfo类型适配学生信息表结构 + +2. 前端API调整: + - 替换原有API接口调用 + - 实现新的数据获取和联动机制 + +3. 界面交互调整: + - 使用院系、专业、班级的名称进行数据交互 + - 学期字段改为手动输入方式 + - 修改学生性别显示规则,适配M/F字段 + +### 4. 核心调整点 + +1. **数据源切换**:从系统自建模拟数据切换到直接查询xg_student_info表 +2. **字段匹配**:根据xg_student_info表结构对接对应字段 +3. **查询策略**:使用动态SQL实现多级联动查询 +4. **ID处理**:兼容保留原有ID字段,但实际使用名称字段进行数据关联 +5. **前端适配**:调整前端代码使其适配新的数据结构和交互方式 + +## 文件变更 + +1. **后端文件**: + - XljkEvaluationController.java - 添加新API接口 + - IXljkEvaluationService.java - 添加新服务方法 + - XljkEvaluationServiceImpl.java - 实现学生信息查询逻辑 + +2. **前端文件**: + - types.ts - 更新数据类型定义 + - index.ts - 更新API调用接口 + - add.vue - 更新表单处理逻辑 + +## 效果总结 + +通过此次调整,实现了心理健康测评功能与现有学生信息表的对接,使得测试过程中可以使用真实学生数据进行业务验证。此方案作为临时适配方案,待学生信息管理模块完全开发完成后,可考虑采用更规范的数据服务调用方式进行优化。 \ No newline at end of file diff --git a/docs/变更管理/code-adjust-record-2025-07-03-lixuming.md b/docs/变更管理/code-adjust-record-2025-07-03-lixuming.md new file mode 100644 index 00000000..9c0b886a --- /dev/null +++ b/docs/变更管理/code-adjust-record-2025-07-03-lixuming.md @@ -0,0 +1,41 @@ +# 代码调整记录 - 2025-07-03 - lixuming + +## 变更时间:2025-07-03 14:30:00 + +## 变更内容 + +### 数据库连接配置修改 + +1. 修改了应用配置文件中的数据库连接,从阿里云数据库改为本地数据库 +2. 修改文件:`backend/ruoyi-admin/src/main/resources/application-dev.yml` +3. 具体修改: + ```yaml + # 修改前 + url: jdbc:mysql://47.99.164.66:3306/hzdyjs_xg?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true + username: root + password: hn02le.34lkdLKD + + # 修改后 + url: jdbc:mysql://localhost:3306/hzdyjs_xg?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true + username: root + password: 'DP@xp117' + ``` + +## 变更原因 + +1. 将应用数据库连接从阿里云改为本地开发环境,方便本地开发和调试 +2. Redis连接保持不变,继续使用阿里云Redis服务 + +## 变更影响 + +1. 应用将从本地数据库读取数据,确保本地数据库中存在相应的表结构和数据 +2. 多租户配置需要注意,确保表 `xljk_evaluation` 包含在排除表列表中或数据有正确的租户ID + +## 相关文件 + +- `backend/ruoyi-admin/src/main/resources/application-dev.yml` + +## 备注 + +使用本地数据库后,需确保本地数据库中的表结构和初始数据与原阿里云数据库一致。 +特别注意多租户配置,心理健康测评表中的租户ID需设置为 `000000`。 \ No newline at end of file diff --git a/docs/开发文档/API/心理健康测评API.md b/docs/开发文档/API/心理健康测评API.md new file mode 100644 index 00000000..26335476 --- /dev/null +++ b/docs/开发文档/API/心理健康测评API.md @@ -0,0 +1,803 @@ +# 心理健康测评API文档 + +## 1. API概述 + +心理健康测评模块提供班主任对班级学生进行心理健康状况评估的功能,包括测评创建、学生数据加载、心理状态评估、测评统计等功能。 + +### 1.1 基本信息 + +- **模块名称**:心理健康测评模块 +- **模块代码**:ruoyi-xljk +- **API前缀**:/xljk +- **数据表**:xljk_evaluation, xljk_evaluation_detail +- **开发负责人**:Cursor AI +- **创建日期**:2025-07-02 + +### 1.2 功能列表 + +| 功能 | 描述 | +| ---- | ---- | +| 测评管理 | 创建、查询、修改、删除测评 | +| 测评明细管理 | 查询、修改学生心理状态 | +| 测评流程 | 发布测评、完成测评 | +| 数据统计 | 测评统计、重点关注学生统计 | + +## 2. API列表 + +### 2.1 测评管理API + +#### 2.1.1 查询测评列表 + +- **接口URL**:/xljk/evaluation/list +- **请求方式**:GET +- **接口权限**:xljk:evaluation:list +- **请求参数**: + +| 参数名 | 类型 | 是否必须 | 描述 | +| ------ | ---- | -------- | ---- | +| pageNum | int | 否 | 当前页码,默认为1 | +| pageSize | int | 否 | 每页记录数,默认为10 | +| evaluationName | string | 否 | 测评名称,支持模糊查询 | +| majorId | long | 否 | 专业ID | +| classId | long | 否 | 班级ID | +| semester | string | 否 | 学期 | +| status | string | 否 | 状态(0-草稿,1-已发布,2-已完成) | + +- **返回示例**: + +```json +{ + "code": 200, + "msg": "操作成功", + "data": { + "total": 3, + "rows": [ + { + "id": 1, + "evaluationName": "2024上学期计算机2301班心理健康测评", + "majorId": 101, + "majorName": "计算机应用技术", + "classId": 1001, + "className": "计算机2301班", + "semester": "2024上学期", + "status": "2", + "createName": "张班主任", + "remark": "期末测评", + "createBy": 2001, + "createTime": "2025-01-10 09:00:00", + "updateBy": 2001, + "updateTime": "2025-01-10 10:30:00", + "studentCount": 5, + "focusCount": 2 + }, + { + "id": 2, + "evaluationName": "2024上学期电子2302班心理健康测评", + "majorId": 102, + "majorName": "电子商务", + "classId": 1002, + "className": "电子2302班", + "semester": "2024上学期", + "status": "0", + "createName": "李班主任", + "remark": "期末测评草稿", + "createBy": 2002, + "createTime": "2025-01-11 14:00:00", + "updateBy": 2002, + "updateTime": "2025-01-11 14:30:00", + "studentCount": 0, + "focusCount": 0 + } + ] + } +} +``` + +#### 2.1.2 获取测评详情 + +- **接口URL**:/xljk/evaluation/{id} +- **请求方式**:GET +- **接口权限**:xljk:evaluation:query +- **请求参数**: + +| 参数名 | 类型 | 是否必须 | 描述 | +| ------ | ---- | -------- | ---- | +| id | long | 是 | 测评ID | + +- **返回示例**: + +```json +{ + "code": 200, + "msg": "操作成功", + "data": { + "id": 1, + "evaluationName": "2024上学期计算机2301班心理健康测评", + "majorId": 101, + "majorName": "计算机应用技术", + "classId": 1001, + "className": "计算机2301班", + "semester": "2024上学期", + "status": "2", + "createName": "张班主任", + "remark": "期末测评", + "createBy": 2001, + "createTime": "2025-01-10 09:00:00", + "updateBy": 2001, + "updateTime": "2025-01-10 10:30:00", + "studentCount": 5, + "focusCount": 2 + } +} +``` + +#### 2.1.3 新增测评 + +- **接口URL**:/xljk/evaluation +- **请求方式**:POST +- **接口权限**:xljk:evaluation:add +- **请求参数**: + +| 参数名 | 类型 | 是否必须 | 描述 | +| ------ | ---- | -------- | ---- | +| evaluationName | string | 是 | 测评名称 | +| majorId | long | 是 | 专业ID | +| majorName | string | 是 | 专业名称 | +| classId | long | 是 | 班级ID | +| className | string | 是 | 班级名称 | +| semester | string | 是 | 学期 | +| remark | string | 否 | 备注 | + +- **请求示例**: + +```json +{ + "evaluationName": "2024下学期计算机2301班心理健康测评", + "majorId": 101, + "majorName": "计算机应用技术", + "classId": 1001, + "className": "计算机2301班", + "semester": "2024下学期", + "remark": "期末测评" +} +``` + +- **返回示例**: + +```json +{ + "code": 200, + "msg": "操作成功", + "data": 3 +} +``` + +#### 2.1.4 修改测评 + +- **接口URL**:/xljk/evaluation +- **请求方式**:PUT +- **接口权限**:xljk:evaluation:edit +- **请求参数**: + +| 参数名 | 类型 | 是否必须 | 描述 | +| ------ | ---- | -------- | ---- | +| id | long | 是 | 测评ID | +| evaluationName | string | 是 | 测评名称 | +| majorId | long | 是 | 专业ID | +| majorName | string | 是 | 专业名称 | +| classId | long | 是 | 班级ID | +| className | string | 是 | 班级名称 | +| semester | string | 是 | 学期 | +| remark | string | 否 | 备注 | + +- **请求示例**: + +```json +{ + "id": 3, + "evaluationName": "2024下学期计算机2301班心理健康测评(修改)", + "majorId": 101, + "majorName": "计算机应用技术", + "classId": 1001, + "className": "计算机2301班", + "semester": "2024下学期", + "remark": "期末测评(修改)" +} +``` + +- **返回示例**: + +```json +{ + "code": 200, + "msg": "操作成功" +} +``` + +#### 2.1.5 删除测评 + +- **接口URL**:/xljk/evaluation/{ids} +- **请求方式**:DELETE +- **接口权限**:xljk:evaluation:remove +- **请求参数**: + +| 参数名 | 类型 | 是否必须 | 描述 | +| ------ | ---- | -------- | ---- | +| ids | long[] | 是 | 测评ID数组 | + +- **返回示例**: + +```json +{ + "code": 200, + "msg": "操作成功" +} +``` + +#### 2.1.6 获取专业和班级选项 + +- **接口URL**:/xljk/evaluation/options/majorAndClass +- **请求方式**:GET +- **接口权限**:xljk:evaluation:query +- **请求参数**:无 +- **返回示例**: + +```json +{ + "code": 200, + "msg": "操作成功", + "data": { + "majors": [ + { + "id": 101, + "name": "计算机应用技术" + }, + { + "id": 102, + "name": "电子商务" + }, + { + "id": 103, + "name": "会计" + } + ], + "classes": [ + { + "id": 1001, + "name": "计算机2301班", + "majorId": 101 + }, + { + "id": 1002, + "name": "电子2302班", + "majorId": 102 + }, + { + "id": 1003, + "name": "会计2303班", + "majorId": 103 + } + ] + } +} +``` + +#### 2.1.7 获取学期选项 + +- **接口URL**:/xljk/evaluation/options/semester +- **请求方式**:GET +- **接口权限**:xljk:evaluation:query +- **请求参数**:无 +- **返回示例**: + +```json +{ + "code": 200, + "msg": "操作成功", + "data": [ + "2023上学期", + "2023下学期", + "2024上学期", + "2024下学期", + "2025上学期", + "2025下学期" + ] +} +``` + +#### 2.1.8 发布测评 + +- **接口URL**:/xljk/evaluation/{id}/publish +- **请求方式**:PUT +- **接口权限**:xljk:evaluation:publish +- **请求参数**: + +| 参数名 | 类型 | 是否必须 | 描述 | +| ------ | ---- | -------- | ---- | +| id | long | 是 | 测评ID | + +- **返回示例**: + +```json +{ + "code": 200, + "msg": "操作成功" +} +``` + +#### 2.1.9 完成测评 + +- **接口URL**:/xljk/evaluation/{id}/complete +- **请求方式**:PUT +- **接口权限**:xljk:evaluation:complete +- **请求参数**: + +| 参数名 | 类型 | 是否必须 | 描述 | +| ------ | ---- | -------- | ---- | +| id | long | 是 | 测评ID | + +- **返回示例**: + +```json +{ + "code": 200, + "msg": "操作成功" +} +``` + +#### 2.1.10 导出测评 + +- **接口URL**:/xljk/evaluation/export +- **请求方式**:POST +- **接口权限**:xljk:evaluation:export +- **请求参数**:同查询测评列表接口 +- **返回结果**:Excel文件流 + +### 2.2 测评明细API + +#### 2.2.1 查询测评明细列表 + +- **接口URL**:/xljk/evaluation/detail/list +- **请求方式**:GET +- **接口权限**:xljk:evaluation:list +- **请求参数**: + +| 参数名 | 类型 | 是否必须 | 描述 | +| ------ | ---- | -------- | ---- | +| pageNum | int | 否 | 当前页码,默认为1 | +| pageSize | int | 否 | 每页记录数,默认为10 | +| evaluationId | long | 否 | 测评ID | +| studentName | string | 否 | 学生姓名,支持模糊查询 | +| studentNo | string | 否 | 学号,支持模糊查询 | +| gender | string | 否 | 性别(0-男,1-女,2-未知) | +| mentalStatus | string | 否 | 心理状态(1-健康,2-良好,3-重点关注) | + +- **返回示例**: + +```json +{ + "code": 200, + "msg": "操作成功", + "data": { + "total": 5, + "rows": [ + { + "id": 101, + "evaluationId": 1, + "studentId": 10001, + "studentNo": "2024001", + "studentName": "张三", + "gender": "0", + "birthDate": "2005-06-15", + "phone": "13800138001", + "mentalStatus": "1", + "score": null, + "remark": null, + "createBy": 2001, + "createTime": "2025-01-10 09:10:00", + "updateBy": 2001, + "updateTime": "2025-01-10 09:10:00", + "evaluationName": "2024上学期计算机2301班心理健康测评", + "className": "计算机2301班", + "majorName": "计算机应用技术", + "semester": "2024上学期" + }, + { + "id": 103, + "evaluationId": 1, + "studentId": 10003, + "studentNo": "2024003", + "studentName": "王五", + "gender": "0", + "birthDate": "2005-09-10", + "phone": "13800138003", + "mentalStatus": "3", + "score": 75, + "remark": "近期学习压力大,需要关注", + "createBy": 2001, + "createTime": "2025-01-10 09:20:00", + "updateBy": 2001, + "updateTime": "2025-01-10 09:20:00", + "evaluationName": "2024上学期计算机2301班心理健康测评", + "className": "计算机2301班", + "majorName": "计算机应用技术", + "semester": "2024上学期" + } + ] + } +} +``` + +#### 2.2.2 根据测评ID查询明细列表 + +- **接口URL**:/xljk/evaluation/detail/evaluation/{evaluationId} +- **请求方式**:GET +- **接口权限**:xljk:evaluation:query +- **请求参数**: + +| 参数名 | 类型 | 是否必须 | 描述 | +| ------ | ---- | -------- | ---- | +| evaluationId | long | 是 | 测评ID | + +- **返回示例**: + +```json +{ + "code": 200, + "msg": "操作成功", + "data": [ + { + "id": 101, + "evaluationId": 1, + "studentId": 10001, + "studentNo": "2024001", + "studentName": "张三", + "gender": "0", + "birthDate": "2005-06-15", + "phone": "13800138001", + "mentalStatus": "1", + "score": null, + "remark": null, + "createBy": 2001, + "createTime": "2025-01-10 09:10:00", + "updateBy": 2001, + "updateTime": "2025-01-10 09:10:00" + }, + { + "id": 102, + "evaluationId": 1, + "studentId": 10002, + "studentNo": "2024002", + "studentName": "李四", + "gender": "0", + "birthDate": "2005-03-22", + "phone": "13800138002", + "mentalStatus": "2", + "score": null, + "remark": null, + "createBy": 2001, + "createTime": "2025-01-10 09:15:00", + "updateBy": 2001, + "updateTime": "2025-01-10 09:15:00" + } + ] +} +``` + +#### 2.2.3 获取学生信息 + +- **接口URL**:/xljk/evaluation/detail/students/{classId} +- **请求方式**:GET +- **接口权限**:xljk:evaluation:query +- **请求参数**: + +| 参数名 | 类型 | 是否必须 | 描述 | +| ------ | ---- | -------- | ---- | +| classId | long | 是 | 班级ID | + +- **返回示例**: + +```json +{ + "code": 200, + "msg": "操作成功", + "data": [ + { + "id": 10001, + "studentNo": "2024001", + "studentName": "张三", + "gender": "0", + "birthDate": "2005-06-15", + "phone": "13800138001" + }, + { + "id": 10002, + "studentNo": "2024002", + "studentName": "李四", + "gender": "0", + "birthDate": "2005-03-22", + "phone": "13800138002" + } + ] +} +``` + +#### 2.2.4 批量新增测评明细 + +- **接口URL**:/xljk/evaluation/detail/batch +- **请求方式**:POST +- **接口权限**:xljk:evaluation:add +- **请求参数**: + +| 参数名 | 类型 | 是否必须 | 描述 | +| ------ | ---- | -------- | ---- | +| 数组 | array | 是 | 测评明细数组 | + +- **请求示例**: + +```json +[ + { + "evaluationId": 3, + "studentId": 10001, + "studentNo": "2024001", + "studentName": "张三", + "gender": "0", + "birthDate": "2005-06-15", + "phone": "13800138001" + }, + { + "evaluationId": 3, + "studentId": 10002, + "studentNo": "2024002", + "studentName": "李四", + "gender": "0", + "birthDate": "2005-03-22", + "phone": "13800138002" + } +] +``` + +- **返回示例**: + +```json +{ + "code": 200, + "msg": "操作成功" +} +``` + +#### 2.2.5 批量更新学生心理状态 + +- **接口URL**:/xljk/evaluation/detail/batch/mentalStatus +- **请求方式**:PUT +- **接口权限**:xljk:evaluation:edit +- **请求参数**: + +| 参数名 | 类型 | 是否必须 | 描述 | +| ------ | ---- | -------- | ---- | +| 数组 | array | 是 | 学生心理状态数组 | + +- **请求示例**: + +```json +[ + { + "id": 101, + "mentalStatus": "1" + }, + { + "id": 102, + "mentalStatus": "2" + }, + { + "id": 103, + "mentalStatus": "3", + "score": 75, + "remark": "近期学习压力大,需要关注" + } +] +``` + +- **返回示例**: + +```json +{ + "code": 200, + "msg": "操作成功" +} +``` + +#### 2.2.6 获取重点关注学生列表 + +- **接口URL**:/xljk/evaluation/detail/focus +- **请求方式**:GET +- **接口权限**:xljk:evaluation:query +- **请求参数**: + +| 参数名 | 类型 | 是否必须 | 描述 | +| ------ | ---- | -------- | ---- | +| pageNum | int | 否 | 当前页码,默认为1 | +| pageSize | int | 否 | 每页记录数,默认为10 | +| evaluationId | long | 否 | 测评ID | +| studentName | string | 否 | 学生姓名,支持模糊查询 | +| studentNo | string | 否 | 学号,支持模糊查询 | +| gender | string | 否 | 性别(0-男,1-女,2-未知) | + +- **返回示例**: + +```json +{ + "code": 200, + "msg": "操作成功", + "data": { + "total": 2, + "rows": [ + { + "id": 103, + "evaluationId": 1, + "studentId": 10003, + "studentNo": "2024003", + "studentName": "王五", + "gender": "0", + "birthDate": "2005-09-10", + "phone": "13800138003", + "mentalStatus": "3", + "score": 75, + "remark": "近期学习压力大,需要关注", + "createBy": 2001, + "createTime": "2025-01-10 09:20:00", + "updateBy": 2001, + "updateTime": "2025-01-10 09:20:00", + "evaluationName": "2024上学期计算机2301班心理健康测评", + "className": "计算机2301班", + "majorName": "计算机应用技术", + "semester": "2024上学期" + }, + { + "id": 105, + "evaluationId": 1, + "studentId": 10005, + "studentNo": "2024005", + "studentName": "钱七", + "gender": "1", + "birthDate": "2005-07-20", + "phone": "13800138005", + "mentalStatus": "3", + "score": 80, + "remark": "家庭情况特殊,需要关注", + "createBy": 2001, + "createTime": "2025-01-10 09:30:00", + "updateBy": 2001, + "updateTime": "2025-01-10 09:30:00", + "evaluationName": "2024上学期计算机2301班心理健康测评", + "className": "计算机2301班", + "majorName": "计算机应用技术", + "semester": "2024上学期" + } + ] + } +} +``` + +### 2.3 统计分析API + +#### 2.3.1 获取测评统计数据 + +- **接口URL**:/xljk/evaluation/{id}/statistics +- **请求方式**:GET +- **接口权限**:xljk:evaluation:statistics +- **请求参数**: + +| 参数名 | 类型 | 是否必须 | 描述 | +| ------ | ---- | -------- | ---- | +| id | long | 是 | 测评ID | + +- **返回示例**: + +```json +{ + "code": 200, + "msg": "操作成功", + "data": { + "evaluationName": "2024上学期计算机2301班心理健康测评", + "className": "计算机2301班", + "semester": "2024上学期", + "createName": "张班主任", + "createTime": "2025-01-10 09:00:00", + "totalCount": 5, + "healthyCount": 2, + "goodCount": 1, + "focusCount": 2, + "healthyPercent": 40.0, + "goodPercent": 20.0, + "focusPercent": 40.0, + "maleCount": 3, + "femaleCount": 2, + "maleFocusCount": 1, + "femaleFocusCount": 1 + } +} +``` + +#### 2.3.2 获取重点关注学生统计 + +- **接口URL**:/xljk/evaluation/statistics/focus +- **请求方式**:GET +- **接口权限**:xljk:evaluation:statistics +- **请求参数**: + +| 参数名 | 类型 | 是否必须 | 描述 | +| ------ | ---- | -------- | ---- | +| majorId | long | 否 | 专业ID | +| classId | long | 否 | 班级ID | +| semester | string | 否 | 学期 | + +- **返回示例**: + +```json +{ + "code": 200, + "msg": "操作成功", + "data": { + "totalStudentCount": 10, + "totalFocusCount": 4, + "totalFocusRate": 40.0, + "classStats": [ + { + "className": "计算机2301班", + "studentCount": 5, + "focusCount": 2, + "focusRate": 40.0 + }, + { + "className": "电子2302班", + "studentCount": 5, + "focusCount": 2, + "focusRate": 40.0 + } + ], + "semesterStats": [ + { + "semester": "2023下学期", + "studentCount": 5, + "focusCount": 2, + "focusRate": 40.0 + }, + { + "semester": "2024上学期", + "studentCount": 5, + "focusCount": 2, + "focusRate": 40.0 + } + ] + } +} +``` + +## 3. 数据字典 + +### 3.1 测评状态(xljk_evaluation_status) + +| 编码 | 标签 | 描述 | +| ---- | ---- | ---- | +| 0 | 草稿 | 测评创建后的初始状态 | +| 1 | 已发布 | 测评发布后的状态 | +| 2 | 已完成 | 测评完成后的状态 | + +### 3.2 心理状态(xljk_mental_status) + +| 编码 | 标签 | 描述 | +| ---- | ---- | ---- | +| 1 | 健康 | 心理状态健康 | +| 2 | 良好 | 心理状态良好 | +| 3 | 重点关注 | 需要重点关注的心理状态 | + +## 4. 注意事项 + +1. 测评状态流转:草稿 -> 已发布 -> 已完成,不能跳过中间状态 +2. 草稿状态的测评可以修改和删除,已发布和已完成状态的测评不能删除 +3. 已完成状态的测评不能修改学生心理状态 +4. 重点关注状态的学生必须填写分数 +5. 测评完成后,会统计各状态学生人数和比例 +6. 班主任只能查看和管理自己创建的测评 \ No newline at end of file diff --git a/docs/设计文档/database/心理健康测评/xljk_add_department_fields.sql b/docs/设计文档/database/心理健康测评/xljk_add_department_fields.sql new file mode 100644 index 00000000..bc340be7 --- /dev/null +++ b/docs/设计文档/database/心理健康测评/xljk_add_department_fields.sql @@ -0,0 +1,27 @@ +-- 心理健康测评表增加院系字段脚本 +-- 日期:2025-07-02 +-- 作者:lixuming + +-- 在心理健康测评表中添加院系ID和院系名称字段 +ALTER TABLE xljk_evaluation +ADD COLUMN department_id bigint NOT NULL COMMENT '院系ID' AFTER id, +ADD COLUMN department_name varchar(100) NOT NULL COMMENT '院系名称' AFTER department_id; + +-- 更新已有数据,设置默认值 +-- 这里使用智能控制学院(103)作为示例默认值 +UPDATE xljk_evaluation SET department_id = 103, department_name = '智能控制学院' WHERE 1=1; + +-- 为院系ID字段添加索引以提高查询效率 +ALTER TABLE xljk_evaluation ADD INDEX idx_department_id (department_id); + +-- 系统院系参考数据(来自sys_dept表) +-- 101 是二级学院的父级ID +/* +智能控制学院(103) +智能制造学院(104) +医药健康学院(105) +餐饮休闲学院(106) +数字信息学院(107) +人文学院(1938483954134245378) +生态园林学院(1938484049621770242) +*/ \ No newline at end of file diff --git a/docs/设计文档/database/心理健康测评/xljk_evaluation.sql b/docs/设计文档/database/心理健康测评/xljk_evaluation.sql new file mode 100644 index 00000000..3ebbf669 --- /dev/null +++ b/docs/设计文档/database/心理健康测评/xljk_evaluation.sql @@ -0,0 +1,81 @@ +-- ---------------------------- +-- 心理健康测评模块数据表 +-- ---------------------------- + +-- ---------------------------- +-- 心理健康测评表 +-- ---------------------------- +DROP TABLE IF EXISTS `xljk_evaluation`; +CREATE TABLE `xljk_evaluation` ( + `id` bigint(20) NOT NULL COMMENT '主键ID', + `evaluation_name` varchar(100) NOT NULL COMMENT '测评名称', + `major_id` bigint(20) NOT NULL COMMENT '专业ID', + `major_name` varchar(100) NOT NULL COMMENT '专业名称', + `class_id` bigint(20) NOT NULL COMMENT '班级ID', + `class_name` varchar(100) NOT NULL COMMENT '班级名称', + `semester` varchar(50) NOT NULL COMMENT '学期(如2024上学期)', + `status` char(1) NOT NULL DEFAULT '0' COMMENT '状态(0-草稿,1-已发布,2-已完成)', + `create_by` bigint(20) NOT NULL COMMENT '创建者ID(班主任ID)', + `create_name` varchar(50) NOT NULL COMMENT '创建者姓名', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新者', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) DEFAULT NULL COMMENT '备注', + `tenant_id` varchar(20) DEFAULT NULL COMMENT '租户ID', + `deleted` char(1) NOT NULL DEFAULT '0' COMMENT '删除标志(0-存在,1-删除)', + PRIMARY KEY (`id`), + KEY `idx_class_id` (`class_id`), + KEY `idx_semester` (`semester`), + KEY `idx_status` (`status`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='心理健康测评表'; + +-- ---------------------------- +-- 心理健康测评明细表 +-- ---------------------------- +DROP TABLE IF EXISTS `xljk_evaluation_detail`; +CREATE TABLE `xljk_evaluation_detail` ( + `id` bigint(20) NOT NULL COMMENT '主键ID', + `evaluation_id` bigint(20) NOT NULL COMMENT '测评表ID', + `student_id` bigint(20) NOT NULL COMMENT '学生ID', + `student_no` varchar(50) NOT NULL COMMENT '学号', + `student_name` varchar(50) NOT NULL COMMENT '学生姓名', + `gender` char(1) DEFAULT NULL COMMENT '性别(0-男,1-女,2-未知)', + `birth_date` date DEFAULT NULL COMMENT '出生日期', + `phone` varchar(20) DEFAULT NULL COMMENT '联系电话', + `mental_status` char(1) NOT NULL COMMENT '心理状态(1-健康,2-良好,3-重点关注)', + `score` int(11) DEFAULT NULL COMMENT '分数(仅重点关注时填写)', + `create_by` bigint(20) NOT NULL COMMENT '创建者', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新者', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) DEFAULT NULL COMMENT '备注', + `tenant_id` varchar(20) DEFAULT NULL COMMENT '租户ID', + `deleted` char(1) NOT NULL DEFAULT '0' COMMENT '删除标志(0-存在,1-删除)', + PRIMARY KEY (`id`), + KEY `idx_evaluation_id` (`evaluation_id`), + KEY `idx_student_id` (`student_id`), + KEY `idx_mental_status` (`mental_status`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='心理健康测评明细表'; + +-- ---------------------------- +-- 示例数据 +-- ---------------------------- + +-- 插入测评表示例数据 +INSERT INTO `xljk_evaluation` VALUES (1, '2024上学期计算机2301班心理健康测评', 101, '计算机应用技术', 1001, '计算机2301班', '2024上学期', '2', 2001, '张班主任', '2025-01-10 09:00:00', 2001, '2025-01-10 10:30:00', '期末测评', '000000', '0'); +INSERT INTO `xljk_evaluation` VALUES (2, '2024上学期电子2302班心理健康测评', 102, '电子商务', 1002, '电子2302班', '2024上学期', '0', 2002, '李班主任', '2025-01-11 14:00:00', 2002, '2025-01-11 14:30:00', '期末测评草稿', '000000', '0'); +INSERT INTO `xljk_evaluation` VALUES (3, '2023下学期计算机2301班心理健康测评', 101, '计算机应用技术', 1001, '计算机2301班', '2023下学期', '2', 2001, '张班主任', '2024-12-15 09:00:00', 2001, '2024-12-15 11:00:00', '期末测评', '000000', '0'); + +-- 插入测评明细示例数据 +INSERT INTO `xljk_evaluation_detail` VALUES (101, 1, 10001, '2024001', '张三', '0', '2005-06-15', '13800138001', '1', NULL, 2001, '2025-01-10 09:10:00', 2001, '2025-01-10 09:10:00', NULL, '000000', '0'); +INSERT INTO `xljk_evaluation_detail` VALUES (102, 1, 10002, '2024002', '李四', '0', '2005-03-22', '13800138002', '2', NULL, 2001, '2025-01-10 09:15:00', 2001, '2025-01-10 09:15:00', NULL, '000000', '0'); +INSERT INTO `xljk_evaluation_detail` VALUES (103, 1, 10003, '2024003', '王五', '0', '2005-09-10', '13800138003', '3', 75, 2001, '2025-01-10 09:20:00', 2001, '2025-01-10 09:20:00', '近期学习压力大,需要关注', '000000', '0'); +INSERT INTO `xljk_evaluation_detail` VALUES (104, 1, 10004, '2024004', '赵六', '1', '2005-11-05', '13800138004', '1', NULL, 2001, '2025-01-10 09:25:00', 2001, '2025-01-10 09:25:00', NULL, '000000', '0'); +INSERT INTO `xljk_evaluation_detail` VALUES (105, 1, 10005, '2024005', '钱七', '1', '2005-07-20', '13800138005', '3', 80, 2001, '2025-01-10 09:30:00', 2001, '2025-01-10 09:30:00', '家庭情况特殊,需要关注', '000000', '0'); + +-- 插入第三个测评的明细示例数据 +INSERT INTO `xljk_evaluation_detail` VALUES (201, 3, 10001, '2024001', '张三', '0', '2005-06-15', '13800138001', '1', NULL, 2001, '2024-12-15 09:10:00', 2001, '2024-12-15 09:10:00', NULL, '000000', '0'); +INSERT INTO `xljk_evaluation_detail` VALUES (202, 3, 10002, '2024002', '李四', '0', '2005-03-22', '13800138002', '1', NULL, 2001, '2024-12-15 09:15:00', 2001, '2024-12-15 09:15:00', NULL, '000000', '0'); +INSERT INTO `xljk_evaluation_detail` VALUES (203, 3, 10003, '2024003', '王五', '0', '2005-09-10', '13800138003', '3', 70, 2001, '2024-12-15 09:20:00', 2001, '2024-12-15 09:20:00', '期末考试压力大', '000000', '0'); +INSERT INTO `xljk_evaluation_detail` VALUES (204, 3, 10004, '2024004', '赵六', '1', '2005-11-05', '13800138004', '2', NULL, 2001, '2024-12-15 09:25:00', 2001, '2024-12-15 09:25:00', NULL, '000000', '0'); +INSERT INTO `xljk_evaluation_detail` VALUES (205, 3, 10005, '2024005', '钱七', '1', '2005-07-20', '13800138005', '3', 85, 2001, '2024-12-15 09:30:00', 2001, '2024-12-15 09:30:00', '家庭情况特殊,需要关注', '000000', '0'); \ No newline at end of file diff --git a/docs/设计文档/database/心理健康测评/xljk_field_update.sql b/docs/设计文档/database/心理健康测评/xljk_field_update.sql new file mode 100644 index 00000000..759a4e74 --- /dev/null +++ b/docs/设计文档/database/心理健康测评/xljk_field_update.sql @@ -0,0 +1,26 @@ +-- 心理健康测评数据库字段更新脚本 +-- 日期:2025-07-02 +-- 作者:lixuming + +-- 在心理健康测评表中添加create_dept字段 +ALTER TABLE xljk_evaluation ADD COLUMN create_dept bigint NOT NULL COMMENT '创建部门' AFTER tenant_id; + +-- 在心理健康测评明细表中添加create_dept字段 +ALTER TABLE xljk_evaluation_detail ADD COLUMN create_dept bigint NOT NULL COMMENT '创建部门' AFTER tenant_id; + +-- 初始化create_dept字段,将create_by的值作为create_dept的初始值 +UPDATE xljk_evaluation SET create_dept = create_by; +UPDATE xljk_evaluation_detail SET create_dept = create_by; + +-- 更新心理健康测评表的XML映射文件: +-- 在backend/ruoyi-modules/ruoyi-xljk/src/main/resources/mapper/XljkEvaluationMapper.xml文件中添加: +-- + +-- 更新心理健康测评明细表的XML映射文件: +-- 在backend/ruoyi-modules/ruoyi-xljk/src/main/resources/mapper/XljkEvaluationDetailMapper.xml文件中添加: +-- + +-- 说明: +-- 此脚本用于修复心理健康测评模块中因字段缺失导致的SQL错误 +-- 错误:Unknown column 'create_dept' in 'field list' +-- 原因:实体类通过继承BaseEntity获得了createDept字段,但数据库表中不存在对应的create_dept列 \ No newline at end of file diff --git a/docs/设计文档/database/心理健康测评/xljk_menu_config.sql b/docs/设计文档/database/心理健康测评/xljk_menu_config.sql new file mode 100644 index 00000000..a58ea983 --- /dev/null +++ b/docs/设计文档/database/心理健康测评/xljk_menu_config.sql @@ -0,0 +1,89 @@ +-- ========================================== +-- 心理健康测评模块菜单权限配置脚本 +-- 版本:V1.0.1 +-- 功能:心理健康测评模块菜单权限配置 +-- 作者:lixuming +-- 时间:2025-07-02 +-- 依据文档:docs/需求文档/心理测评需求/心理健康测评系统设计说明.md +-- 更新:将心理健康设置为一级菜单,与首页、系统管理平级 +-- ========================================== + +-- 设置字符集 +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +-- ---------------------------- +-- 心理健康测评模块菜单结构(二级层级) +-- ---------------------------- + +-- 1. 心理健康一级菜单(与首页、系统管理平级) +INSERT INTO `sys_menu` ( + `menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query_param`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark` +) VALUES +(2300, '心理健康', 0, 8, 'xljk', NULL, NULL, 1, 0, 'M', '0', '0', NULL, 'heart', 103, 1, NOW(), 1, NOW(), '心理健康一级菜单'); + +-- 2. 心理健康测评二级功能菜单 +INSERT INTO `sys_menu` ( + `menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query_param`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark` +) VALUES +(2310, '心理健康测评', 2300, 1, 'evaluation', 'xljk/evaluation/index', NULL, 1, 0, 'C', '0', '0', 'xljk:evaluation:list', 'form', 103, 1, NOW(), 1, NOW(), '心理健康测评页面'); + +-- 3. 心理健康测评功能按钮 +INSERT INTO `sys_menu` ( + `menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query_param`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark` +) VALUES +-- 心理健康测评按钮 +(2311, '测评查询', 2310, 1, '', NULL, NULL, 1, 0, 'F', '0', '0', 'xljk:evaluation:query', '#', 103, 1, NOW(), 1, NOW(), '测评查询'), +(2312, '测评新增', 2310, 2, '', NULL, NULL, 1, 0, 'F', '0', '0', 'xljk:evaluation:add', '#', 103, 1, NOW(), 1, NOW(), '测评新增'), +(2313, '测评修改', 2310, 3, '', NULL, NULL, 1, 0, 'F', '0', '0', 'xljk:evaluation:edit', '#', 103, 1, NOW(), 1, NOW(), '测评修改'), +(2314, '测评删除', 2310, 4, '', NULL, NULL, 1, 0, 'F', '0', '0', 'xljk:evaluation:remove', '#', 103, 1, NOW(), 1, NOW(), '测评删除'), +(2315, '测评导出', 2310, 5, '', NULL, NULL, 1, 0, 'F', '0', '0', 'xljk:evaluation:export', '#', 103, 1, NOW(), 1, NOW(), '测评导出'); + +-- ---------------------------- +-- 角色菜单权限配置 +-- ---------------------------- + +-- 为超级管理员角色分配所有权限 +INSERT INTO `sys_role_menu` (`role_id`, `menu_id`) +SELECT 1, menu_id FROM `sys_menu` WHERE menu_id = 2300 OR (menu_id >= 2310 AND menu_id <= 2315); + +-- 为学生处管理员角色分配全部权限 +INSERT INTO `sys_role_menu` (`role_id`, `menu_id`) +SELECT 2, menu_id FROM `sys_menu` WHERE menu_id = 2300 OR (menu_id >= 2310 AND menu_id <= 2315); + +-- 为二级学院管理员角色分配权限 +INSERT INTO `sys_role_menu` (`role_id`, `menu_id`) +SELECT 3, menu_id FROM `sys_menu` WHERE menu_id = 2300 OR (menu_id >= 2310 AND menu_id <= 2315); + +-- 为辅导员角色分配权限 +INSERT INTO `sys_role_menu` (`role_id`, `menu_id`) VALUES +(4, 2300), -- 心理健康一级菜单 +(4, 2310), -- 心理健康测评 +(4, 2311), -- 测评查询 +(4, 2312), -- 测评新增 +(4, 2313), -- 测评修改 +(4, 2315); -- 测评导出 + +-- 为班级教师角色分配基础权限 +INSERT INTO `sys_role_menu` (`role_id`, `menu_id`) VALUES +(5, 2300), -- 心理健康一级菜单 +(5, 2310), -- 心理健康测评 +(5, 2311); -- 测评查询 + +-- 为学生角色分配查看权限 +INSERT INTO `sys_role_menu` (`role_id`, `menu_id`) VALUES +(6, 2300), -- 心理健康一级菜单 +(6, 2310), -- 心理健康测评 +(6, 2311); -- 测评查询 + +-- 添加心理健康测评状态字典 +INSERT INTO `sys_dict_type` VALUES(1000, '心理测评状态', 'evaluation_status', '0', 1, NOW(), NULL, NULL, '心理健康测评状态'); +INSERT INTO `sys_dict_data` VALUES(1001, 0, '草稿', '0', 'evaluation_status', '', 'warning', 'N', '0', 1, NOW(), 1, NOW(), '草稿状态'); +INSERT INTO `sys_dict_data` VALUES(1002, 1, '已发布', '1', 'evaluation_status', '', 'primary', 'N', '0', 1, NOW(), 1, NOW(), '已发布状态'); +INSERT INTO `sys_dict_data` VALUES(1003, 2, '已完成', '2', 'evaluation_status', '', 'success', 'N', '0', 1, NOW(), 1, NOW(), '已完成状态'); + +SET FOREIGN_KEY_CHECKS = 1; + +-- 验证菜单配置结果 +SELECT '心理健康测评菜单权限配置完成!' AS result; +SELECT CONCAT('心理健康测评菜单:', COUNT(*), '个') AS menu_info FROM sys_menu WHERE menu_id BETWEEN 2300 AND 2315; \ No newline at end of file diff --git a/docs/需求文档/心理测评需求/心理健康测评系统设计说明.md b/docs/需求文档/心理测评需求/心理健康测评系统设计说明.md new file mode 100644 index 00000000..ed179227 --- /dev/null +++ b/docs/需求文档/心理测评需求/心理健康测评系统设计说明.md @@ -0,0 +1,198 @@ +# 心理健康测评系统设计说明 + +## 设计目标 + +设计一个简单实用的心理健康测评系统,由班主任为班级学生进行心理健康状况评估,并记录重点关注的学生,为学校心理健康管理提供有效支持。 + +## 数据表设计 + +### 1. 心理健康测评表 (`xljk_evaluation`) + +**主要功能**: 管理班级心理健康测评的基本信息 + +**字段说明**: + +- **标准字段**: 按要求包含 `id`、`tenant_id`、`create_by`、`create_time`、`update_by`、`update_time`、`deleted` +- **业务字段**: + - `evaluation_name`: 测评名称 + - `major_id`: 专业ID + - `major_name`: 专业名称 + - `class_id`: 班级ID + - `class_name`: 班级名称 + - `semester`: 学期(如2024上学期) + - `status`: 状态(0-草稿,1-已发布,2-已完成) + - `create_name`: 创建者姓名(班主任姓名) + - `remark`: 备注 + +### 2. 心理健康测评明细表 (`xljk_evaluation_detail`) + +**主要功能**: 记录每个学生的心理健康评估结果 + +**字段说明**: + +- **标准字段**: 按要求包含 `id`、`tenant_id`、`create_by`、`create_time`、`update_by`、`update_time`、`deleted` +- **学生信息**: + - `evaluation_id`: 关联测评表ID + - `student_id`: 学生ID + - `student_no`: 学号 + - `student_name`: 学生姓名 + - `gender`: 性别(0-男,1-女,2-未知) + - `birth_date`: 出生日期 + - `phone`: 联系电话 +- **评估信息**: + - `mental_status`: 心理状态(1-健康,2-良好,3-重点关注) + - `score`: 分数(仅重点关注时填写) + - `remark`: 备注 + +## 核心功能流程 + +### 1. 测评创建 + +- 班主任创建新测评表 +- 选择专业、班级、学年(如2024上学期) +- 系统自动加载该班级学生信息(专业、班级、学号、姓名、性别、出生日期、联系电话) +- 初始状态为"草稿" + +### 2. 测评填写 + +- 班主任为每个学生选择心理状态:健康、良好、重点关注 +- 选择"重点关注"时,需要填写分数 +- 无固定分数标准,重点关注由班主任自行判断 +- 可保存为草稿,随时继续编辑 + +### 3. 测评提交 + +- 班主任确认所有学生评估完成后提交 +- 提交后状态改为"已完成" +- 提交后保存历史测评记录 +- 无需流转审批 + +### 4. 测评统计 + +- 统计重点关注学生数量和比例 +- 生成重点关注学生名单 +- 支持按学期、专业、班级查看统计数据 + +## 设计特点 + +### 简化原则 + +- 无固定测评周期,由班主任自行发起测评 +- 测评直接提交完成,无需流转审批 +- 重点关注无固定分数标准,由班主任自行判断 + +### 数据关联 + +- 测评明细表通过 `evaluation_id` 关联测评主表 +- 学生信息从学生信息管理模块同步获取 +- 保存历史测评记录,支持趋势分析 + +### 数据完整性 + +- 使用雪花ID作为主键,保证唯一性 +- 外键约束确保测评明细表与测评表的关联 +- 必填字段设置 NOT NULL 约束 +- 合理的索引设计提高查询效率 + +## 角色权限 + +### 班主任 + +- 创建和填写心理健康测评表 +- 查看本班学生的心理测评历史记录 +- 查看本班学生的心理咨询预约情况 + +### 心理健康管理员 + +- 查看所有班级的测评统计数据 +- 查看重点关注学生名单 +- 无权修改测评数据 + +### 心理咨询师 + +- 查看重点关注学生名单 +- 查看学生的测评历史 +- 无权修改测评数据 + +## SQL建表语句 + +```sql +-- 心理健康测评表 +CREATE TABLE `xljk_evaluation` ( + `id` bigint(20) NOT NULL COMMENT '主键ID', + `evaluation_name` varchar(100) NOT NULL COMMENT '测评名称', + `major_id` bigint(20) NOT NULL COMMENT '专业ID', + `major_name` varchar(100) NOT NULL COMMENT '专业名称', + `class_id` bigint(20) NOT NULL COMMENT '班级ID', + `class_name` varchar(100) NOT NULL COMMENT '班级名称', + `semester` varchar(50) NOT NULL COMMENT '学期(如2024上学期)', + `status` char(1) NOT NULL DEFAULT '0' COMMENT '状态(0-草稿,1-已发布,2-已完成)', + `create_by` bigint(20) NOT NULL COMMENT '创建者ID(班主任ID)', + `create_name` varchar(50) NOT NULL COMMENT '创建者姓名', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新者', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) DEFAULT NULL COMMENT '备注', + `tenant_id` varchar(20) DEFAULT NULL COMMENT '租户ID', + `deleted` char(1) NOT NULL DEFAULT '0' COMMENT '删除标志(0-存在,1-删除)', + PRIMARY KEY (`id`), + KEY `idx_class_id` (`class_id`), + KEY `idx_semester` (`semester`), + KEY `idx_status` (`status`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='心理健康测评表'; + +-- 心理健康测评明细表 +CREATE TABLE `xljk_evaluation_detail` ( + `id` bigint(20) NOT NULL COMMENT '主键ID', + `evaluation_id` bigint(20) NOT NULL COMMENT '测评表ID', + `student_id` bigint(20) NOT NULL COMMENT '学生ID', + `student_no` varchar(50) NOT NULL COMMENT '学号', + `student_name` varchar(50) NOT NULL COMMENT '学生姓名', + `gender` char(1) DEFAULT NULL COMMENT '性别(0-男,1-女,2-未知)', + `birth_date` date DEFAULT NULL COMMENT '出生日期', + `phone` varchar(20) DEFAULT NULL COMMENT '联系电话', + `mental_status` char(1) NOT NULL COMMENT '心理状态(1-健康,2-良好,3-重点关注)', + `score` int(11) DEFAULT NULL COMMENT '分数(仅重点关注时填写)', + `create_by` bigint(20) NOT NULL COMMENT '创建者', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新者', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) DEFAULT NULL COMMENT '备注', + `tenant_id` varchar(20) DEFAULT NULL COMMENT '租户ID', + `deleted` char(1) NOT NULL DEFAULT '0' COMMENT '删除标志(0-存在,1-删除)', + PRIMARY KEY (`id`), + KEY `idx_evaluation_id` (`evaluation_id`), + KEY `idx_student_id` (`student_id`), + KEY `idx_mental_status` (`mental_status`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='心理健康测评明细表'; +``` + +## 示例数据 + +```sql +-- 插入测评表示例数据 +INSERT INTO `xljk_evaluation` VALUES (1, '2024上学期计算机2301班心理健康测评', 101, '计算机应用技术', 1001, '计算机2301班', '2024上学期', '2', 2001, '张班主任', '2025-01-10 09:00:00', 2001, '2025-01-10 10:30:00', '期末测评', '000000', '0'); +INSERT INTO `xljk_evaluation` VALUES (2, '2024上学期电子2302班心理健康测评', 102, '电子商务', 1002, '电子2302班', '2024上学期', '0', 2002, '李班主任', '2025-01-11 14:00:00', 2002, '2025-01-11 14:30:00', '期末测评草稿', '000000', '0'); +INSERT INTO `xljk_evaluation` VALUES (3, '2023下学期计算机2301班心理健康测评', 101, '计算机应用技术', 1001, '计算机2301班', '2023下学期', '2', 2001, '张班主任', '2024-12-15 09:00:00', 2001, '2024-12-15 11:00:00', '期末测评', '000000', '0'); + +-- 插入测评明细示例数据 +INSERT INTO `xljk_evaluation_detail` VALUES (101, 1, 10001, '2024001', '张三', '0', '2005-06-15', '13800138001', '1', NULL, 2001, '2025-01-10 09:10:00', 2001, '2025-01-10 09:10:00', NULL, '000000', '0'); +INSERT INTO `xljk_evaluation_detail` VALUES (102, 1, 10002, '2024002', '李四', '0', '2005-03-22', '13800138002', '2', NULL, 2001, '2025-01-10 09:15:00', 2001, '2025-01-10 09:15:00', NULL, '000000', '0'); +INSERT INTO `xljk_evaluation_detail` VALUES (103, 1, 10003, '2024003', '王五', '0', '2005-09-10', '13800138003', '3', 75, 2001, '2025-01-10 09:20:00', 2001, '2025-01-10 09:20:00', '近期学习压力大,需要关注', '000000', '0'); +INSERT INTO `xljk_evaluation_detail` VALUES (104, 1, 10004, '2024004', '赵六', '1', '2005-11-05', '13800138004', '1', NULL, 2001, '2025-01-10 09:25:00', 2001, '2025-01-10 09:25:00', NULL, '000000', '0'); +INSERT INTO `xljk_evaluation_detail` VALUES (105, 1, 10005, '2024005', '钱七', '1', '2005-07-20', '13800138005', '3', 80, 2001, '2025-01-10 09:30:00', 2001, '2025-01-10 09:30:00', '家庭情况特殊,需要关注', '000000', '0'); + +-- 插入第三个测评的明细示例数据 +INSERT INTO `xljk_evaluation_detail` VALUES (201, 3, 10001, '2024001', '张三', '0', '2005-06-15', '13800138001', '1', NULL, 2001, '2024-12-15 09:10:00', 2001, '2024-12-15 09:10:00', NULL, '000000', '0'); +INSERT INTO `xljk_evaluation_detail` VALUES (202, 3, 10002, '2024002', '李四', '0', '2005-03-22', '13800138002', '1', NULL, 2001, '2024-12-15 09:15:00', 2001, '2024-12-15 09:15:00', NULL, '000000', '0'); +INSERT INTO `xljk_evaluation_detail` VALUES (203, 3, 10003, '2024003', '王五', '0', '2005-09-10', '13800138003', '3', 70, 2001, '2024-12-15 09:20:00', 2001, '2024-12-15 09:20:00', '期末考试压力大', '000000', '0'); +INSERT INTO `xljk_evaluation_detail` VALUES (204, 3, 10004, '2024004', '赵六', '1', '2005-11-05', '13800138004', '2', NULL, 2001, '2024-12-15 09:25:00', 2001, '2024-12-15 09:25:00', NULL, '000000', '0'); +INSERT INTO `xljk_evaluation_detail` VALUES (205, 3, 10005, '2024005', '钱七', '1', '2005-07-20', '13800138005', '3', 85, 2001, '2024-12-15 09:30:00', 2001, '2024-12-15 09:30:00', '家庭情况特殊,需要关注', '000000', '0'); +``` + +## 使用说明 + +1. 执行上述SQL脚本创建数据表和示例数据 +2. 系统会从学生信息管理模块同步学生基础信息 +3. 班主任可以根据需要随时发起心理健康测评 +4. 测评完成后,可以查看重点关注学生名单和统计数据 \ No newline at end of file diff --git a/test/心理健康测评API测试脚本.js b/test/心理健康测评API测试脚本.js new file mode 100644 index 00000000..6e2e7466 --- /dev/null +++ b/test/心理健康测评API测试脚本.js @@ -0,0 +1,613 @@ +/** + * 心理健康测评API测试脚本 + * 使用Node.js和axios进行API测试 + * + * @author Cursor AI + * @date 2025-07-02 + */ + +const axios = require('axios'); +const fs = require('fs'); + +// 配置信息 +const config = { + baseURL: 'http://localhost:8080', + timeout: 10000, + headers: { + 'Content-Type': 'application/json' + } +}; + +// 测试结果记录 +const testResults = { + total: 0, + passed: 0, + failed: 0, + skipped: 0, + details: [] +}; + +// 创建axios实例 +const api = axios.create(config); + +// 存储登录后的token +let token = ''; +// 存储测试过程中创建的测评ID +let evaluationId = null; +// 存储测试过程中创建的测评明细ID +let detailIds = []; + +/** + * 登录获取token + */ +async function login() { + try { + console.log('===== 登录获取token ====='); + const loginData = { + username: 'admin', + password: 'admin123', + code: '1234', + uuid: 'test-uuid' + }; + + const response = await api.post('/login', loginData); + if (response.data.code === 200) { + token = response.data.data.token; + api.defaults.headers.common['Authorization'] = `Bearer ${token}`; + console.log('登录成功,获取token成功'); + return true; + } else { + console.error('登录失败:', response.data.msg); + return false; + } + } catch (error) { + console.error('登录异常:', error.message); + return false; + } +} + +/** + * 记录测试结果 + * @param {string} name 测试名称 + * @param {boolean} passed 是否通过 + * @param {string} message 测试消息 + * @param {object} response 响应数据 + */ +function recordTestResult(name, passed, message, response) { + testResults.total++; + if (passed) { + testResults.passed++; + console.log(`✅ ${name}: ${message}`); + } else { + testResults.failed++; + console.error(`❌ ${name}: ${message}`); + } + + testResults.details.push({ + name, + passed, + message, + response: response ? JSON.stringify(response) : null, + timestamp: new Date().toISOString() + }); +} + +/** + * 测试获取专业和班级选项 + */ +async function testGetMajorAndClassOptions() { + try { + console.log('\n===== 测试获取专业和班级选项 ====='); + const response = await api.get('/xljk/evaluation/options/majorAndClass'); + const passed = response.data.code === 200 && + response.data.data && + response.data.data.majors && + response.data.data.classes; + + recordTestResult('获取专业和班级选项', passed, + passed ? '成功获取专业和班级选项' : '获取专业和班级选项失败', + response.data); + + return passed ? response.data.data : null; + } catch (error) { + recordTestResult('获取专业和班级选项', false, `异常: ${error.message}`, null); + return null; + } +} + +/** + * 测试获取学期选项 + */ +async function testGetSemesterOptions() { + try { + console.log('\n===== 测试获取学期选项 ====='); + const response = await api.get('/xljk/evaluation/options/semester'); + const passed = response.data.code === 200 && + Array.isArray(response.data.data) && + response.data.data.length > 0; + + recordTestResult('获取学期选项', passed, + passed ? '成功获取学期选项' : '获取学期选项失败', + response.data); + + return passed ? response.data.data : null; + } catch (error) { + recordTestResult('获取学期选项', false, `异常: ${error.message}`, null); + return null; + } +} + +/** + * 测试创建测评 + */ +async function testCreateEvaluation(options) { + try { + console.log('\n===== 测试创建测评 ====='); + if (!options || !options.majors || !options.classes || !options.semesters) { + recordTestResult('创建测评', false, '缺少必要的选项数据', null); + return null; + } + + // 选择第一个专业和班级 + const major = options.majors[0]; + const clazz = options.classes.find(c => c.majorId === major.id) || options.classes[0]; + const semester = options.semesters[0]; + + const evaluationData = { + evaluationName: `${semester}${clazz.name}心理健康测评(测试)`, + majorId: major.id, + majorName: major.name, + classId: clazz.id, + className: clazz.name, + semester: semester, + remark: '自动化测试创建' + }; + + const response = await api.post('/xljk/evaluation', evaluationData); + const passed = response.data.code === 200 && response.data.data; + + if (passed) { + evaluationId = response.data.data; + } + + recordTestResult('创建测评', passed, + passed ? `成功创建测评,ID: ${evaluationId}` : '创建测评失败', + response.data); + + return passed ? { + id: evaluationId, + majorId: major.id, + classId: clazz.id + } : null; + } catch (error) { + recordTestResult('创建测评', false, `异常: ${error.message}`, null); + return null; + } +} + +/** + * 测试获取学生信息 + */ +async function testGetStudents(classId) { + try { + console.log('\n===== 测试获取学生信息 ====='); + if (!classId) { + recordTestResult('获取学生信息', false, '缺少班级ID', null); + return null; + } + + const response = await api.get(`/xljk/evaluation/detail/students/${classId}`); + const passed = response.data.code === 200 && + Array.isArray(response.data.data) && + response.data.data.length > 0; + + recordTestResult('获取学生信息', passed, + passed ? `成功获取班级(${classId})学生信息,共${response.data.data.length}条` : '获取学生信息失败', + response.data); + + return passed ? response.data.data : null; + } catch (error) { + recordTestResult('获取学生信息', false, `异常: ${error.message}`, null); + return null; + } +} + +/** + * 测试批量添加学生 + */ +async function testBatchAddStudents(evaluationId, students) { + try { + console.log('\n===== 测试批量添加学生 ====='); + if (!evaluationId || !students || !Array.isArray(students) || students.length === 0) { + recordTestResult('批量添加学生', false, '缺少测评ID或学生数据', null); + return false; + } + + // 构造学生数据 + const studentData = students.map(student => ({ + evaluationId: evaluationId, + studentId: student.id, + studentNo: student.studentNo, + studentName: student.studentName, + gender: student.gender, + birthDate: student.birthDate, + phone: student.phone + })); + + const response = await api.post('/xljk/evaluation/detail/batch', studentData); + const passed = response.data.code === 200; + + recordTestResult('批量添加学生', passed, + passed ? `成功批量添加${studentData.length}个学生` : '批量添加学生失败', + response.data); + + return passed; + } catch (error) { + recordTestResult('批量添加学生', false, `异常: ${error.message}`, null); + return false; + } +} + +/** + * 测试查询测评详情 + */ +async function testGetEvaluationDetail(evaluationId) { + try { + console.log('\n===== 测试查询测评详情 ====='); + if (!evaluationId) { + recordTestResult('查询测评详情', false, '缺少测评ID', null); + return null; + } + + const response = await api.get(`/xljk/evaluation/${evaluationId}`); + const passed = response.data.code === 200 && + response.data.data && + response.data.data.id === evaluationId; + + recordTestResult('查询测评详情', passed, + passed ? `成功查询测评详情,名称: ${response.data.data.evaluationName}` : '查询测评详情失败', + response.data); + + return passed ? response.data.data : null; + } catch (error) { + recordTestResult('查询测评详情', false, `异常: ${error.message}`, null); + return null; + } +} + +/** + * 测试查询测评明细列表 + */ +async function testGetEvaluationDetailList(evaluationId) { + try { + console.log('\n===== 测试查询测评明细列表 ====='); + if (!evaluationId) { + recordTestResult('查询测评明细列表', false, '缺少测评ID', null); + return null; + } + + const response = await api.get(`/xljk/evaluation/detail/evaluation/${evaluationId}`); + const passed = response.data.code === 200 && + Array.isArray(response.data.data); + + if (passed && response.data.data.length > 0) { + detailIds = response.data.data.map(item => item.id); + } + + recordTestResult('查询测评明细列表', passed, + passed ? `成功查询测评明细列表,共${response.data.data.length}条` : '查询测评明细列表失败', + response.data); + + return passed ? response.data.data : null; + } catch (error) { + recordTestResult('查询测评明细列表', false, `异常: ${error.message}`, null); + return null; + } +} + +/** + * 测试批量更新学生心理状态 + */ +async function testBatchUpdateMentalStatus(details) { + try { + console.log('\n===== 测试批量更新学生心理状态 ====='); + if (!details || !Array.isArray(details) || details.length === 0) { + recordTestResult('批量更新学生心理状态', false, '缺少测评明细数据', null); + return false; + } + + // 构造更新数据,随机分配心理状态 + const updateData = details.map((detail, index) => { + const status = (index % 3 + 1).toString(); + return { + id: detail.id, + mentalStatus: status, + score: status === '3' ? Math.floor(Math.random() * 30) + 70 : null, + remark: status === '3' ? '需要重点关注' : null + }; + }); + + const response = await api.put('/xljk/evaluation/detail/batch/mentalStatus', updateData); + const passed = response.data.code === 200; + + recordTestResult('批量更新学生心理状态', passed, + passed ? `成功批量更新${updateData.length}个学生心理状态` : '批量更新学生心理状态失败', + response.data); + + return passed; + } catch (error) { + recordTestResult('批量更新学生心理状态', false, `异常: ${error.message}`, null); + return false; + } +} + +/** + * 测试发布测评 + */ +async function testPublishEvaluation(evaluationId) { + try { + console.log('\n===== 测试发布测评 ====='); + if (!evaluationId) { + recordTestResult('发布测评', false, '缺少测评ID', null); + return false; + } + + const response = await api.put(`/xljk/evaluation/${evaluationId}/publish`); + const passed = response.data.code === 200; + + recordTestResult('发布测评', passed, + passed ? '成功发布测评' : '发布测评失败', + response.data); + + return passed; + } catch (error) { + recordTestResult('发布测评', false, `异常: ${error.message}`, null); + return false; + } +} + +/** + * 测试完成测评 + */ +async function testCompleteEvaluation(evaluationId) { + try { + console.log('\n===== 测试完成测评 ====='); + if (!evaluationId) { + recordTestResult('完成测评', false, '缺少测评ID', null); + return false; + } + + const response = await api.put(`/xljk/evaluation/${evaluationId}/complete`); + const passed = response.data.code === 200; + + recordTestResult('完成测评', passed, + passed ? '成功完成测评' : '完成测评失败', + response.data); + + return passed; + } catch (error) { + recordTestResult('完成测评', false, `异常: ${error.message}`, null); + return false; + } +} + +/** + * 测试获取测评统计数据 + */ +async function testGetEvaluationStatistics(evaluationId) { + try { + console.log('\n===== 测试获取测评统计数据 ====='); + if (!evaluationId) { + recordTestResult('获取测评统计数据', false, '缺少测评ID', null); + return null; + } + + const response = await api.get(`/xljk/evaluation/${evaluationId}/statistics`); + const passed = response.data.code === 200 && + response.data.data && + response.data.data.totalCount > 0; + + recordTestResult('获取测评统计数据', passed, + passed ? `成功获取测评统计数据,总人数: ${response.data.data.totalCount}` : '获取测评统计数据失败', + response.data); + + return passed ? response.data.data : null; + } catch (error) { + recordTestResult('获取测评统计数据', false, `异常: ${error.message}`, null); + return null; + } +} + +/** + * 测试获取重点关注学生列表 + */ +async function testGetFocusStudents() { + try { + console.log('\n===== 测试获取重点关注学生列表 ====='); + + const response = await api.get('/xljk/evaluation/detail/focus'); + const passed = response.data.code === 200; + + recordTestResult('获取重点关注学生列表', passed, + passed ? `成功获取重点关注学生列表,共${response.data.data.total}条` : '获取重点关注学生列表失败', + response.data); + + return passed ? response.data.data : null; + } catch (error) { + recordTestResult('获取重点关注学生列表', false, `异常: ${error.message}`, null); + return null; + } +} + +/** + * 测试获取重点关注学生统计 + */ +async function testGetFocusStudentsStatistics() { + try { + console.log('\n===== 测试获取重点关注学生统计 ====='); + + const response = await api.get('/xljk/evaluation/statistics/focus'); + const passed = response.data.code === 200 && + response.data.data; + + recordTestResult('获取重点关注学生统计', passed, + passed ? `成功获取重点关注学生统计,总关注率: ${response.data.data.totalFocusRate}%` : '获取重点关注学生统计失败', + response.data); + + return passed ? response.data.data : null; + } catch (error) { + recordTestResult('获取重点关注学生统计', false, `异常: ${error.message}`, null); + return null; + } +} + +/** + * 测试删除测评 + */ +async function testDeleteEvaluation(evaluationId) { + try { + console.log('\n===== 测试删除测评 ====='); + if (!evaluationId) { + recordTestResult('删除测评', false, '缺少测评ID', null); + return false; + } + + const response = await api.delete(`/xljk/evaluation/${evaluationId}`); + // 注意:由于测评已完成,删除应该会失败,这是符合预期的 + const expectedFail = response.data.code !== 200; + + recordTestResult('删除测评', expectedFail, + expectedFail ? '测评已完成,无法删除,符合预期' : '错误地成功删除了已完成的测评', + response.data); + + return expectedFail; + } catch (error) { + // 如果是因为业务规则导致的错误(如已完成的测评不能删除),也算测试通过 + const isBusinessError = error.response && error.response.data && error.response.data.code !== 200; + recordTestResult('删除测评', isBusinessError, + isBusinessError ? '测评已完成,无法删除,符合预期' : `异常: ${error.message}`, + error.response ? error.response.data : null); + return isBusinessError; + } +} + +/** + * 输出测试报告 + */ +function printTestReport() { + console.log('\n===== 测试报告 ====='); + console.log(`总测试数: ${testResults.total}`); + console.log(`通过数: ${testResults.passed}`); + console.log(`失败数: ${testResults.failed}`); + console.log(`跳过数: ${testResults.skipped}`); + console.log(`通过率: ${Math.round(testResults.passed / testResults.total * 100)}%`); + + // 将测试结果写入文件 + const reportFile = `test_report_${new Date().toISOString().replace(/[:.]/g, '-')}.json`; + fs.writeFileSync(reportFile, JSON.stringify(testResults, null, 2)); + console.log(`测试报告已保存到: ${reportFile}`); +} + +/** + * 主测试流程 + */ +async function runTests() { + console.log('===== 心理健康测评API测试开始 ====='); + + // 登录获取token + const loginSuccess = await login(); + if (!loginSuccess) { + console.error('登录失败,无法继续测试'); + return; + } + + // 获取选项数据 + const majorAndClassOptions = await testGetMajorAndClassOptions(); + const semesterOptions = await testGetSemesterOptions(); + + if (!majorAndClassOptions || !semesterOptions) { + console.error('获取基础数据失败,无法继续测试'); + return; + } + + const options = { + majors: majorAndClassOptions.majors, + classes: majorAndClassOptions.classes, + semesters: semesterOptions + }; + + // 创建测评 + const evaluationInfo = await testCreateEvaluation(options); + if (!evaluationInfo) { + console.error('创建测评失败,无法继续测试'); + return; + } + + // 获取学生信息 + const students = await testGetStudents(evaluationInfo.classId); + if (!students) { + console.error('获取学生信息失败,无法继续测试'); + return; + } + + // 批量添加学生 + const addSuccess = await testBatchAddStudents(evaluationInfo.id, students); + if (!addSuccess) { + console.error('批量添加学生失败,无法继续测试'); + return; + } + + // 查询测评详情 + await testGetEvaluationDetail(evaluationInfo.id); + + // 查询测评明细列表 + const details = await testGetEvaluationDetailList(evaluationInfo.id); + if (!details) { + console.error('查询测评明细列表失败,无法继续测试'); + return; + } + + // 批量更新学生心理状态 + const updateSuccess = await testBatchUpdateMentalStatus(details); + if (!updateSuccess) { + console.error('批量更新学生心理状态失败,无法继续测试'); + return; + } + + // 发布测评 + const publishSuccess = await testPublishEvaluation(evaluationInfo.id); + if (!publishSuccess) { + console.error('发布测评失败,无法继续测试'); + return; + } + + // 完成测评 + const completeSuccess = await testCompleteEvaluation(evaluationInfo.id); + if (!completeSuccess) { + console.error('完成测评失败,无法继续测试'); + return; + } + + // 获取测评统计数据 + await testGetEvaluationStatistics(evaluationInfo.id); + + // 获取重点关注学生列表 + await testGetFocusStudents(); + + // 获取重点关注学生统计 + await testGetFocusStudentsStatistics(); + + // 测试删除测评(应该失败,因为已完成) + await testDeleteEvaluation(evaluationInfo.id); + + // 输出测试报告 + printTestReport(); + + console.log('===== 心理健康测评API测试结束 ====='); +} + +// 运行测试 +runTests().catch(error => { + console.error('测试过程中发生异常:', error); + printTestReport(); +}); diff --git a/web/src/api/xljk/evaluation/index.ts b/web/src/api/xljk/evaluation/index.ts new file mode 100644 index 00000000..b3f8bd20 --- /dev/null +++ b/web/src/api/xljk/evaluation/index.ts @@ -0,0 +1,191 @@ +import request from '@/utils/request'; +import { + XljkEvaluationVO, + XljkEvaluationForm, + XljkEvaluationQuery, + XljkEvaluationDetailVO, + XljkEvaluationDetailForm, + XljkEvaluationDetailQuery, + CollegeOption, + MajorOption, + ClassOption, + StudentInfo +} from './types'; + +// 查询心理健康测评列表 +export const listEvaluation = (query: XljkEvaluationQuery) => { + return request({ + url: '/xljk/evaluation/list', + method: 'get', + params: query + }); +}; + +// 查询心理健康测评详细信息 +export const getEvaluation = (id: string | number) => { + return request({ + url: `/xljk/evaluation/${id}`, + method: 'get' + }); +}; + +// 新增心理健康测评 +export const addEvaluation = (data: XljkEvaluationForm) => { + // 确保必填字段都有值,避免数据库插入错误 + if (data.departmentName && !data.departmentId) { + data.departmentId = 0; // 使用临时ID,后端会根据名称处理 + } + + if (data.majorName && !data.majorId) { + data.majorId = 0; // 使用临时ID,后端会根据名称处理 + } + + if (data.className && !data.classId) { + data.classId = 0; // 使用临时ID,后端会根据名称处理 + } + + return request({ + url: '/xljk/evaluation', + method: 'post', + data: data + }); +}; + +// 修改心理健康测评 +export const updateEvaluation = (data: XljkEvaluationForm) => { + return request({ + url: '/xljk/evaluation', + method: 'put', + data: data + }); +}; + +// 删除心理健康测评 +export const delEvaluation = (ids: string | number | Array) => { + return request({ + url: `/xljk/evaluation/${typeof ids === 'object' ? ids.join(',') : ids}`, + method: 'delete' + }); +}; + +// 获取院系选项 +export const getDepartmentOptions = () => { + return request({ + url: '/xljk/evaluation/options/department', + method: 'get' + }); +}; + +// 获取院系选项(新接口) +export const getCollegeOptions = () => { + return request({ + url: '/xljk/evaluation/options/colleges', + method: 'get' + }); +}; + +// 获取专业选项 +export const getMajorOptions = (collegeName?: string) => { + return request({ + url: '/xljk/evaluation/options/majors', + method: 'get', + params: { collegeName } + }); +}; + +// 获取班级选项 +export const getClassOptions = (collegeName?: string, majorName?: string) => { + return request({ + url: '/xljk/evaluation/options/classes', + method: 'get', + params: { collegeName, majorName } + }); +}; + +// 获取班级学生列表 +export const getStudentsByClass = (collegeName?: string, majorName?: string, className?: string) => { + return request({ + url: '/xljk/evaluation/students', + method: 'get', + params: { collegeName, majorName, className } + }); +}; + +// 获取学期选项 +export const getSemesterOptions = () => { + return request({ + url: '/xljk/evaluation/options/semester', + method: 'get' + }); +}; + +// 发布测评 +export const publishEvaluation = (id: string | number) => { + return request({ + url: `/xljk/evaluation/${id}/publish`, + method: 'put' + }); +}; + +// 完成测评 +export const completeEvaluation = (id: string | number) => { + return request({ + url: `/xljk/evaluation/${id}/complete`, + method: 'put' + }); +}; + +// 获取测评统计数据 +export const getEvaluationStatistics = (id: string | number) => { + return request({ + url: `/xljk/evaluation/${id}/statistics`, + method: 'get' + }); +}; + +// 获取重点关注学生统计 +export const getFocusStudentsStatistics = (query: XljkEvaluationQuery) => { + return request({ + url: '/xljk/evaluation/statistics/focus', + method: 'get', + params: query + }); +}; + +// 查询测评明细列表 +export const listEvaluationDetail = (query: XljkEvaluationDetailQuery) => { + return request({ + url: '/xljk/evaluation/detail/list', + method: 'get', + params: query + }); +}; + +// 获取测评明细列表 +export const getEvaluationDetailsByEvaluationId = (evaluationId: string | number) => { + return request({ + url: `/xljk/evaluation/detail/evaluation/${evaluationId}`, + method: 'get' + }); +}; + +// 批量新增测评明细 +export const batchAddEvaluationDetails = (data: XljkEvaluationDetailForm[]) => { + return request({ + url: '/xljk/evaluation/detail/batch', + method: 'post', + data: data + }); +}; + +// 批量更新学生心理状态 +export const batchUpdateMentalStatus = (data: XljkEvaluationDetailForm[]) => { + // 确保数据中的ID字段保持原有格式,不做Number转换 + console.log('批量更新数据 - 第一条记录evaluationId:', data[0]?.evaluationId); + + return request({ + url: '/xljk/evaluation/detail/batch/mentalStatus', + method: 'put', + data: data + }); +}; \ No newline at end of file diff --git a/web/src/api/xljk/evaluation/types.ts b/web/src/api/xljk/evaluation/types.ts new file mode 100644 index 00000000..a774229f --- /dev/null +++ b/web/src/api/xljk/evaluation/types.ts @@ -0,0 +1,513 @@ +export interface XljkEvaluationVO { + /** + * 主键ID + */ + id: string | number; + + /** + * 院系ID + */ + departmentId: number; + + /** + * 院系名称 + */ + departmentName: string; + + /** + * 测评名称 + */ + evaluationName: string; + + /** + * 专业ID + */ + majorId: number; + + /** + * 专业名称 + */ + majorName: string; + + /** + * 班级ID + */ + classId: number; + + /** + * 班级名称 + */ + className: string; + + /** + * 学期 + */ + semester: string; + + /** + * 状态(0-草稿,1-已发布,2-已完成) + */ + status: string; + + /** + * 创建者ID(班主任ID) + */ + createBy: number; + + /** + * 创建者姓名 + */ + createName: string; + + /** + * 创建时间 + */ + createTime: string; + + /** + * 更新者 + */ + updateBy: number; + + /** + * 更新时间 + */ + updateTime: string; + + /** + * 备注 + */ + remark: string; + + /** + * 学生总数 + */ + studentCount?: number; + + /** + * 重点关注学生数 + */ + focusCount?: number; +} + +export interface XljkEvaluationForm extends BaseEntity { + /** + * 主键ID + */ + id?: string | number; + + /** + * 院系ID + */ + departmentId?: number; + + /** + * 院系名称 + */ + departmentName?: string; + + /** + * 测评名称 + */ + evaluationName?: string; + + /** + * 专业ID + */ + majorId?: number; + + /** + * 专业名称 + */ + majorName?: string; + + /** + * 班级ID + */ + classId?: number; + + /** + * 班级名称 + */ + className?: string; + + /** + * 学期 + */ + semester?: string; + + /** + * 状态(0-草稿,1-已发布,2-已完成) + */ + status?: string; + + /** + * 创建者姓名 + */ + createName?: string; + + /** + * 备注 + */ + remark?: string; +} + +export interface XljkEvaluationQuery extends PageQuery { + /** + * 院系ID + */ + departmentId?: number; + + /** + * 院系名称 + */ + departmentName?: string; + + /** + * 测评名称 + */ + evaluationName?: string; + + /** + * 专业ID + */ + majorId?: number; + + /** + * 专业名称 + */ + majorName?: string; + + /** + * 班级ID + */ + classId?: number; + + /** + * 班级名称 + */ + className?: string; + + /** + * 学期 + */ + semester?: string; + + /** + * 状态 + */ + status?: string; + + /** + * 日期范围参数 + */ + params?: any; +} + +export interface XljkEvaluationDetailVO { + /** + * 主键ID + */ + id: string | number; + + /** + * 测评表ID + */ + evaluationId: number; + + /** + * 测评名称 + */ + evaluationName?: string; + + /** + * 学生ID + */ + studentId: number; + + /** + * 学号 + */ + studentNo: string; + + /** + * 学生姓名 + */ + studentName: string; + + /** + * 性别(M-男,F-女) + */ + gender: string; + + /** + * 出生日期 + */ + birthDate: string; + + /** + * 联系电话 + */ + phone: string; + + /** + * 心理状态(1-健康,2-良好,3-重点关注) + */ + mentalStatus: string; + + /** + * 分数 + */ + score?: number; + + /** + * 创建者 + */ + createBy: number; + + /** + * 创建时间 + */ + createTime: string; + + /** + * 更新者 + */ + updateBy: number; + + /** + * 更新时间 + */ + updateTime: string; + + /** + * 备注 + */ + remark: string; + + /** + * 班级名称 + */ + className?: string; + + /** + * 专业名称 + */ + majorName?: string; + + /** + * 学期 + */ + semester?: string; +} + +export interface XljkEvaluationDetailForm extends BaseEntity { + /** + * 主键ID + */ + id?: string | number; + + /** + * 测评表ID + */ + evaluationId?: string | number; // 支持字符串类型的ID + + /** + * 学生ID + */ + studentId?: number; + + /** + * 学号 + */ + studentNo?: string; + + /** + * 学生姓名 + */ + studentName?: string; + + /** + * 性别(M-男,F-女) + */ + gender?: string; + + /** + * 出生日期 + */ + birthDate?: string; + + /** + * 联系电话 + */ + phone?: string; + + /** + * 心理状态(1-健康,2-良好,3-重点关注) + */ + mentalStatus?: string; + + /** + * 分数 + */ + score?: number; + + /** + * 备注 + */ + remark?: string; +} + +export interface XljkEvaluationDetailQuery extends PageQuery { + /** + * 测评表ID + */ + evaluationId?: number; + + /** + * 学生ID + */ + studentId?: number; + + /** + * 学号 + */ + studentNo?: string; + + /** + * 学生姓名 + */ + studentName?: string; + + /** + * 心理状态 + */ + mentalStatus?: string; + + /** + * 日期范围参数 + */ + params?: any; +} + +export interface StudentInfo { + /** + * 学生ID + */ + studentId: number; + + /** + * 学号 + */ + studentNo: string; + + /** + * 学生姓名 + */ + studentName: string; + + /** + * 性别(M-男,F-女) + */ + gender: string; + + /** + * 出生日期 + */ + birthDate: string; + + /** + * 联系电话 + */ + phone: string; + + /** + * 心理状态(1-健康,2-良好,3-重点关注) + */ + mentalStatus?: string; + + /** + * 分数,当心理状态为"重点关注"时需要填写 + */ + score?: number; + + /** + * 测评明细ID,已有测评数据时存在 + */ + detailId?: number; + + /** + * 备注 + */ + remark?: string; +} + +export interface CollegeOption { + /** + * 院系名称 + */ + name: string; +} + +export interface MajorOption { + /** + * 专业名称 + */ + name: string; +} + +export interface ClassOption { + /** + * 班级名称 + */ + name: string; +} + +export interface SemesterOption { + /** + * 学期值 + */ + value: string; + + /** + * 学期名称 + */ + label: string; +} + +export interface EvaluationStatistics { + /** + * 学生总数 + */ + totalStudents: number; + + /** + * 健康学生数 + */ + healthyCount: number; + + /** + * 良好学生数 + */ + goodCount: number; + + /** + * 重点关注学生数 + */ + focusCount: number; + + /** + * 健康学生百分比 + */ + healthyPercent: number; + + /** + * 良好学生百分比 + */ + goodPercent: number; + + /** + * 重点关注学生百分比 + */ + focusPercent: number; +} \ No newline at end of file diff --git a/web/src/router/index.ts b/web/src/router/index.ts index 43c5c7c5..68da6687 100644 --- a/web/src/router/index.ts +++ b/web/src/router/index.ts @@ -89,10 +89,56 @@ export const constantRoutes: RouteRecordRaw[] = [ } ] }, + { + path: '/xljk', + component: Layout, + hidden: true, + children: [ + { + path: 'evaluation/detail/:id', + component: () => import('@/views/xljk/evaluation/detail.vue'), + name: 'XljkEvaluationDetail', + meta: { title: '心理健康测评详情', icon: 'form', activeMenu: '/xljk/evaluation' } + }, + { + path: 'evaluation/add', + component: () => import('@/views/xljk/evaluation/add.vue'), + name: 'XljkEvaluationAdd', + meta: { title: '新增心理健康测评', icon: 'form', activeMenu: '/xljk/evaluation' } + }, + { + path: 'evaluation/edit/:id', + component: () => import('@/views/xljk/evaluation/edit.vue'), + name: 'XljkEvaluationEdit', + meta: { title: '编辑心理健康测评', icon: 'form', activeMenu: '/xljk/evaluation' } + }, + { + path: 'evaluation/fill/:id', + component: () => import('@/views/xljk/evaluation/fill.vue'), + name: 'XljkEvaluationFill', + meta: { title: '填写心理健康测评', icon: 'form', activeMenu: '/xljk/evaluation' } + } + ] + } ]; // 动态路由,基于用户权限动态去加载 -export const dynamicRoutes: RouteRecordRaw[] = []; +export const dynamicRoutes: RouteRecordRaw[] = [ + { + path: '/xljk', + component: Layout, + name: 'Xljk', + meta: { title: '学工管理', icon: 'education' }, + children: [ + { + path: 'evaluation', + component: () => import('@/views/xljk/evaluation/index.vue'), + name: 'XljkEvaluation', + meta: { title: '心理健康测评', icon: 'heart', permissions: ['xljk:evaluation:list'] } + } + ] + } +]; /** * 创建路由 diff --git a/web/src/views/xljk/evaluation/add.vue b/web/src/views/xljk/evaluation/add.vue new file mode 100644 index 00000000..8714b66f --- /dev/null +++ b/web/src/views/xljk/evaluation/add.vue @@ -0,0 +1,457 @@ + + + + + \ No newline at end of file diff --git a/web/src/views/xljk/evaluation/detail.vue b/web/src/views/xljk/evaluation/detail.vue new file mode 100644 index 00000000..57f05479 --- /dev/null +++ b/web/src/views/xljk/evaluation/detail.vue @@ -0,0 +1,446 @@ + + + + + \ No newline at end of file diff --git a/web/src/views/xljk/evaluation/edit.vue b/web/src/views/xljk/evaluation/edit.vue new file mode 100644 index 00000000..46b9824b --- /dev/null +++ b/web/src/views/xljk/evaluation/edit.vue @@ -0,0 +1,373 @@ + + + + + \ No newline at end of file diff --git a/web/src/views/xljk/evaluation/fill.vue b/web/src/views/xljk/evaluation/fill.vue new file mode 100644 index 00000000..13f437b7 --- /dev/null +++ b/web/src/views/xljk/evaluation/fill.vue @@ -0,0 +1,343 @@ + + + + + \ No newline at end of file diff --git a/web/src/views/xljk/evaluation/index.vue b/web/src/views/xljk/evaluation/index.vue new file mode 100644 index 00000000..30df649a --- /dev/null +++ b/web/src/views/xljk/evaluation/index.vue @@ -0,0 +1,499 @@ + + + + + \ No newline at end of file diff --git a/工程本地启动指导.md b/工程本地启动指导.md index f1d095d9..31c220f4 100644 --- a/工程本地启动指导.md +++ b/工程本地启动指导.md @@ -232,7 +232,7 @@ cd backend #### 3. 启动主应用服务 ```bash -./hot-start.sh +./start-main.sh ``` **等待提示**: 看到 "主应用启动成功" 或访问 `http://localhost:8080` 正常返回