فهرست منبع

Merge remote-tracking branch 'origin/dev' into dev

大数据与最优化研究所 4 ماه پیش
والد
کامیت
99b5b7ab8e
21فایلهای تغییر یافته به همراه515 افزوده شده و 4 حذف شده
  1. 6 0
      src/main/java/com/xjrsoft/common/utils/LocalDateTimeUtil.java
  2. 3 0
      src/main/java/com/xjrsoft/module/base/dto/AddBaseClassPageDto.java
  3. 3 0
      src/main/java/com/xjrsoft/module/base/entity/BaseClass.java
  4. 3 0
      src/main/java/com/xjrsoft/module/base/vo/BaseClassPageVo.java
  5. 3 0
      src/main/java/com/xjrsoft/module/base/vo/BaseClassVo.java
  6. 94 0
      src/main/java/com/xjrsoft/module/databoard/controller/DataboardController.java
  7. 135 0
      src/main/java/com/xjrsoft/module/databoard/controller/DatadetailController.java
  8. 37 0
      src/main/java/com/xjrsoft/module/databoard/vo/InternshipStatisticsDetailClassVo.java
  9. 28 0
      src/main/java/com/xjrsoft/module/databoard/vo/InternshipStatisticsDetailCompanyVo.java
  10. 34 0
      src/main/java/com/xjrsoft/module/databoard/vo/InternshipStatisticsDetailEvaluateVo.java
  11. 43 0
      src/main/java/com/xjrsoft/module/databoard/vo/InternshipStatisticsDetailVo.java
  12. 37 0
      src/main/java/com/xjrsoft/module/databoard/vo/InternshipStatisticsVo.java
  13. 1 0
      src/main/java/com/xjrsoft/module/organization/controller/UserController.java
  14. 3 0
      src/main/java/com/xjrsoft/module/organization/dto/UserPageDto.java
  15. 51 0
      src/main/java/com/xjrsoft/module/system/service/impl/LoginServiceImpl.java
  16. 3 0
      src/main/java/com/xjrsoft/module/teacher/dto/AddBaseTeacherRegularDto.java
  17. 3 0
      src/main/java/com/xjrsoft/module/teacher/dto/UpdateBaseTeacherRegularDto.java
  18. 4 0
      src/main/java/com/xjrsoft/module/teacher/entity/BaseTeacherRegular.java
  19. 3 3
      src/main/resources/logback.xml
  20. 1 1
      src/main/resources/mapper/student/BaseStudentSchoolRollMapper.xml
  21. 20 0
      src/test/java/com/xjrsoft/xjrsoftboot/WechatMessageTest.java

+ 6 - 0
src/main/java/com/xjrsoft/common/utils/LocalDateTimeUtil.java

@@ -12,6 +12,7 @@ import java.time.LocalTime;
 import java.time.Year;
 import java.time.YearMonth;
 import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoUnit;
 
 public final class LocalDateTimeUtil {
     private LocalDateTimeUtil(){}
@@ -147,4 +148,9 @@ public final class LocalDateTimeUtil {
         // 检查目标日期是否在开始日期和结束日期之间(包含边界)
         return !targetDateTime.isBefore(startDateTime) && !targetDateTime.isAfter(endDateTime);
     }
+
+
+    public static long getMinutes(LocalDateTime startDateTime, LocalDateTime endDateTime){
+        return ChronoUnit.MINUTES.between(startDateTime, endDateTime);
+    }
 }

+ 3 - 0
src/main/java/com/xjrsoft/module/base/dto/AddBaseClassPageDto.java

@@ -45,4 +45,7 @@ public class AddBaseClassPageDto implements Serializable {
 
     @ApiModelProperty("专业方向id(base_major_set)")
     private Long majorSetId;
+
+    @ApiModelProperty("实习次数")
+    private Integer internshipFrequency;
 }

+ 3 - 0
src/main/java/com/xjrsoft/module/base/entity/BaseClass.java

@@ -78,4 +78,7 @@ public class BaseClass implements Serializable {
 
     @ApiModelProperty("专业方向id(base_major_set)")
     private Long majorSetId;
+
+    @ApiModelProperty("实习次数")
+    private Integer internshipFrequency;
 }

+ 3 - 0
src/main/java/com/xjrsoft/module/base/vo/BaseClassPageVo.java

@@ -73,4 +73,7 @@ public class BaseClassPageVo {
 
     @ApiModelProperty("手机号")
     private String teacherMobile;
+
+    @ApiModelProperty("实习次数")
+    private Integer internshipFrequency;
 }

