提交代码

This commit is contained in:
zlwu committed 2025-09-07 20:32:52 +08:00
1 parent edaf8dbacf
commit 9c3741562d
13 files changed
+1574 -9

No files matched your search

+2 -1
View File
@@ -326,4 +326,5 @@ docs/变更管理/
查找界面中涉及到的权限字符.md
docs/部署文档/nginx配置/hzdyjsweb.camasort.com.conf
首页完善的提示词.md
scripts/
scripts/
学生宿舍卫生检查、学生违纪记录统计.md
@@ -0,0 +1,82 @@
package org.dromara.xg.controller;
import java.util.List;
import lombok.RequiredArgsConstructor;
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.log.annotation.Log;
import org.dromara.common.web.core.BaseController;
import org.dromara.common.core.domain.R;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.xg.domain.bo.XgStudentStatisticsBo;
import org.dromara.xg.domain.vo.XgStudentStatisticsVo;
import org.dromara.xg.domain.vo.XgCascadeOptionVo;
import org.dromara.xg.service.IXgStudentStatisticsService;
/**
* 学生宿舍卫生检查、违纪记录统计
*
* @author zlwu
* @date 2025-01-14
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/xg/studentStatistics")
public class XgStudentStatisticsController extends BaseController {
private final IXgStudentStatisticsService studentStatisticsService;
/**
* 查询学生宿舍卫生检查、违纪记录统计数据
*/
@SaCheckPermission("xg:studentStatistics:query")
@PostMapping("/statistics")
public R<XgStudentStatisticsVo> getStatistics(@Validated @RequestBody XgStudentStatisticsBo bo) {
return R.ok(studentStatisticsService.getStatistics(bo));
}
/**
* 导出学生宿舍卫生检查、违纪记录统计数据
*/
@SaCheckPermission("xg:studentStatistics:export")
@Log(title = "学生统计数据", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void exportStatistics(@Validated @RequestBody XgStudentStatisticsBo bo,
jakarta.servlet.http.HttpServletResponse response) {
studentStatisticsService.exportStatistics(bo, response);
}
/**
* 获取二级学院列表
*/
@SaCheckPermission("xg:studentStatistics:query")
@GetMapping("/colleges")
public R<List<XgCascadeOptionVo>> getColleges() {
return R.ok(studentStatisticsService.getColleges());
}
/**
* 根据学院ID获取专业列表
*/
@SaCheckPermission("xg:studentStatistics:query")
@GetMapping("/majors/{collegeId}")
public R<List<XgCascadeOptionVo>> getMajorsByCollegeId(
@NotNull(message = "学院ID不能为空") @PathVariable Long collegeId) {
return R.ok(studentStatisticsService.getMajorsByCollegeId(collegeId));
}
/**
* 根据专业ID获取班级列表
*/
@SaCheckPermission("xg:studentStatistics:query")
@GetMapping("/classes/{majorId}")
public R<List<XgCascadeOptionVo>> getClassesByMajorId(
@NotNull(message = "专业ID不能为空") @PathVariable Long majorId) {
return R.ok(studentStatisticsService.getClassesByMajorId(majorId));
}
}
@@ -0,0 +1,48 @@
package org.dromara.xg.domain.bo;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import jakarta.validation.constraints.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.time.LocalDateTime;
/**
* 学生宿舍卫生检查、违纪记录统计查询业务对象
*
* @author zlwu
* @date 2025-01-14
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class XgStudentStatisticsBo extends BaseEntity {
/**
* 统计开始时间
*/
@NotNull(message = "统计开始时间不能为空")
private LocalDateTime startTime;
/**
* 统计结束时间
*/
@NotNull(message = "统计结束时间不能为空")
private LocalDateTime endTime;
/**
* 二级学院ID
*/
private Long collegeId;
/**
* 专业ID
*/
private Long majorId;
/**
* 班级ID
*/
private Long classId;
}
@@ -0,0 +1,34 @@
package org.dromara.xg.domain.vo;
import lombok.Data;
/**
* 级联选择器选项视图对象
*
* @author zlwu
* @date 2025-01-14
*/
@Data
public class XgCascadeOptionVo {
/**
* ID
*/
private Long id;
/**
* 显示名称
*/
private String label;
/**
* 值
*/
private String value;
/**
* 排序
*/
private Integer sort;
}
@@ -0,0 +1,117 @@
package org.dromara.xg.domain.vo;
import lombok.Data;
import java.util.List;
/**
* 学生宿舍卫生检查、违纪记录统计视图对象
*
* @author zlwu
* @date 2025-01-14
*/
@Data
public class XgStudentStatisticsVo {
/**
* 统计维度 (college-学院, major-专业, class-班级, classDetail-班级详情)
*/
private String dimension;
/**
* 统计图表数据
*/
private List<StatisticsChartData> chartData;
/**
* 明细数据
*/
private List<StatisticsDetailData> detailData;
/**
* 图表数据内部类
*/
@Data
public static class StatisticsChartData {
/**
* 名称 (学院名、专业名、班级名)
*/
private String name;
/**
* 宿舍扣分总数
*/
private Integer dormDeductionCount;
/**
* 宿舍违纪记录总数
*/
private Integer dormViolationCount;
/**
* 宿舍违纪记录扣分总数
*/
private Double dormViolationDeduction;
/**
* 教学区违纪记录总数
*/
private Integer teachingViolationCount;
/**
* 教学区违纪记录扣分总数
*/
private Double teachingViolationDeduction;
}
/**
* 明细数据内部类
*/
@Data
public static class StatisticsDetailData {
/**
* ID
*/
private Long id;
/**
* 名称
*/
private String name;
/**
* 上级名称(如学院下的专业名称显示学院名)
*/
private String parentName;
/**
* 宿舍扣分总数
*/
private Integer dormDeductionCount;
/**
* 宿舍违纪记录总数
*/
private Integer dormViolationCount;
/**
* 宿舍违纪记录扣分总数
*/
private Double dormViolationDeduction;
/**
* 教学区违纪记录总数
*/
private Integer teachingViolationCount;
/**
* 教学区违纪记录扣分总数
*/
private Double teachingViolationDeduction;
/**
* 合计扣分
*/
private Double totalDeduction;
}
}
@@ -0,0 +1,63 @@
package org.dromara.xg.mapper;
import org.apache.ibatis.annotations.Param;
import org.dromara.xg.domain.bo.XgStudentStatisticsBo;
import org.dromara.xg.domain.vo.XgStudentStatisticsVo;
import org.dromara.xg.domain.vo.XgCascadeOptionVo;
import java.util.List;
/**
* 学生宿舍卫生检查、违纪记录统计Mapper接口
*
* @author zlwu
* @date 2025-01-14
*/
public interface XgStudentStatisticsMapper {
/**
* 按学院维度统计图表数据
*/
List<XgStudentStatisticsVo.StatisticsChartData> getCollegeStatistics(@Param("bo") XgStudentStatisticsBo bo);
/**
* 按学院维度统计明细数据
*/
List<XgStudentStatisticsVo.StatisticsDetailData> getCollegeDetailStatistics(@Param("bo") XgStudentStatisticsBo bo);
/**
* 按专业维度统计图表数据
*/
List<XgStudentStatisticsVo.StatisticsChartData> getMajorStatistics(@Param("bo") XgStudentStatisticsBo bo);
/**
* 按专业维度统计明细数据
*/
List<XgStudentStatisticsVo.StatisticsDetailData> getMajorDetailStatistics(@Param("bo") XgStudentStatisticsBo bo);
/**
* 按班级维度统计图表数据
*/
List<XgStudentStatisticsVo.StatisticsChartData> getClassStatistics(@Param("bo") XgStudentStatisticsBo bo);
/**
* 按班级维度统计明细数据
*/
List<XgStudentStatisticsVo.StatisticsDetailData> getClassDetailStatistics(@Param("bo") XgStudentStatisticsBo bo);
/**
* 获取二级学院列表
*/
List<XgCascadeOptionVo> getColleges();
/**
* 根据学院ID获取专业列表
*/
List<XgCascadeOptionVo> getMajorsByCollegeId(@Param("collegeId") Long collegeId);
/**
* 根据专业ID获取班级列表
*/
List<XgCascadeOptionVo> getClassesByMajorId(@Param("majorId") Long majorId);
}
@@ -0,0 +1,56 @@
package org.dromara.xg.service;
import java.util.List;
import jakarta.servlet.http.HttpServletResponse;
import org.dromara.xg.domain.bo.XgStudentStatisticsBo;
import org.dromara.xg.domain.vo.XgStudentStatisticsVo;
import org.dromara.xg.domain.vo.XgCascadeOptionVo;
/**
* 学生宿舍卫生检查、违纪记录统计Service接口
*
* @author zlwu
* @date 2025-01-14
*/
public interface IXgStudentStatisticsService {
/**
* 获取统计数据
*
* @param bo 查询条件
* @return 统计结果
*/
XgStudentStatisticsVo getStatistics(XgStudentStatisticsBo bo);
/**
* 导出统计数据
*
* @param bo 查询条件
* @param response HTTP响应
*/
void exportStatistics(XgStudentStatisticsBo bo, HttpServletResponse response);
/**
* 获取二级学院列表
*
* @return 学院列表
*/
List<XgCascadeOptionVo> getColleges();
/**
* 根据学院ID获取专业列表
*
* @param collegeId 学院ID
* @return 专业列表
*/
List<XgCascadeOptionVo> getMajorsByCollegeId(Long collegeId);
/**
* 根据专业ID获取班级列表
*
* @param majorId 专业ID
* @return 班级列表
*/
List<XgCascadeOptionVo> getClassesByMajorId(Long majorId);
}
@@ -0,0 +1,117 @@
package org.dromara.xg.service.impl;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import jakarta.servlet.http.HttpServletResponse;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.xg.service.IXgStudentStatisticsService;
import org.dromara.xg.domain.bo.XgStudentStatisticsBo;
import org.dromara.xg.domain.vo.XgStudentStatisticsVo;
import org.dromara.xg.domain.vo.XgCascadeOptionVo;
import org.dromara.xg.mapper.XgStudentStatisticsMapper;
import java.util.List;
import java.util.Map;
/**
* 学生宿舍卫生检查、违纪记录统计Service业务层处理
*
* @author zlwu
* @date 2025-01-14
*/
@RequiredArgsConstructor
@Service
public class XgStudentStatisticsServiceImpl implements IXgStudentStatisticsService {
private final XgStudentStatisticsMapper statisticsMapper;
@Override
public XgStudentStatisticsVo getStatistics(XgStudentStatisticsBo bo) {
XgStudentStatisticsVo result = new XgStudentStatisticsVo();
// 确定统计维度
String dimension = determineDimension(bo);
result.setDimension(dimension);
// 获取图表数据和明细数据
switch (dimension) {
case "college":
result.setChartData(statisticsMapper.getCollegeStatistics(bo));
result.setDetailData(statisticsMapper.getCollegeDetailStatistics(bo));
break;
case "major":
result.setChartData(statisticsMapper.getMajorStatistics(bo));
result.setDetailData(statisticsMapper.getMajorDetailStatistics(bo));
break;
case "class":
result.setChartData(statisticsMapper.getClassStatistics(bo));
result.setDetailData(statisticsMapper.getClassDetailStatistics(bo));
break;
case "classDetail":
// 班级详情统计:图表数据和明细数据都只显示指定班级
List<XgStudentStatisticsVo.StatisticsDetailData> detailData = statisticsMapper
.getClassDetailStatistics(bo);
result.setDetailData(detailData);
// 将明细数据转换为图表数据格式
result.setChartData(convertDetailToChartData(detailData));
break;
}
return result;
}
@Override
public void exportStatistics(XgStudentStatisticsBo bo, HttpServletResponse response) {
XgStudentStatisticsVo statistics = getStatistics(bo);
ExcelUtil.exportExcel(statistics.getDetailData(), "学生统计数据", XgStudentStatisticsVo.StatisticsDetailData.class,
response);
}
@Override
public List<XgCascadeOptionVo> getColleges() {
return statisticsMapper.getColleges();
}
@Override
public List<XgCascadeOptionVo> getMajorsByCollegeId(Long collegeId) {
return statisticsMapper.getMajorsByCollegeId(collegeId);
}
@Override
public List<XgCascadeOptionVo> getClassesByMajorId(Long majorId) {
return statisticsMapper.getClassesByMajorId(majorId);
}
/**
* 确定统计维度
*/
private String determineDimension(XgStudentStatisticsBo bo) {
if (bo.getClassId() != null) {
return "classDetail";
} else if (bo.getMajorId() != null) {
return "class";
} else if (bo.getCollegeId() != null) {
return "major";
} else {
return "college";
}
}
/**
* 将明细数据转换为图表数据格式
*/
private List<XgStudentStatisticsVo.StatisticsChartData> convertDetailToChartData(
List<XgStudentStatisticsVo.StatisticsDetailData> detailData) {
return detailData.stream().map(detail -> {
XgStudentStatisticsVo.StatisticsChartData chartData = new XgStudentStatisticsVo.StatisticsChartData();
chartData.setName(detail.getName());
chartData.setDormDeductionCount(detail.getDormDeductionCount());
chartData.setDormViolationCount(detail.getDormViolationCount());
chartData.setDormViolationDeduction(detail.getDormViolationDeduction());
chartData.setTeachingViolationCount(detail.getTeachingViolationCount());
chartData.setTeachingViolationDeduction(detail.getTeachingViolationDeduction());
return chartData;
}).collect(java.util.stream.Collectors.toList());
}
}
@@ -0,0 +1,504 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.xg.mapper.XgStudentStatisticsMapper">
<!-- 按学院维度统计图表数据 -->
<select id="getCollegeStatistics" resultType="org.dromara.xg.domain.vo.XgStudentStatisticsVo$StatisticsChartData">
SELECT
d.dept_name as name,
COALESCE(dorm_stats.dormDeductionCount, 0) as dormDeductionCount,
COALESCE(dorm_violation_stats.dormViolationCount, 0) as dormViolationCount,
COALESCE(dorm_violation_stats.dormViolationDeduction, 0) as dormViolationDeduction,
COALESCE(teaching_violation_stats.teachingViolationCount, 0) as teachingViolationCount,
COALESCE(teaching_violation_stats.teachingViolationDeduction, 0) as teachingViolationDeduction
FROM sys_dept d
LEFT JOIN (
-- 宿舍卫生检查扣分统计
SELECT
c.college_id,
COUNT(h.id) as dormDeductionCount
FROM xg_dorm_hygiene_check h
INNER JOIN xg_class_msg c ON h.room_id IN (
SELECT DISTINCT bs.room_id
FROM xg_dorm_bed_student bs
INNER JOIN xg_student_msg s ON bs.student_id = s.id
WHERE s.class_id = c.id AND s.deleted = 0
)
WHERE h.deleted = 0
AND h.check_date BETWEEN #{bo.startTime} AND #{bo.endTime}
AND h.total_score > 0
GROUP BY c.college_id
) dorm_stats ON d.dept_id = dorm_stats.college_id
LEFT JOIN (
-- 宿舍区违纪记录统计
SELECT
dr.college_id,
COUNT(dr.id) as dormViolationCount,
COALESCE(SUM(dr.score_deduction), 0) as dormViolationDeduction
FROM xskh_discipline_record dr
WHERE dr.deleted = 0
AND dr.violation_source = '1'
AND dr.status = '1'
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
GROUP BY dr.college_id
) dorm_violation_stats ON d.dept_id = dorm_violation_stats.college_id
LEFT JOIN (
-- 教学区违纪记录统计
SELECT
dr.college_id,
COUNT(dr.id) as teachingViolationCount,
COALESCE(SUM(dr.score_deduction), 0) as teachingViolationDeduction
FROM xskh_discipline_record dr
WHERE dr.deleted = 0
AND dr.violation_source = '2'
AND dr.status = '1'
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
GROUP BY dr.college_id
) teaching_violation_stats ON d.dept_id = teaching_violation_stats.college_id
WHERE d.parent_id = 101 AND d.del_flag = '0'
ORDER BY d.order_num ASC, d.dept_name ASC
</select>
<!-- 按学院维度统计明细数据 -->
<select id="getCollegeDetailStatistics" resultType="org.dromara.xg.domain.vo.XgStudentStatisticsVo$StatisticsDetailData">
SELECT
d.dept_id as id,
d.dept_name as name,
'' as parentName,
COALESCE(dorm_stats.dormDeductionCount, 0) as dormDeductionCount,
COALESCE(dorm_violation_stats.dormViolationCount, 0) as dormViolationCount,
COALESCE(dorm_violation_stats.dormViolationDeduction, 0) as dormViolationDeduction,
COALESCE(teaching_violation_stats.teachingViolationCount, 0) as teachingViolationCount,
COALESCE(teaching_violation_stats.teachingViolationDeduction, 0) as teachingViolationDeduction,
COALESCE(dorm_violation_stats.dormViolationDeduction, 0) + COALESCE(teaching_violation_stats.teachingViolationDeduction, 0) as totalDeduction
FROM sys_dept d
LEFT JOIN (
-- 宿舍卫生检查扣分统计
SELECT
c.college_id,
COUNT(h.id) as dormDeductionCount
FROM xg_dorm_hygiene_check h
INNER JOIN xg_class_msg c ON h.room_id IN (
SELECT DISTINCT bs.room_id
FROM xg_dorm_bed_student bs
INNER JOIN xg_student_msg s ON bs.student_id = s.id
WHERE s.class_id = c.id AND s.deleted = 0
)
WHERE h.deleted = 0
AND h.check_date BETWEEN #{bo.startTime} AND #{bo.endTime}
AND h.total_score > 0
GROUP BY c.college_id
) dorm_stats ON d.dept_id = dorm_stats.college_id
LEFT JOIN (
-- 宿舍区违纪记录统计
SELECT
dr.college_id,
COUNT(dr.id) as dormViolationCount,
COALESCE(SUM(dr.score_deduction), 0) as dormViolationDeduction
FROM xskh_discipline_record dr
WHERE dr.deleted = 0
AND dr.violation_source = '1'
AND dr.status = '1'
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
GROUP BY dr.college_id
) dorm_violation_stats ON d.dept_id = dorm_violation_stats.college_id
LEFT JOIN (
-- 教学区违纪记录统计
SELECT
dr.college_id,
COUNT(dr.id) as teachingViolationCount,
COALESCE(SUM(dr.score_deduction), 0) as teachingViolationDeduction
FROM xskh_discipline_record dr
WHERE dr.deleted = 0
AND dr.violation_source = '2'
AND dr.status = '1'
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
GROUP BY dr.college_id
) teaching_violation_stats ON d.dept_id = teaching_violation_stats.college_id
WHERE d.parent_id = 101 AND d.del_flag = '0'
ORDER BY d.order_num ASC, d.dept_name ASC
</select>
<!-- 按专业维度统计图表数据 -->
<select id="getMajorStatistics" resultType="org.dromara.xg.domain.vo.XgStudentStatisticsVo$StatisticsChartData">
SELECT
d.dept_name as name,
COALESCE(dorm_stats.dormDeductionCount, 0) as dormDeductionCount,
COALESCE(dorm_violation_stats.dormViolationCount, 0) as dormViolationCount,
COALESCE(dorm_violation_stats.dormViolationDeduction, 0) as dormViolationDeduction,
COALESCE(teaching_violation_stats.teachingViolationCount, 0) as teachingViolationCount,
COALESCE(teaching_violation_stats.teachingViolationDeduction, 0) as teachingViolationDeduction
FROM sys_dept d
LEFT JOIN (
-- 宿舍卫生检查扣分统计
SELECT
c.major_id,
COUNT(h.id) as dormDeductionCount
FROM xg_dorm_hygiene_check h
INNER JOIN xg_class_msg c ON h.room_id IN (
SELECT DISTINCT bs.room_id
FROM xg_dorm_bed_student bs
INNER JOIN xg_student_msg s ON bs.student_id = s.id
WHERE s.class_id = c.id AND s.deleted = 0
)
WHERE h.deleted = 0
AND h.check_date BETWEEN #{bo.startTime} AND #{bo.endTime}
AND h.total_score > 0
AND c.college_id = #{bo.collegeId}
GROUP BY c.major_id
) dorm_stats ON d.dept_id = dorm_stats.major_id
LEFT JOIN (
-- 宿舍区违纪记录统计
SELECT
dr.major_id,
COUNT(dr.id) as dormViolationCount,
COALESCE(SUM(dr.score_deduction), 0) as dormViolationDeduction
FROM xskh_discipline_record dr
WHERE dr.deleted = 0
AND dr.violation_source = '1'
AND dr.status = '1'
AND dr.college_id = #{bo.collegeId}
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
GROUP BY dr.major_id
) dorm_violation_stats ON d.dept_id = dorm_violation_stats.major_id
LEFT JOIN (
-- 教学区违纪记录统计
SELECT
dr.major_id,
COUNT(dr.id) as teachingViolationCount,
COALESCE(SUM(dr.score_deduction), 0) as teachingViolationDeduction
FROM xskh_discipline_record dr
WHERE dr.deleted = 0
AND dr.violation_source = '2'
AND dr.status = '1'
AND dr.college_id = #{bo.collegeId}
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
GROUP BY dr.major_id
) teaching_violation_stats ON d.dept_id = teaching_violation_stats.major_id
WHERE d.parent_id = #{bo.collegeId} AND d.dept_category LIKE 'zy-%' AND d.del_flag = '0'
ORDER BY d.order_num ASC, d.dept_name ASC
</select>
<!-- 按专业维度统计明细数据 -->
<select id="getMajorDetailStatistics" resultType="org.dromara.xg.domain.vo.XgStudentStatisticsVo$StatisticsDetailData">
SELECT
d.dept_id as id,
d.dept_name as name,
p.dept_name as parentName,
COALESCE(dorm_stats.dormDeductionCount, 0) as dormDeductionCount,
COALESCE(dorm_violation_stats.dormViolationCount, 0) as dormViolationCount,
COALESCE(dorm_violation_stats.dormViolationDeduction, 0) as dormViolationDeduction,
COALESCE(teaching_violation_stats.teachingViolationCount, 0) as teachingViolationCount,
COALESCE(teaching_violation_stats.teachingViolationDeduction, 0) as teachingViolationDeduction,
COALESCE(dorm_violation_stats.dormViolationDeduction, 0) + COALESCE(teaching_violation_stats.teachingViolationDeduction, 0) as totalDeduction
FROM sys_dept d
INNER JOIN sys_dept p ON d.parent_id = p.dept_id
LEFT JOIN (
-- 宿舍卫生检查扣分统计
SELECT
c.major_id,
COUNT(h.id) as dormDeductionCount
FROM xg_dorm_hygiene_check h
INNER JOIN xg_class_msg c ON h.room_id IN (
SELECT DISTINCT bs.room_id
FROM xg_dorm_bed_student bs
INNER JOIN xg_student_msg s ON bs.student_id = s.id
WHERE s.class_id = c.id AND s.deleted = 0
)
WHERE h.deleted = 0
AND h.check_date BETWEEN #{bo.startTime} AND #{bo.endTime}
AND h.total_score > 0
AND c.college_id = #{bo.collegeId}
GROUP BY c.major_id
) dorm_stats ON d.dept_id = dorm_stats.major_id
LEFT JOIN (
-- 宿舍区违纪记录统计
SELECT
dr.major_id,
COUNT(dr.id) as dormViolationCount,
COALESCE(SUM(dr.score_deduction), 0) as dormViolationDeduction
FROM xskh_discipline_record dr
WHERE dr.deleted = 0
AND dr.violation_source = '1'
AND dr.status = '1'
AND dr.college_id = #{bo.collegeId}
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
GROUP BY dr.major_id
) dorm_violation_stats ON d.dept_id = dorm_violation_stats.major_id
LEFT JOIN (
-- 教学区违纪记录统计
SELECT
dr.major_id,
COUNT(dr.id) as teachingViolationCount,
COALESCE(SUM(dr.score_deduction), 0) as teachingViolationDeduction
FROM xskh_discipline_record dr
WHERE dr.deleted = 0
AND dr.violation_source = '2'
AND dr.status = '1'
AND dr.college_id = #{bo.collegeId}
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
GROUP BY dr.major_id
) teaching_violation_stats ON d.dept_id = teaching_violation_stats.major_id
WHERE d.parent_id = #{bo.collegeId} AND d.dept_category LIKE 'zy-%' AND d.del_flag = '0'
ORDER BY d.order_num ASC, d.dept_name ASC
</select>
<!-- 按班级维度统计图表数据 -->
<select id="getClassStatistics" resultType="org.dromara.xg.domain.vo.XgStudentStatisticsVo$StatisticsChartData">
SELECT
c.class_name as name,
(SELECT COUNT(h.id)
FROM xg_dorm_hygiene_check h
WHERE h.deleted = 0
AND h.check_date BETWEEN #{bo.startTime} AND #{bo.endTime}
AND h.total_score > 0
AND h.room_id IN (
SELECT DISTINCT bs.room_id
FROM xg_dorm_bed_student bs
INNER JOIN xg_student_msg s ON bs.student_id = s.id
WHERE s.class_id = c.id AND s.deleted = 0
)
) as dormDeductionCount,
(SELECT COUNT(dr.id)
FROM xskh_discipline_record dr
WHERE dr.deleted = 0
AND dr.violation_source = '1'
AND dr.status = '1'
AND dr.class_id = c.id
AND dr.college_id = #{bo.collegeId}
AND dr.major_id = #{bo.majorId}
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
) as dormViolationCount,
(SELECT COALESCE(SUM(dr.score_deduction), 0)
FROM xskh_discipline_record dr
WHERE dr.deleted = 0
AND dr.violation_source = '1'
AND dr.status = '1'
AND dr.class_id = c.id
AND dr.college_id = #{bo.collegeId}
AND dr.major_id = #{bo.majorId}
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
) as dormViolationDeduction,
(SELECT COUNT(dr.id)
FROM xskh_discipline_record dr
WHERE dr.deleted = 0
AND dr.violation_source = '2'
AND dr.status = '1'
AND dr.class_id = c.id
AND dr.college_id = #{bo.collegeId}
AND dr.major_id = #{bo.majorId}
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
) as teachingViolationCount,
(SELECT COALESCE(SUM(dr.score_deduction), 0)
FROM xskh_discipline_record dr
WHERE dr.deleted = 0
AND dr.violation_source = '2'
AND dr.status = '1'
AND dr.class_id = c.id
AND dr.college_id = #{bo.collegeId}
AND dr.major_id = #{bo.majorId}
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
) as teachingViolationDeduction
FROM xg_class_msg c
WHERE c.college_id = #{bo.collegeId} AND c.major_id = #{bo.majorId} AND c.deleted = 0
ORDER BY c.class_name ASC
</select>
<!-- 按班级维度统计明细数据 -->
<select id="getClassDetailStatistics" resultType="org.dromara.xg.domain.vo.XgStudentStatisticsVo$StatisticsDetailData">
<choose>
<when test="bo.classId != null">
<!-- 班级详情统计 -->
SELECT
c.id as id,
c.class_name as name,
CONCAT(c.college_name, '-', c.major_name) as parentName,
(SELECT COUNT(h.id)
FROM xg_dorm_hygiene_check h
WHERE h.deleted = 0
AND h.check_date BETWEEN #{bo.startTime} AND #{bo.endTime}
AND h.total_score > 0
AND h.room_id IN (
SELECT DISTINCT bs.room_id
FROM xg_dorm_bed_student bs
INNER JOIN xg_student_msg s ON bs.student_id = s.id
WHERE s.class_id = c.id AND s.deleted = 0
)
) as dormDeductionCount,
(SELECT COUNT(dr.id)
FROM xskh_discipline_record dr
WHERE dr.deleted = 0
AND dr.violation_source = '1'
AND dr.status = '1'
AND dr.class_id = #{bo.classId}
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
) as dormViolationCount,
(SELECT COALESCE(SUM(dr.score_deduction), 0)
FROM xskh_discipline_record dr
WHERE dr.deleted = 0
AND dr.violation_source = '1'
AND dr.status = '1'
AND dr.class_id = #{bo.classId}
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
) as dormViolationDeduction,
(SELECT COUNT(dr.id)
FROM xskh_discipline_record dr
WHERE dr.deleted = 0
AND dr.violation_source = '2'
AND dr.status = '1'
AND dr.class_id = #{bo.classId}
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
) as teachingViolationCount,
(SELECT COALESCE(SUM(dr.score_deduction), 0)
FROM xskh_discipline_record dr
WHERE dr.deleted = 0
AND dr.violation_source = '2'
AND dr.status = '1'
AND dr.class_id = #{bo.classId}
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
) as teachingViolationDeduction,
((SELECT COALESCE(SUM(dr.score_deduction), 0)
FROM xskh_discipline_record dr
WHERE dr.deleted = 0
AND dr.violation_source = '1'
AND dr.status = '1'
AND dr.class_id = #{bo.classId}
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
) +
(SELECT COALESCE(SUM(dr.score_deduction), 0)
FROM xskh_discipline_record dr
WHERE dr.deleted = 0
AND dr.violation_source = '2'
AND dr.status = '1'
AND dr.class_id = #{bo.classId}
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
)) as totalDeduction
FROM xg_class_msg c
WHERE c.id = #{bo.classId} AND c.deleted = 0
</when>
<otherwise>
<!-- 班级列表统计 -->
SELECT
c.id as id,
c.class_name as name,
c.major_name as parentName,
(SELECT COUNT(h.id)
FROM xg_dorm_hygiene_check h
WHERE h.deleted = 0
AND h.check_date BETWEEN #{bo.startTime} AND #{bo.endTime}
AND h.total_score > 0
AND h.room_id IN (
SELECT DISTINCT bs.room_id
FROM xg_dorm_bed_student bs
INNER JOIN xg_student_msg s ON bs.student_id = s.id
WHERE s.class_id = c.id AND s.deleted = 0
)
) as dormDeductionCount,
(SELECT COUNT(dr.id)
FROM xskh_discipline_record dr
WHERE dr.deleted = 0
AND dr.violation_source = '1'
AND dr.status = '1'
AND dr.class_id = c.id
AND dr.college_id = #{bo.collegeId}
AND dr.major_id = #{bo.majorId}
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
) as dormViolationCount,
(SELECT COALESCE(SUM(dr.score_deduction), 0)
FROM xskh_discipline_record dr
WHERE dr.deleted = 0
AND dr.violation_source = '1'
AND dr.status = '1'
AND dr.class_id = c.id
AND dr.college_id = #{bo.collegeId}
AND dr.major_id = #{bo.majorId}
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
) as dormViolationDeduction,
(SELECT COUNT(dr.id)
FROM xskh_discipline_record dr
WHERE dr.deleted = 0
AND dr.violation_source = '2'
AND dr.status = '1'
AND dr.class_id = c.id
AND dr.college_id = #{bo.collegeId}
AND dr.major_id = #{bo.majorId}
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
) as teachingViolationCount,
(SELECT COALESCE(SUM(dr.score_deduction), 0)
FROM xskh_discipline_record dr
WHERE dr.deleted = 0
AND dr.violation_source = '2'
AND dr.status = '1'
AND dr.class_id = c.id
AND dr.college_id = #{bo.collegeId}
AND dr.major_id = #{bo.majorId}
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
) as teachingViolationDeduction,
((SELECT COALESCE(SUM(dr.score_deduction), 0)
FROM xskh_discipline_record dr
WHERE dr.deleted = 0
AND dr.violation_source = '1'
AND dr.status = '1'
AND dr.class_id = c.id
AND dr.college_id = #{bo.collegeId}
AND dr.major_id = #{bo.majorId}
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
) +
(SELECT COALESCE(SUM(dr.score_deduction), 0)
FROM xskh_discipline_record dr
WHERE dr.deleted = 0
AND dr.violation_source = '2'
AND dr.status = '1'
AND dr.class_id = c.id
AND dr.college_id = #{bo.collegeId}
AND dr.major_id = #{bo.majorId}
AND dr.discipline_date BETWEEN #{bo.startTime} AND #{bo.endTime}
)) as totalDeduction
FROM xg_class_msg c
WHERE c.college_id = #{bo.collegeId} AND c.major_id = #{bo.majorId} AND c.deleted = 0
ORDER BY c.class_name ASC
</otherwise>
</choose>
</select>
<!-- 获取二级学院列表 -->
<select id="getColleges" resultType="org.dromara.xg.domain.vo.XgCascadeOptionVo">
SELECT
dept_id as id,
dept_name as label,
CAST(dept_id AS CHAR) as value,
order_num as sort
FROM sys_dept
WHERE parent_id = 101 AND del_flag = '0'
ORDER BY order_num ASC, dept_name ASC
</select>
<!-- 根据学院ID获取专业列表 -->
<select id="getMajorsByCollegeId" resultType="org.dromara.xg.domain.vo.XgCascadeOptionVo">
SELECT
dept_id as id,
dept_name as label,
CAST(dept_id AS CHAR) as value,
order_num as sort
FROM sys_dept
WHERE parent_id = #{collegeId}
AND dept_category LIKE 'zy-%'
AND del_flag = '0'
ORDER BY order_num ASC, dept_name ASC
</select>
<!-- 根据专业ID获取班级列表 -->
<select id="getClassesByMajorId" resultType="org.dromara.xg.domain.vo.XgCascadeOptionVo">
SELECT
id,
class_name as label,
CAST(id AS CHAR) as value,
0 as sort
FROM xg_class_msg
WHERE major_id = #{majorId} AND deleted = 0
ORDER BY class_name ASC
</select>
</mapper>
+1 -1
View File
@@ -34,7 +34,7 @@
"await-to-js": "3.0.0",
"axios": "1.8.4",
"crypto-js": "4.2.0",
"echarts": "5.6.0",
"echarts": "^5.6.0",
"element-plus": "2.9.8",
"file-saver": "2.0.5",
"highlight.js": "11.9.0",
+86
View File
@@ -0,0 +1,86 @@
import request from '@/utils/request'
export interface StudentStatisticsBo {
startTime: string
endTime: string
collegeId?: number
majorId?: number
classId?: number
}
export interface StatisticsChartData {
name: string
dormDeductionCount: number
dormViolationCount: number
dormViolationDeduction: number
teachingViolationCount: number
teachingViolationDeduction: number
}
export interface StatisticsDetailData {
id: number
name: string
parentName: string
dormDeductionCount: number
dormViolationCount: number
dormViolationDeduction: number
teachingViolationCount: number
teachingViolationDeduction: number
totalDeduction: number
}
export interface StudentStatisticsVo {
dimension: string
chartData: StatisticsChartData[]
detailData: StatisticsDetailData[]
}
export interface CascadeOptionVo {
id: number
label: string
value: string
sort: number
}
// 获取统计数据
export function getStatistics(data: StudentStatisticsBo) {
return request({
url: '/xg/studentStatistics/statistics',
method: 'post',
data: data
})
}
// 导出统计数据
export function exportStatistics(data: StudentStatisticsBo) {
return request({
url: '/xg/studentStatistics/export',
method: 'post',
data: data,
responseType: 'blob'
})
}
// 获取二级学院列表
export function getColleges() {
return request({
url: '/xg/studentStatistics/colleges',
method: 'get'
})
}
// 根据学院ID获取专业列表
export function getMajorsByCollegeId(collegeId: number) {
return request({
url: `/xg/studentStatistics/majors/${collegeId}`,
method: 'get'
})
}
// 根据专业ID获取班级列表
export function getClassesByMajorId(majorId: number) {
return request({
url: `/xg/studentStatistics/classes/${majorId}`,
method: 'get'
})
}
@@ -0,0 +1,426 @@
<template>
<div class="p-2 page-container">
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" label-width="120px">
<el-row :gutter="20">
<el-col :span="6">
<el-form-item label="统计开始时间" prop="startTime" required>
<el-date-picker
v-model="queryParams.startTime"
type="datetime"
placeholder="选择开始时间"
value-format="YYYY-MM-DD HH:mm:ss"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="统计结束时间" prop="endTime" required>
<el-date-picker
v-model="queryParams.endTime"
type="datetime"
placeholder="选择结束时间"
value-format="YYYY-MM-DD HH:mm:ss"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="二级学院" prop="collegeId">
<el-select v-model="queryParams.collegeId" placeholder="请选择学院" clearable style="width: 100%" @change="onCollegeChange">
<el-option v-for="item in collegeOptions" :key="item.id" :label="item.label" :value="item.id" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="专业" prop="majorId">
<el-select
v-model="queryParams.majorId"
placeholder="请选择专业"
clearable
style="width: 100%"
:disabled="!queryParams.collegeId"
@change="onMajorChange"
>
<el-option v-for="item in majorOptions" :key="item.id" :label="item.label" :value="item.id" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="6">
<el-form-item label="班级" prop="classId">
<el-select v-model="queryParams.classId" placeholder="请选择班级" clearable style="width: 100%" :disabled="!queryParams.majorId">
<el-option v-for="item in classOptions" :key="item.id" :label="item.label" :value="item.id" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="18">
<el-form-item class="search-btn-container">
<el-button type="primary" icon="Search" @click="handleQuery" :loading="loading">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
<!-- <el-button type="success" icon="Download" @click="handleExport" :loading="exportLoading" v-if="statisticsData">导出</el-button> -->
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
</div>
</transition>
<!-- 无数据提示 -->
<el-card shadow="never" v-if="!statisticsData && !loading">
<el-empty description="暂无数据" style="padding: 60px 0">
<template #description>
<p style="color: #909399; font-size: 14px">请设置统计时间范围和筛选条件,然后点击【搜索】按钮查看统计数据</p>
</template>
</el-empty>
</el-card>
<!-- 统计图表 -->
<el-card shadow="never" v-if="statisticsData">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<div class="card-header">
<span>{{ getChartTitle() }}</span>
</div>
</el-col>
<right-toolbar :showSearch="showSearch" @update:showSearch="showSearch = $event" @queryTable="handleQuery"></right-toolbar>
</el-row>
</template>
<div ref="chartRef" style="height: 400px"></div>
</el-card>
<!-- 统计明细 -->
<el-card shadow="never" v-if="statisticsData">
<template #header>
<div class="card-header">
<span>明细数据</span>
</div>
</template>
<el-table :data="statisticsData.detailData" style="width: 100%" border>
<el-table-column prop="name" label="名称" width="200" />
<el-table-column prop="parentName" label="上级" width="150" v-if="statisticsData.dimension !== 'college'" />
<el-table-column prop="dormDeductionCount" label="宿舍扣分总数" min-width="120" align="center">
<template #default="scope">
{{ scope.row.dormDeductionCount && scope.row.dormDeductionCount !== 0 ? `-${scope.row.dormDeductionCount}` : '0' }}
</template>
</el-table-column>
<el-table-column prop="dormViolationCount" label="宿舍违纪记录总数" min-width="140" align="center" />
<el-table-column prop="dormViolationDeduction" label="宿舍违纪记录扣分总数" min-width="160" align="center">
<template #default="scope">
{{
scope.row.dormViolationDeduction && scope.row.dormViolationDeduction !== 0 ? `-${scope.row.dormViolationDeduction.toFixed(2)}` : '0.00'
}}
</template>
</el-table-column>
<el-table-column prop="teachingViolationCount" label="教学区违纪记录总数" min-width="160" align="center" />
<el-table-column prop="teachingViolationDeduction" label="教学区违纪记录扣分总数" min-width="180" align="center">
<template #default="scope">
{{
scope.row.teachingViolationDeduction && scope.row.teachingViolationDeduction !== 0
? `-${scope.row.teachingViolationDeduction.toFixed(2)}`
: '0.00'
}}
</template>
</el-table-column>
<el-table-column prop="totalDeduction" label="违纪合计扣分" min-width="140" align="center">
<template #default="scope">
{{ scope.row.totalDeduction && scope.row.totalDeduction !== 0 ? `-${scope.row.totalDeduction.toFixed(2)}` : '0.00' }}
</template>
</el-table-column>
</el-table>
</el-card>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted, nextTick, getCurrentInstance, ComponentInternalInstance } from 'vue';
import { ElMessage } from 'element-plus';
import * as echarts from 'echarts';
import {
getStatistics,
exportStatistics,
getColleges,
getMajorsByCollegeId,
getClassesByMajorId,
type StudentStatisticsBo,
type StudentStatisticsVo,
type CascadeOptionVo
} from '@/api/xg/studentStatistics';
defineOptions({
name: 'StudentStatistics'
});
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const queryFormRef = ref();
const chartRef = ref<HTMLDivElement>();
const loading = ref(false);
const exportLoading = ref(false);
const showSearch = ref(true);
// 查询参数
const queryParams = reactive<StudentStatisticsBo>({
startTime: '',
endTime: '',
collegeId: undefined,
majorId: undefined,
classId: undefined
});
// 级联选择器选项
const collegeOptions = ref<CascadeOptionVo[]>([]);
const majorOptions = ref<CascadeOptionVo[]>([]);
const classOptions = ref<CascadeOptionVo[]>([]);
// 统计数据
const statisticsData = ref<StudentStatisticsVo>();
// 图表实例
let chart: echarts.ECharts | null = null;
/** 设置默认时间范围(当前月第一天到最后一天) */
const setDefaultTimeRange = () => {
const now = new Date();
const year = now.getFullYear();
const month = now.getMonth();
// 当前月第一天 00:00:00
const firstDay = new Date(year, month, 1);
const startTime = `${firstDay.getFullYear()}-${String(firstDay.getMonth() + 1).padStart(2, '0')}-${String(firstDay.getDate()).padStart(2, '0')} 00:00:00`;
// 当前月最后一天 23:59:59
const lastDay = new Date(year, month + 1, 0);
const endTime = `${lastDay.getFullYear()}-${String(lastDay.getMonth() + 1).padStart(2, '0')}-${String(lastDay.getDate()).padStart(2, '0')} 23:59:59`;
queryParams.startTime = startTime;
queryParams.endTime = endTime;
};
/** 查询学院列表 */
const getCollegeList = async () => {
try {
const res = await getColleges();
collegeOptions.value = res.data || [];
} catch (error) {
console.error('获取学院列表失败:', error);
}
};
/** 学院变化事件 */
const onCollegeChange = async (collegeId?: number) => {
queryParams.majorId = undefined;
queryParams.classId = undefined;
majorOptions.value = [];
classOptions.value = [];
if (collegeId) {
try {
const res = await getMajorsByCollegeId(collegeId);
majorOptions.value = res.data || [];
} catch (error) {
console.error('获取专业列表失败:', error);
}
}
};
/** 专业变化事件 */
const onMajorChange = async (majorId?: number) => {
queryParams.classId = undefined;
classOptions.value = [];
if (majorId) {
try {
const res = await getClassesByMajorId(majorId);
classOptions.value = res.data || [];
} catch (error) {
console.error('获取班级列表失败:', error);
}
}
};
/** 搜索按钮操作 */
const handleQuery = async () => {
if (!queryParams.startTime || !queryParams.endTime) {
ElMessage.warning('请填写统计开始时间和结束时间');
return;
}
loading.value = true;
try {
const res = await getStatistics(queryParams);
statisticsData.value = res.data;
// 渲染图表
await nextTick();
renderChart();
} catch (error) {
console.error('获取统计数据失败:', error);
ElMessage.error('获取统计数据失败');
} finally {
loading.value = false;
}
};
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value?.resetFields();
// 重置为默认时间范围
setDefaultTimeRange();
queryParams.collegeId = undefined;
queryParams.majorId = undefined;
queryParams.classId = undefined;
majorOptions.value = [];
classOptions.value = [];
statisticsData.value = undefined;
if (chart) {
chart.clear();
}
};
/** 导出按钮操作 */
const handleExport = async () => {
exportLoading.value = true;
try {
await exportStatistics(queryParams);
ElMessage.success('导出成功');
} catch (error) {
console.error('导出失败:', error);
ElMessage.error('导出失败');
} finally {
exportLoading.value = false;
}
};
/** 获取图表标题 */
const getChartTitle = () => {
if (!statisticsData.value) return '';
const dimension = statisticsData.value.dimension;
switch (dimension) {
case 'college':
return '二级学院统计';
case 'major':
return '专业统计';
case 'class':
return '班级统计';
case 'classDetail':
return '班级详情统计';
default:
return '统计图表';
}
};
/** 渲染图表 */
const renderChart = () => {
if (!chartRef.value || !statisticsData.value) return;
// 销毁现有图表
if (chart) {
chart.dispose();
}
// 创建新图表
chart = echarts.init(chartRef.value);
const chartData = statisticsData.value.chartData || [];
const names = chartData.map((item) => item.name);
const option = {
title: {
text: getChartTitle(),
left: 'center'
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
legend: {
data: ['宿舍扣分总数', '宿舍违纪记录总数', '宿舍违纪记录扣分总数', '教学区违纪记录总数', '教学区违纪记录扣分总数'],
top: 30
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
top: '15%',
containLabel: true
},
xAxis: {
type: 'category',
data: names,
axisTick: {
alignWithLabel: true
}
},
yAxis: {
type: 'value'
},
series: [
{
name: '宿舍扣分总数',
type: 'bar',
data: chartData.map((item) => item.dormDeductionCount)
},
{
name: '宿舍违纪记录总数',
type: 'bar',
data: chartData.map((item) => item.dormViolationCount)
},
{
name: '宿舍违纪记录扣分总数',
type: 'bar',
data: chartData.map((item) => item.dormViolationDeduction)
},
{
name: '教学区违纪记录总数',
type: 'bar',
data: chartData.map((item) => item.teachingViolationCount)
},
{
name: '教学区违纪记录扣分总数',
type: 'bar',
data: chartData.map((item) => item.teachingViolationDeduction)
}
]
};
chart.setOption(option);
// 监听窗口大小变化
window.addEventListener('resize', () => {
chart?.resize();
});
};
onMounted(() => {
// 设置默认时间范围
setDefaultTimeRange();
// 获取学院列表
getCollegeList();
});
</script>
<style scoped>
.page-container {
background-color: #f5f5f5;
}
.search-btn-container {
text-align: left;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
}
</style>
@@ -51,6 +51,12 @@
<el-option v-for="type in disciplineTypeOptions" :key="type.id" :label="type.typeName" :value="type.id" />
</el-select>
</el-form-item>
<!-- 违纪处分类型说明显示 -->
<el-form-item label="类型说明" v-if="selectedDisciplineType && selectedDisciplineType.remark">
<div class="discipline-type-remark">
<el-text type="info" size="small">{{ selectedDisciplineType.remark }}</el-text>
</div>
</el-form-item>
<el-form-item label="违纪处分日期" prop="disciplineDate">
<el-date-picker
v-model="form.disciplineDate"
@@ -253,7 +259,7 @@
<script setup name="DisciplineRecordForm" lang="ts">
import { ref, reactive, computed, toRefs, getCurrentInstance } from 'vue';
import { UploadFilled, Document, Loading, Download, Delete } from '@element-plus/icons-vue';
import { ElMessage, ElMessageBox, ElLoading, FormInstance } from 'element-plus';
import { ElMessage, ElMessageBox, ElLoading } from 'element-plus';
import { getToken } from '@/utils/auth';
import { globalHeaders } from '@/utils/request';
import ImagePreview from '@/components/ImagePreview/index.vue';
@@ -271,7 +277,7 @@ const emit = defineEmits(['success']);
const { proxy } = getCurrentInstance() as any;
const { student_discipline_status } = toRefs<any>(proxy?.useDict('student_discipline_status'));
const disciplineRecordFormRef = ref<FormInstance>();
const disciplineRecordFormRef = ref<any>();
const buttonLoading = ref(false);
// 学生选择器相关状态
@@ -281,6 +287,9 @@ const studentLoading = ref(false);
// 违纪处分类型选项
const disciplineTypeOptions = ref<DisciplineTypeVO[]>([]);
// 选中的违纪处分类型信息
const selectedDisciplineType = ref<DisciplineTypeVO | null>(null);
// 附件上传相关状态
const attachmentList = ref<any[]>([]);
@@ -307,16 +316,12 @@ const initFormData: DisciplineRecordFormType = {
disciplineContent: undefined,
scoreDeduction: undefined,
status: '1', // 默认生效
approvalStatus: undefined,
approvalBy: undefined,
approvalTime: undefined,
approvalRemark: undefined,
attachmentOssIds: undefined
};
const form = ref<DisciplineRecordFormType>({ ...initFormData });
const rules = reactive({
const rules = reactive<any>({
studentId: [{ required: true, message: '学生不能为空', trigger: 'change' }],
disciplineTypeId: [{ required: true, message: '违纪处分类型不能为空', trigger: 'change' }],
disciplineDate: [{ required: true, message: '违纪处分日期不能为空', trigger: 'blur' }],
@@ -383,6 +388,14 @@ const openDialog = async (id?: string | number, title?: string) => {
// 处理附件数据
await handleAttachmentData();
// 设置选中的违纪处分类型(用于显示类型说明)
if (form.value.disciplineTypeId) {
const selectedType = disciplineTypeOptions.value.find((type) => type.id === form.value.disciplineTypeId);
if (selectedType) {
selectedDisciplineType.value = selectedType;
}
}
}
};
@@ -390,6 +403,7 @@ const openDialog = async (id?: string | number, title?: string) => {
const resetForm = () => {
form.value = { ...initFormData };
attachmentList.value = [];
selectedDisciplineType.value = null;
disciplineRecordFormRef.value?.resetFields();
};
@@ -478,12 +492,18 @@ const loadDisciplineTypes = async () => {
const handleDisciplineTypeChange = (typeId: string | number) => {
if (!typeId) {
form.value.disciplineTypeName = undefined;
selectedDisciplineType.value = null;
return;
}
const selectedType = disciplineTypeOptions.value.find((type) => type.id === typeId);
if (selectedType) {
form.value.disciplineTypeName = selectedType.typeName;
selectedDisciplineType.value = selectedType;
// 自动填充最低扣分(如果有的话)
if (selectedType.minScore !== undefined && selectedType.minScore !== null) {
form.value.scoreDeduction = Number(selectedType.minScore);
}
}
};
@@ -972,6 +992,17 @@ defineExpose({
box-sizing: border-box;
}
/* 违纪处分类型说明显示 */
.discipline-type-remark {
padding: 8px 12px;
background: #f0f9ff;
border: 1px solid #bfdbfe;
border-radius: 4px;
font-size: 13px;
line-height: 1.5;
color: #1e40af;
}
.student-name-text {
font-weight: 500;
color: #303133;