+ 3 - 0
src/main/java/com/xjrsoft/module/base/vo/BaseClassVo.java

@@ -71,4 +71,7 @@ public class BaseClassVo {
     @ApiModelProperty("专业方向id(base_major_set)")
     private Long majorSetId;
 
+    @ApiModelProperty("实习次数")
+    private Integer internshipFrequency;
+
 }

+ 94 - 0
src/main/java/com/xjrsoft/module/databoard/controller/DataboardController.java

@@ -11,6 +11,8 @@ import com.xjrsoft.common.enums.StudyStatusEnum;
 import com.xjrsoft.common.model.result.RT;
 import com.xjrsoft.common.mybatis.SqlRunnerAdapter;
 import com.xjrsoft.common.utils.VoToColumnUtil;
+import com.xjrsoft.module.base.entity.BaseSemester;
+import com.xjrsoft.module.base.service.IBaseSemesterService;
 import com.xjrsoft.module.courseTable.entity.CourseTable;
 import com.xjrsoft.module.courseTable.service.ICourseTableService;
 import com.xjrsoft.module.databoard.dto.StatisticsDetailDto;
@@ -36,6 +38,8 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
 import javax.validation.Valid;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
@@ -58,6 +62,7 @@ public class DataboardController {
     private final IBaseStudentService studentService;
     private final ITeacherbaseManagerService teacherService;
     private final IWorkflowFormRelationService formRelationService;
+    private final IBaseSemesterService semesterService;
 
     @GetMapping(value = "/process-statistics")
     @ApiOperation(value = "流程统计")
@@ -605,4 +610,93 @@ public class DataboardController {
         return RT.ok(result);
     }
 
+    @GetMapping(value = "/internship-statistics")
+    @ApiOperation(value = "实习统计")
+    @SaCheckPermission("databoard:detail")
+    @XjrLog(value = "实习统计", saveResponseData = true)
+    public RT<InternshipStatisticsVo> internshipStatistics(@Valid StatisticsDetailDto dto) {
+        BaseSemester semester = semesterService.getCurrentSemester();
+        if(semester == null){
+            return RT.error("未能查询计划到当前学期");
+        }
+
+        InternshipStatisticsVo result = new InternshipStatisticsVo();
+
+        String sql = " SELECT DISTINCT t1.participant_user_id FROM internship_plan_manage_participant t1" +
+                " INNER JOIN internship_plan_manage t2 ON t1.internship_plan_manage_id = t2.id" +
+                " INNER JOIN xjr_user t3 ON t1.participant_user_id = t3.id" +
+                " WHERE t1.delete_mark = 0 AND t2.delete_mark = 0 AND t3.delete_mark = 0" +
+                " and t2.base_semester_id = " + semester.getId();
+
+        List<Map<String, Object>> studentlist = SqlRunnerAdapter.db().selectList(sql);
+
+
+        sql = "SELECT DISTINCT t3.id FROM student_internship_alone_apply t1" +
+            " INNER JOIN xjr_workflow_form_relation t2 ON t1.id = CAST(t2.form_key_value AS SIGNED)" +
+            " INNER JOIN xjr_user t3 ON t3.id = t1.student_user_id" +
+            " INNER JOIN internship_plan_manage t4 ON t1.internship_plan_manage_id = t4.id" +
+            " WHERE t1.delete_mark = 0 AND t3.delete_mark = 0 AND t4.delete_mark = 0" +
+            " and t4.base_semester_id = " + semester.getId() +
+            " AND t2.current_state = 'COMPLETED'";
+        List<Map<String, Object>> list2 = SqlRunnerAdapter.db().selectList(sql);
+
+        int studentCount = studentlist.size() + list2.size();
+        result.setStudentCount(studentCount);
+
+        //实习班级
+        sql = " SELECT DISTINCT t3.id FROM internship_plan_class t1" +
+            " INNER JOIN internship_plan_manage t2 ON t1.internship_plan_manage_id = t2.id" +
+            " INNER JOIN base_class t3 ON t1.class_id = t3.id" +
+            " WHERE t1.delete_mark = 0 AND t2.delete_mark = 0 AND t3.delete_mark = 0" +
+            " and t2.base_semester_id = " + semester.getId();
+        List<Map<String, Object>> list = SqlRunnerAdapter.db().selectList(sql);
+        result.setClassCount(list.size());
+
+        //实习企业
+        sql = " SELECT * FROM company_coop WHERE delete_mark = 0";
+        list = SqlRunnerAdapter.db().selectList(sql);
+        result.setCompanyCount(list.size());
+
+
+        sql = "SELECT DISTINCT t3.id FROM student_special_constitution t1" +
+            " INNER JOIN xjr_workflow_form_relation t2 ON t1.id = CAST(t2.form_key_value AS SIGNED)" +
+            " INNER JOIN xjr_user t3 ON t3.id = t1.student_user_id" +
+            " WHERE t1.delete_mark = 0 AND t3.delete_mark = 0" +
+            " AND t2.current_state = 'COMPLETED'";
+        List<Map<String, Object>> specialConstitutions = SqlRunnerAdapter.db().selectList(sql);
+
+        int allCount = specialConstitutions.size() + studentCount;
+
+        List<ItemCountRatioVo> studentList = new ArrayList<>();
+        //统一实习
+        ItemCountRatioVo item = new ItemCountRatioVo();
+        item.setItem("统一实习");
+        item.setCount(studentlist.size());
+        //计算占比
+        BigDecimal divide = BigDecimal.valueOf(studentlist.size()).divide(BigDecimal.valueOf(allCount), 4, RoundingMode.HALF_UP);
+        item.setRatio(divide.doubleValue());
+        studentList.add(item);
+
+        //自主实习
+        item = new ItemCountRatioVo();
+        item.setItem("自主实习");
+        item.setCount(list2.size());
+        //计算占比
+        divide = BigDecimal.valueOf(list2.size()).divide(BigDecimal.valueOf(allCount), 4, RoundingMode.HALF_UP);
+        item.setRatio(divide.doubleValue());
+        studentList.add(item);
+
+        //自主实习
+        item = new ItemCountRatioVo();
+        item.setItem("自主实习");
+        item.setCount(specialConstitutions.size());
+        //计算占比
+        divide = BigDecimal.valueOf(specialConstitutions.size()).divide(BigDecimal.valueOf(allCount), 4, RoundingMode.HALF_UP);
+        item.setRatio(divide.doubleValue());
+        studentList.add(item);
+
+        result.setStudentList(studentList);
+        return RT.ok(result);
+    }
+
 }

+ 135 - 0
src/main/java/com/xjrsoft/module/databoard/controller/DatadetailController.java

@@ -16,6 +16,7 @@ import com.xjrsoft.common.utils.SqlRunnerAdapterUtil;
 import com.xjrsoft.common.utils.VoToColumnUtil;
 import com.xjrsoft.module.base.entity.BaseSemester;
 import com.xjrsoft.module.base.mapper.BaseSemesterMapper;
+import com.xjrsoft.module.base.service.IBaseSemesterService;
 import com.xjrsoft.module.databoard.dto.StatisticsDetailDto;
 import com.xjrsoft.module.databoard.dto.TeacherChangeStatisticsDetailDto;
 import com.xjrsoft.module.databoard.vo.CourseCountListVo;
@@ -24,6 +25,10 @@ import com.xjrsoft.module.databoard.vo.DistributionVo;
 import com.xjrsoft.module.databoard.vo.DurationVo;
 import com.xjrsoft.module.databoard.vo.HealthItemCountVo;
 import com.xjrsoft.module.databoard.vo.HealthStatisticsDetailVo;
+import com.xjrsoft.module.databoard.vo.InternshipStatisticsDetailClassVo;
+import com.xjrsoft.module.databoard.vo.InternshipStatisticsDetailCompanyVo;
+import com.xjrsoft.module.databoard.vo.InternshipStatisticsDetailEvaluateVo;
+import com.xjrsoft.module.databoard.vo.InternshipStatisticsDetailVo;
 import com.xjrsoft.module.databoard.vo.ItemCount2Vo;
 import com.xjrsoft.module.databoard.vo.ItemCountAmountVo;
 import com.xjrsoft.module.databoard.vo.ItemCountRatioVo;
@@ -96,6 +101,7 @@ public class DatadetailController {
     private final IBaseStudentService studentService;
     private final IWfSubscriptionService subscriptionService;
     private final BaseSemesterMapper baseSemesterMapper;
+    private final IBaseSemesterService semesterService;
 
     @GetMapping(value = "/process-statistics")
     @ApiOperation(value = "流程统计详情")
@@ -963,4 +969,133 @@ public class DatadetailController {
         return RT.ok(result);
     }
 
+
+    @GetMapping(value = "/internship-statistics")
+    @ApiOperation(value = "实习统计")
+    @SaCheckPermission("databoard:detail")
+    @XjrLog(value = "实习统计", saveResponseData = true)
+    public RT<InternshipStatisticsDetailVo> internshipStatistics(@Valid StatisticsDetailDto dto) {
+        InternshipStatisticsDetailVo result = new InternshipStatisticsDetailVo();
+        BaseSemester semester = semesterService.getCurrentSemester();
+        if(semester == null){
+            return RT.error("未能查询计划到当前学期");
+        }
+        String sql = " SELECT DISTINCT t1.participant_user_id FROM internship_plan_manage_participant t1" +
+                " INNER JOIN internship_plan_manage t2 ON t1.internship_plan_manage_id = t2.id" +
+                " INNER JOIN xjr_user t3 ON t1.participant_user_id = t3.id" +
+                " WHERE t1.delete_mark = 0 AND t2.delete_mark = 0 AND t3.delete_mark = 0" +
+                " and t2.base_semester_id = " + semester.getId();
+
+        List<Map<String, Object>> studentlist = SqlRunnerAdapter.db().selectList(sql);
+
+
+        sql = "SELECT DISTINCT t3.id FROM student_internship_alone_apply t1" +
+                " INNER JOIN xjr_workflow_form_relation t2 ON t1.id = CAST(t2.form_key_value AS SIGNED)" +
+                " INNER JOIN xjr_user t3 ON t3.id = t1.student_user_id" +
+                " INNER JOIN internship_plan_manage t4 ON t1.internship_plan_manage_id = t4.id" +
+                " WHERE t1.delete_mark = 0 AND t3.delete_mark = 0 AND t4.delete_mark = 0" +
+                " and t4.base_semester_id = " + semester.getId() +
+                " AND t2.current_state = 'COMPLETED'";
+        List<Map<String, Object>> list2 = SqlRunnerAdapter.db().selectList(sql);
+
+        int studentCount = studentlist.size() + list2.size();
+        result.setStudentCount(studentCount);
+
+        //实习班级
+        sql = " SELECT DISTINCT t3.id FROM internship_plan_class t1" +
+                " INNER JOIN internship_plan_manage t2 ON t1.internship_plan_manage_id = t2.id" +
+                " INNER JOIN base_class t3 ON t1.class_id = t3.id" +
+                " WHERE t1.delete_mark = 0 AND t2.delete_mark = 0 AND t3.delete_mark = 0" +
+                " and t2.base_semester_id = " + semester.getId();
+        List<Map<String, Object>> list = SqlRunnerAdapter.db().selectList(sql);
+        result.setClassCount(list.size());
+
+        //实习企业
+        sql = " SELECT * FROM company_coop WHERE delete_mark = 0";
+        list = SqlRunnerAdapter.db().selectList(sql);
+        result.setCompanyCount(list.size());
+
+
+        sql = "SELECT DISTINCT t3.name,\n" +
+            "(SELECT COUNT(participant_user_id) FROM internship_plan_manage_participant\n" +
+            "WHERE class_id = t3.id AND internship_plan_manage_id = t2.id and delete_mark = 0) AS unite_count,\n" +
+            "(SELECT COUNT(a1.student_user_id) FROM student_internship_alone_apply a1" +
+            " INNER JOIN xjr_workflow_form_relation a2 ON t1.id = CAST(a2.form_key_value AS SIGNED)" +
+            " WHERE a1.class_id = t3.id AND a1.internship_plan_manage_id = t2.id and a1.delete_mark = 0" +
+            " and a2.current_state = 'COMPLETED'" +
+            " ) AS alone_count,\n" +
+            "(SELECT COUNT(student_user_id) FROM student_special_constitution a1" +
+            " INNER JOIN xjr_workflow_form_relation a2 ON t1.id = CAST(a2.form_key_value AS SIGNED)" +
+            " WHERE a1.class_id = t3.id and a1.delete_mark = 0 and a2.current_state = 'COMPLETED') AS special_count\n" +
+            "FROM internship_plan_class t1\n" +
+            "INNER JOIN internship_plan_manage t2 ON t1.internship_plan_manage_id = t2.id\n" +
+            "INNER JOIN base_class t3 ON t1.class_id = t3.id\n" +
+            "WHERE t1.delete_mark = 0 AND t2.delete_mark = 0 AND t3.delete_mark = 0" +
+            " and t2.base_semester_id = " + semester.getId();
+        List<Map<String, Object>> classDatas = SqlRunnerAdapter.db().selectList(sql);
+
+        List<InternshipStatisticsDetailClassVo> classList = new ArrayList<>();
+        for (Map<String, Object> objectMap : classDatas) {
+            classList.add(new InternshipStatisticsDetailClassVo(){{
+                setClassName(objectMap.get("name").toString());
+                setUniteCount(Integer.parseInt(objectMap.get("unite_count").toString()));
+                setAloneCount(Integer.parseInt(objectMap.get("alone_count").toString()));
+                setSpecialCount(Integer.parseInt(objectMap.get("special_count").toString()));
+            }});
+        }
+        result.setClassList(classList);
+
+        sql = "SELECT t1.id,t1.company_name,\n" +
+                "(\n" +
+                "SELECT COUNT(a1.id) FROM internship_plan_manage_participant a1\n" +
+                "INNER JOIN internship_plan_manage a2 ON a2.id = a1.internship_plan_manage_id \n" +
+                "WHERE a1.delete_mark = 0 AND a2.delete_mark = 0\n" +
+                "AND a2.internship_unit_id = t1.id\n" +
+                ") AS counts\n" +
+                "FROM company_coop t1\n" +
+                "WHERE t1.delete_mark = 0\n" +
+                "AND id IN (\n" +
+                "SELECT DISTINCT internship_unit_id FROM internship_plan_manage\n" +
+                "WHERE delete_mark = 0 AND base_semester_id = "  +semester.getId() +
+                ")";
+        List<Map<String, Object>> companyDatas = SqlRunnerAdapter.db().selectList(sql);
+        List<InternshipStatisticsDetailCompanyVo> companyList = new ArrayList<>();
+        for (Map<String, Object> companyData : companyDatas) {
+            companyList.add(new InternshipStatisticsDetailCompanyVo(){{
+                setCompanyName(companyData.get("company_name").toString());
+                setStudentCount(Integer.parseInt(companyData.get("counts").toString()));
+            }});
+        }
+        result.setCompanyList(companyList);
+
+        sql = "SELECT t3.name,\n" +
+                "(SELECT COUNT(*) FROM internship_plan_manage_participant WHERE delete_mark = 0\n" +
+                "AND result = '1' AND class_id = t3.id AND internship_plan_manage_id = t2.id\n" +
+                ") AS unqualified, \n" +
+                "(SELECT COUNT(*) FROM internship_plan_manage_participant WHERE delete_mark = 0\n" +
+                "AND result = '2' AND class_id = t3.id AND internship_plan_manage_id = t2.id\n" +
+                ") AS qualified, \n" +
+                "(SELECT COUNT(*) FROM internship_plan_manage_participant WHERE delete_mark = 0\n" +
+                "AND result = '3' AND class_id = t3.id AND internship_plan_manage_id = t2.id\n" +
+                ") AS excellent\n" +
+                "FROM internship_plan_class t1\n" +
+                "INNER JOIN internship_plan_manage t2 ON t1.internship_plan_manage_id = t2.id\n" +
+                "INNER JOIN base_class t3 ON t1.class_id = t3.id\n" +
+                "WHERE t1.delete_mark = 0 AND t2.delete_mark = 0 AND t3.delete_mark = 0" +
+                " and t2.base_semester_id = " + semester.getId();
+        List<Map<String, Object>> evaluateDatas = SqlRunnerAdapter.db().selectList(sql);
+        List<InternshipStatisticsDetailEvaluateVo> evaluateList = new ArrayList<>();
+        for (Map<String, Object> companyData : evaluateDatas) {
+            evaluateList.add(new InternshipStatisticsDetailEvaluateVo(){{
+                setClassName(companyData.get("name").toString());
+                setUnqualifiedCount(Integer.parseInt(companyData.get("unqualified").toString()));
+                setQualifiedCount(Integer.parseInt(companyData.get("qualified").toString()));
+                setExcellentCount(Integer.parseInt(companyData.get("excellent").toString()));
+            }});
+        }
+        result.setEvaluateList(evaluateList);
+
+        return RT.ok(result);
+    }
+
 }

+ 37 - 0
src/main/java/com/xjrsoft/module/databoard/vo/InternshipStatisticsDetailClassVo.java

@@ -0,0 +1,37 @@
+package com.xjrsoft.module.databoard.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @title: 实习详情统计-班级
+ * @Author dzx
+ * @Date: 2025年7月14日
+ * @Version 1.0
+ */
+@Data
+public class InternshipStatisticsDetailClassVo {
+
+    /**
+     * 发起流程总数
+     */
+    @ApiModelProperty("班级名称")
+    private String className;
+    /**
+     * 完成总数
+     */
+    @ApiModelProperty("统一实习学生数量")
+    private Integer uniteCount;
+    /**
+     * 未完成总数
+     */
+    @ApiModelProperty("自主实习学生数量")
+    private Integer aloneCount;
+
+
+    @ApiModelProperty("特殊体质学生数量")
+    private Integer specialCount;
+
+}

+ 28 - 0
src/main/java/com/xjrsoft/module/databoard/vo/InternshipStatisticsDetailCompanyVo.java

@@ -0,0 +1,28 @@
+package com.xjrsoft.module.databoard.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @title: 实习详情统计-实习企业
+ * @Author dzx
+ * @Date: 2025年7月14日
+ * @Version 1.0
+ */
+@Data
+public class InternshipStatisticsDetailCompanyVo {
+
+    /**
+     * 发起流程总数
+     */
+    @ApiModelProperty("实习学生数量")
+    private Integer studentCount;
+    /**
+     * 完成总数
+     */
+    @ApiModelProperty("企业名称")
+    private String companyName;
+
+}

+ 34 - 0
src/main/java/com/xjrsoft/module/databoard/vo/InternshipStatisticsDetailEvaluateVo.java

@@ -0,0 +1,34 @@
+package com.xjrsoft.module.databoard.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @title: 实习详情统计-实习类型
+ * @Author dzx
+ * @Date: 2025年7月14日
+ * @Version 1.0
+ */
+@Data
+public class InternshipStatisticsDetailEvaluateVo {
+
+    @ApiModelProperty("班级名称")
+    private String className;
+    /**
+     * 完成总数
+     */
+    @ApiModelProperty("不合格数量")
+    private Integer unqualifiedCount;
+    /**
+     * 未完成总数
+     */
+    @ApiModelProperty("合格数量")
+    private Integer qualifiedCount;
+
+
+    @ApiModelProperty("优秀数量")
+    private Integer excellentCount;
+
+}

+ 43 - 0
src/main/java/com/xjrsoft/module/databoard/vo/InternshipStatisticsDetailVo.java

@@ -0,0 +1,43 @@
+package com.xjrsoft.module.databoard.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @title: 数据看板-流程统计出参
+ * @Author dzx
+ * @Date: 2024年8月2日
+ * @Version 1.0
+ */
+@Data
+public class InternshipStatisticsDetailVo {
+
+    /**
+     * 发起流程总数
+     */
+    @ApiModelProperty("实习学生数量")
+    private Integer studentCount;
+    /**
+     * 完成总数
+     */
+    @ApiModelProperty("实习班级数量")
+    private Integer classCount;
+    /**
+     * 未完成总数
+     */
+    @ApiModelProperty("实习企业数量")
+    private Integer companyCount;
+
+
+    @ApiModelProperty("实习企业")
+    private List<InternshipStatisticsDetailCompanyVo> companyList;
+
+    @ApiModelProperty("实习班级")
+    private List<InternshipStatisticsDetailClassVo> classList;
+
+    @ApiModelProperty("实习结果")
+    private List<InternshipStatisticsDetailEvaluateVo> evaluateList;
+
+}

+ 37 - 0
src/main/java/com/xjrsoft/module/databoard/vo/InternshipStatisticsVo.java

@@ -0,0 +1,37 @@
+package com.xjrsoft.module.databoard.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @title: 数据看板-流程统计出参
+ * @Author dzx
+ * @Date: 2024年8月2日
+ * @Version 1.0
+ */
+@Data
+public class InternshipStatisticsVo {
+
+    /**
+     * 发起流程总数
+     */
+    @ApiModelProperty("实习学生数量")
+    private Integer studentCount;
+    /**
+     * 完成总数
+     */
+    @ApiModelProperty("实习班级数量")
+    private Integer classCount;
+    /**
+     * 未完成总数
+     */
+    @ApiModelProperty("实习企业数量")
+    private Integer companyCount;
+
+
+    @ApiModelProperty("学生组成占比")
+    private List<ItemCountRatioVo> studentList;
+
+}

+ 1 - 0
src/main/java/com/xjrsoft/module/organization/controller/UserController.java

@@ -186,6 +186,7 @@ public class UserController {
                     .eq(ObjectUtil.isNotNull(dto.getEmployWay()), BaseTeacher::getEmployWay, dto.getEmployWay())
                     .eq(ObjectUtil.isNotNull(dto.getClassId()), BaseStudentSchoolRoll::getClassId, dto.getClassId())
                     .eq(ObjectUtil.isNotNull(dto.getRoleId()), UserRoleRelation::getRoleId, dto.getRoleId())
+                    .eq(ObjectUtil.isNotNull(dto.getIsTeach()), BaseTeacherRegular::getIsTeach, dto.getIsTeach())
                     .orderByDesc(User::getId)
                     .select(User::getId)
                     .select("d1.name", UserPageVo::getEmployWay)

+ 3 - 0
src/main/java/com/xjrsoft/module/organization/dto/UserPageDto.java

@@ -49,4 +49,7 @@ public class UserPageDto extends PageInput {
 
     @ApiModelProperty("教学状态")
     private String teachingStatus;
+
+    @ApiModelProperty("是否任教(1:是 0:否)")
+    private Integer isTeach;
 }

+ 51 - 0
src/main/java/com/xjrsoft/module/system/service/impl/LoginServiceImpl.java

@@ -13,11 +13,15 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.baomidou.mybatisplus.core.toolkit.StringPool;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
 import com.xjrsoft.common.constant.GlobalConstant;
 import com.xjrsoft.common.enums.EnabledMark;
 import com.xjrsoft.common.enums.RoleEnum;
 import com.xjrsoft.common.exception.MyException;
 import com.xjrsoft.common.utils.FixedArithmeticCaptcha;
+import com.xjrsoft.common.utils.LocalDateTimeUtil;
 import com.xjrsoft.common.utils.RSAUtil;
 import com.xjrsoft.common.utils.RedisUtil;
 import com.xjrsoft.common.utils.WeChatUtil;
@@ -36,6 +40,9 @@ import com.xjrsoft.module.system.vo.*;
 import lombok.AllArgsConstructor;
 import org.springframework.stereotype.Service;
 
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoUnit;
 import java.util.List;
 import java.util.UUID;
 import java.util.concurrent.CompletableFuture;
@@ -73,8 +80,20 @@ public class LoginServiceImpl implements ILoginService {
 
     private final IWhitelistManagementService whitelistManagementService;
 
+    private final static String loginErrorKey = "loginErrorCount";
+    private final static String loginLockKey = "loginLockTime";
+
     @Override
     public LoginVo login(LoginDto dto) throws Exception {
+        if(redisUtil.containsKey(dto.getUserName() + loginLockKey )){
+
+            String dateTime = redisUtil.get(dto.getUserName() + loginLockKey);
+            long minutes = ChronoUnit.MINUTES.between(LocalDateTime.now(), LocalDateTime.parse(dateTime, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+
+            throw new MyException("账户被锁定!请在" + minutes + "分钟后重新登录");
+        }else{
+            redisUtil.delete(dto.getUserName() + loginLockKey);
+        }
         if (licenseConfig.getEnabled()) {
             //查出所有在线用户
             List<String> onlineUser = StpUtil.searchSessionId("", 0, -1, true);
@@ -104,7 +123,39 @@ public class LoginServiceImpl implements ILoginService {
                         .or()
                         .eq(User::getMobile, dto.getUserName()));
 
+
         if (loginUser == null || !BCrypt.checkpw(dto.getPassword(), loginUser.getPassword())) {
+            if(loginUser != null){
+                JsonParser parser = new JsonParser();
+                JsonObject loginErrorJson;
+                if(!redisUtil.containsKey(loginErrorKey)){
+                    //第一次登录失败
+                    loginErrorJson = new JsonObject();
+                    loginErrorJson.addProperty(loginUser.getId().toString(), 1);
+                    redisUtil.set(loginErrorKey, loginErrorJson.toString());
+                }else{
+                    loginErrorJson = parser.parse(redisUtil.get(loginErrorKey)).getAsJsonObject();
+
+                    if(loginErrorJson.has(loginUser.getId().toString())){
+                        int count = loginErrorJson.get(loginUser.getId().toString()).getAsInt();
+                        if(count == 2){
+                            //密码错误3次,锁定登录
+                            LocalDateTime now = LocalDateTime.now();
+                            now = now.plusMinutes(10);
+                            redisUtil.set(loginUser.getUserName() + loginLockKey, now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")), 600);
+                            //锁定之后,清空次数计算
+                            loginErrorJson.remove(loginUser.getId().toString());
+                            redisUtil.set(loginErrorKey, loginErrorJson.toString());
+                        }else{
+                            loginErrorJson.addProperty(loginUser.getId().toString(), count + 1);
+                            redisUtil.set(loginErrorKey, loginErrorJson.toString());
+                        }
+                    }else{
+                        loginErrorJson.addProperty(loginUser.getId().toString(),  1);
+                        redisUtil.set(loginErrorKey, loginErrorJson.toString());
+                    }
+                }
+            }
             throw new MyException("账号或密码不正确");
         }
 

+ 3 - 0
src/main/java/com/xjrsoft/module/teacher/dto/AddBaseTeacherRegularDto.java

@@ -67,4 +67,7 @@ public class AddBaseTeacherRegularDto implements Serializable {
     @ApiModelProperty("任教学科(base_course_subject)")
     private Long courseSubjectId;
 
+    @ApiModelProperty("是否任课老师(1:是 0:否)")
+    private Integer isTeach;
+
 }

+ 3 - 0
src/main/java/com/xjrsoft/module/teacher/dto/UpdateBaseTeacherRegularDto.java

@@ -72,4 +72,7 @@ public class UpdateBaseTeacherRegularDto implements Serializable {
     @ApiModelProperty("任教学科(base_course_subject)")
     private Long courseSubjectId;
 
+    @ApiModelProperty("是否任课老师(1:是 0:否)")
+    private Integer isTeach;
+
 }

+ 4 - 0
src/main/java/com/xjrsoft/module/teacher/entity/BaseTeacherRegular.java

@@ -116,4 +116,8 @@ public class BaseTeacherRegular implements Serializable {
      */
     @ApiModelProperty("任教学科(base_course_subject)")
     private Long courseSubjectId;
+
+
+    @ApiModelProperty("是否任课老师(1:是 0:否)")
+    private Integer isTeach;
 }

+ 3 - 3
src/main/resources/logback.xml

@@ -37,8 +37,8 @@
         <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
             <!-- 日志文件名格式 -->
             <fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log</fileNamePattern>
-            <!-- 日志最大的历史 15天 -->
-            <maxHistory>15</maxHistory>
+            <!-- 日志最大的历史 7天 -->
+            <maxHistory>7</maxHistory>
         </rollingPolicy>
         <encoder>
             <pattern>${log.pattern}</pattern>
@@ -82,7 +82,7 @@
             <!-- 按天回滚 daily -->
             <fileNamePattern>${log.path}/sys-user.%d{yyyy-MM-dd}.log</fileNamePattern>
             <!-- 日志最大的历史 15天 -->
-            <maxHistory>15</maxHistory>
+            <maxHistory>7</maxHistory>
         </rollingPolicy>
         <encoder>
             <pattern>${log.pattern}</pattern>

+ 1 - 1
src/main/resources/mapper/student/BaseStudentSchoolRollMapper.xml

@@ -87,7 +87,7 @@
             AND t2.credential_number LIKE concat('%', #{dto.credentialNumber}, '%')
         </if>
         <if test="dto.notInIds != null and dto.notInIds.size() > 0">
-            and t2.id in
+            and t2.id not in
             <foreach item="notInId" index="index" collection="dto.notInIds" open="(" close=")" separator=",">
                 #{notInId}
             </foreach>

+ 20 - 0
src/test/java/com/xjrsoft/xjrsoftboot/WechatMessageTest.java

@@ -1,8 +1,12 @@
 package com.xjrsoft.xjrsoftboot;
 
+import camundajar.impl.com.google.gson.JsonObject;
 import cn.hutool.core.util.IdUtil;
+import cn.hutool.http.HttpUtil;
 import com.alibaba.fastjson.JSONObject;
 import com.xjrsoft.XjrSoftApplication;
+import com.xjrsoft.common.enums.WeChatType;
+import com.xjrsoft.common.utils.WeChatUtil;
 import com.xjrsoft.module.organization.dto.WeChatSendMessageDto;
 import com.xjrsoft.module.organization.service.IWeChatService;
 import org.junit.jupiter.api.Test;
@@ -23,6 +27,9 @@ class WechatMessageTest {
     @Autowired
     private IWeChatService weChatService;
 
+    @Autowired
+    private WeChatUtil weChatUtil;
+
     @Test
     void test(){
 
@@ -57,4 +64,17 @@ class WechatMessageTest {
             }
         }
     }
+
+    @Test
+    public void getRidInfo(){
+        String token = weChatUtil.getToken(WeChatType.WEWEB);
+        String url = "https://api.weixin.qq.com/cgi-bin/openapi/rid/get?access_token=" + token;
+
+        JSONObject object = new JSONObject();
+        object.put("rid", "686b6714-61e7b031-42b4ea15");
+        String result = HttpUtil.post(url, JSONObject.toJSONString(object));
+
+        System.out.println(result);
+    }
+
 }