Pārlūkot izejas kodu

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

大数据与最优化研究所 1 gadu atpakaļ
vecāks
revīzija
0774d3608d
55 mainītis faili ar 1586 papildinājumiem un 195 dzēšanām
  1. 11 0
      src/main/java/com/xjrsoft/common/constant/GlobalConstant.java
  2. 0 4
      src/main/java/com/xjrsoft/common/interceptor/MagicApiWebLoginInterceptor.java
  3. 45 0
      src/main/java/com/xjrsoft/common/interceptor/RateLimitInterceptor.java
  4. 7 14
      src/main/java/com/xjrsoft/common/runner/OrganizationCacheRunner.java
  5. 5 2
      src/main/java/com/xjrsoft/common/utils/WeChatUtil.java
  6. 4 6
      src/main/java/com/xjrsoft/common/xss/XssFilter.java
  7. 7 0
      src/main/java/com/xjrsoft/config/SaTokenConfig.java
  8. 8 11
      src/main/java/com/xjrsoft/module/attendance/controller/StatisticsController.java
  9. 40 32
      src/main/java/com/xjrsoft/module/attendance/controller/StudentStatisticsController.java
  10. 4 0
      src/main/java/com/xjrsoft/module/attendance/controller/TeacherStatisticsController.java
  11. 6 0
      src/main/java/com/xjrsoft/module/attendance/dto/TeacherDetailsDto.java
  12. 156 0
      src/main/java/com/xjrsoft/module/base/controller/WhitelistManagementController.java
  13. 48 0
      src/main/java/com/xjrsoft/module/base/dto/AddWhitelistManagementDto.java
  14. 32 0
      src/main/java/com/xjrsoft/module/base/dto/UpdateWhitelistManagementDto.java
  15. 40 0
      src/main/java/com/xjrsoft/module/base/dto/WhitelistManagementPageDto.java
  16. 12 0
      src/main/java/com/xjrsoft/module/base/entity/TreeNode.java
  17. 22 0
      src/main/java/com/xjrsoft/module/base/entity/WhiteBaseClass.java
  18. 22 0
      src/main/java/com/xjrsoft/module/base/entity/WhiteBaseGrade.java
  19. 86 0
      src/main/java/com/xjrsoft/module/base/entity/WhitelistManagement.java
  20. 45 0
      src/main/java/com/xjrsoft/module/base/mapper/WhitelistManagementMapper.java
  21. 38 0
      src/main/java/com/xjrsoft/module/base/service/IWhitelistManagementService.java
  22. 108 0
      src/main/java/com/xjrsoft/module/base/service/impl/WhitelistManagementServiceImpl.java
  23. 98 0
      src/main/java/com/xjrsoft/module/base/vo/WhitelistManagementPageVo.java
  24. 49 0
      src/main/java/com/xjrsoft/module/base/vo/WhitelistManagementVo.java
  25. 40 8
      src/main/java/com/xjrsoft/module/hikvision/util/DataUtil.java
  26. 4 4
      src/main/java/com/xjrsoft/module/hikvision/util/OutInRecordUtil.java
  27. 52 33
      src/main/java/com/xjrsoft/module/job/AttenDanceWarnNoticeTask.java
  28. 118 48
      src/main/java/com/xjrsoft/module/job/AttendanceMessageTask.java
  29. 0 3
      src/main/java/com/xjrsoft/module/job/HikvisionBaseDataTask.java
  30. 1 1
      src/main/java/com/xjrsoft/module/job/InsertOutInRecordTask.java
  31. 9 0
      src/main/java/com/xjrsoft/module/organization/controller/UserController.java
  32. 4 0
      src/main/java/com/xjrsoft/module/outint/controller/StudentOutInRecordController.java
  33. 6 3
      src/main/java/com/xjrsoft/module/personnel/controller/StundentFaceProcessController.java
  34. 20 4
      src/main/java/com/xjrsoft/module/personnel/controller/TeacherFaceProcessController.java
  35. 4 0
      src/main/java/com/xjrsoft/module/personnel/service/IStundentFaceProcessService.java
  36. 4 0
      src/main/java/com/xjrsoft/module/personnel/service/ITeacherFaceProcessService.java
  37. 48 0
      src/main/java/com/xjrsoft/module/personnel/service/impl/StundentFaceProcessServiceImpl.java
  38. 47 0
      src/main/java/com/xjrsoft/module/personnel/service/impl/TeacherFaceProcessServiceImpl.java
  39. 4 0
      src/main/java/com/xjrsoft/module/student/controller/StudentManagerController.java
  40. 3 0
      src/main/java/com/xjrsoft/module/system/service/impl/LoginServiceImpl.java
  41. 4 0
      src/main/java/com/xjrsoft/module/teacher/controller/TeacherbaseManagerController.java
  42. 1 0
      src/main/java/com/xjrsoft/module/workflow/service/IWorkflowExecuteService.java
  43. 9 0
      src/main/java/com/xjrsoft/module/workflow/service/impl/WorkflowExecuteServiceImpl.java
  44. 2 1
      src/main/resources/application-dev.yml
  45. 2 1
      src/main/resources/application-pre.yml
  46. 2 1
      src/main/resources/application-prod.yml
  47. 82 0
      src/main/resources/mapper/base/WhitelistManagement.xml
  48. 11 3
      src/main/resources/mapper/outin/StudentOutInRecordMapper.xml
  49. 1 1
      src/main/resources/mapper/teacher/TeacherFaceImportMapper.xml
  50. 16 0
      src/main/resources/sqlScript/20240531_sql.sql
  51. 123 0
      src/main/resources/sqlScript/20240604_sql.sql
  52. 16 0
      src/main/resources/sqlScript/20240618_sql.sql
  53. 2 2
      src/test/java/com/xjrsoft/module/job/AttendanceMessageTaskTest.java
  54. 33 13
      src/test/java/com/xjrsoft/module/job/HikvisionBaseDataTaskTest.java
  55. 25 0
      src/test/java/com/xjrsoft/xjrsoftboot/FreeMarkerGeneratorTest.java

+ 11 - 0
src/main/java/com/xjrsoft/common/constant/GlobalConstant.java

@@ -59,6 +59,12 @@ public interface GlobalConstant {
      * */
     String LOGIN_USER_INFO_KEY = "LOGIN_USER_INFO_KEY";
 
+    /**
+     * @des sa-token 登录人用户类型
+     *
+     * */
+    String LOGIN_USER_TYPE = "LOGIN_USER_TYPE";
+
     /**
      * @des sa-token 登陆人权限Code key
      * */
@@ -408,6 +414,11 @@ public interface GlobalConstant {
      */
     String  DIC_ITEM_CACHE_KEY  = "ALL_DIC_ITEM";
 
+    /**
+     * 学生电信开卡用户
+     */
+    String WHITE_MANAGEMENT_CACHE_KEY = "ALL_WHITE_MANAGEMENT";
+
 
     /**
      * 数据字典详情

+ 0 - 4
src/main/java/com/xjrsoft/common/interceptor/MagicApiWebLoginInterceptor.java

@@ -21,7 +21,6 @@ import javax.servlet.http.HttpServletResponse;
 public class MagicApiWebLoginInterceptor implements HandlerInterceptor {
 
     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
-
         // 根据parameter 判断是否有权限
         String parameter = request.getParameter(StpUtil.getTokenName());
 
@@ -47,8 +46,5 @@ public class MagicApiWebLoginInterceptor implements HandlerInterceptor {
             Object loginIdByToken = StpUtil.getLoginIdByToken(parameter);
             return !ObjectUtil.isNull(loginIdByToken);
         }
-
-
-
     }
 }

+ 45 - 0
src/main/java/com/xjrsoft/common/interceptor/RateLimitInterceptor.java

@@ -0,0 +1,45 @@
+package com.xjrsoft.common.interceptor;
+
+import cn.dev33.satoken.stp.StpUtil;
+import cn.hutool.core.convert.Convert;
+import com.xjrsoft.common.constant.GlobalConstant;
+import com.xjrsoft.common.enums.RoleEnum;
+import com.xjrsoft.common.utils.RedisUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.web.servlet.HandlerInterceptor;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.Map;
+
+@Component
+public class RateLimitInterceptor implements HandlerInterceptor {
+
+    @Autowired
+    private RedisUtil redisUtil;
+
+    @Override
+    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+        if (isLimiting()) {
+            // 暂停5秒
+            Thread.sleep(5000);
+            System.out.println("触发限流");
+        }
+        return true;
+    }
+
+    /**
+     * 是否满足限流条件
+     */
+    public boolean isLimiting() {
+        if (!StpUtil.isLogin()) return false;
+        Long userId = StpUtil.getLoginIdAsLong();
+        Long userType = Convert.toLong(StpUtil.getTokenSession().get(GlobalConstant.LOGIN_USER_TYPE), 0L);
+        if (userType.equals(RoleEnum.STUDENT.getCode())) {
+            Map map = redisUtil.get(GlobalConstant.WHITE_MANAGEMENT_CACHE_KEY, Map.class);
+            return map.get(userId.toString()) == null;
+        }
+        return false;
+    }
+}

+ 7 - 14
src/main/java/com/xjrsoft/common/runner/OrganizationCacheRunner.java

@@ -2,20 +2,9 @@ package com.xjrsoft.common.runner;
 
 import com.xjrsoft.common.constant.GlobalConstant;
 import com.xjrsoft.common.utils.RedisUtil;
-import com.xjrsoft.module.organization.entity.Department;
-import com.xjrsoft.module.organization.entity.Post;
-import com.xjrsoft.module.organization.entity.Role;
-import com.xjrsoft.module.organization.entity.User;
-import com.xjrsoft.module.organization.entity.UserDeptRelation;
-import com.xjrsoft.module.organization.entity.UserPostRelation;
-import com.xjrsoft.module.organization.entity.UserRoleRelation;
-import com.xjrsoft.module.organization.service.IDepartmentService;
-import com.xjrsoft.module.organization.service.IPostService;
-import com.xjrsoft.module.organization.service.IRoleService;
-import com.xjrsoft.module.organization.service.IUserDeptRelationService;
-import com.xjrsoft.module.organization.service.IUserPostRelationService;
-import com.xjrsoft.module.organization.service.IUserRoleRelationService;
-import com.xjrsoft.module.organization.service.IUserService;
+import com.xjrsoft.module.base.service.IWhitelistManagementService;
+import com.xjrsoft.module.organization.entity.*;
+import com.xjrsoft.module.organization.service.*;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.boot.CommandLineRunner;
@@ -50,6 +39,8 @@ public class OrganizationCacheRunner implements CommandLineRunner {
 
     private IUserPostRelationService userPostRelationService;
 
+    private IWhitelistManagementService whitelistManagementService;
+
     @Override
     public void run(String... args) {
         loadUserCache();
@@ -59,6 +50,8 @@ public class OrganizationCacheRunner implements CommandLineRunner {
         loadUserRoleRelationCache();
         loadUserDepartmentRelationCache();
         loadUserPostRelationCache();
+
+        whitelistManagementService.loadCaches();
     }
 
     @Async

+ 5 - 2
src/main/java/com/xjrsoft/common/utils/WeChatUtil.java

@@ -58,8 +58,11 @@ public class WeChatUtil {
     public String assessmentTemplate;
 
     //考勤结果通知模板
-    @Value("${xjrsoft.weChatMessageTemplate.attendanceMessageTemplate}")
-    public String attendanceMessageTemplate;
+    @Value("${xjrsoft.weChatMessageTemplate.attendanceMsgLateTemplate}")
+    public String attendanceMsgLateTemplate;
+
+    @Value("${xjrsoft.weChatMessageTemplate.attendanceMsgAbsenceTemplate}")
+    public String attendanceMsgAbsenceTemplate;
 
     @Value("${xjrsoft.weChatMessageTemplate.outInTemplate}")
     public String outInTemplate;

+ 4 - 6
src/main/java/com/xjrsoft/common/xss/XssFilter.java

@@ -1,21 +1,18 @@
 
 package com.xjrsoft.common.xss;
 
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
+import javax.servlet.*;
 import javax.servlet.http.HttpServletRequest;
 import java.io.IOException;
 
+
 /**
  * XSS过滤
  *
  * @author tzx
  */
 public class XssFilter implements Filter {
+
     @Override
     public void init(FilterConfig config) {
     }
@@ -32,4 +29,5 @@ public class XssFilter implements Filter {
     public void destroy() {
     }
 
+
 }

+ 7 - 0
src/main/java/com/xjrsoft/config/SaTokenConfig.java

@@ -16,6 +16,7 @@ import com.xjrsoft.common.constant.GlobalConstant;
 import com.xjrsoft.common.enums.ResponseCode;
 import com.xjrsoft.common.exception.MyException;
 import com.xjrsoft.common.interceptor.MagicApiWebLoginInterceptor;
+import com.xjrsoft.common.interceptor.RateLimitInterceptor;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
@@ -42,10 +43,16 @@ public class SaTokenConfig implements WebMvcConfigurer {
     public void addInterceptors(InterceptorRegistry registry) {
         // 注册MagicApi登录判断拦截器
         registry.addInterceptor(new MagicApiWebLoginInterceptor()).addPathPatterns(magicApiConfig.getWeb() + "/**");
+        // 注册拦截器
+        registry.addInterceptor(getRateLimitInterceptor()).addPathPatterns("/**");
         //satoken 注解鉴权拦截器
 //        registry.addInterceptor(new SaAnnotationInterceptor()).addPathPatterns("/**");
     }
 
+    @Bean
+    public RateLimitInterceptor getRateLimitInterceptor(){
+        return new RateLimitInterceptor();
+    }
 
     /**
      * 注册 [Sa-Token全局过滤器]

+ 8 - 11
src/main/java/com/xjrsoft/module/attendance/controller/StatisticsController.java

@@ -2,7 +2,6 @@ package com.xjrsoft.module.attendance.controller;
 
 import cn.dev33.satoken.annotation.SaCheckPermission;
 import cn.hutool.core.util.ObjectUtil;
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.github.yulichang.toolkit.MPJWrappers;
 import com.github.yulichang.wrapper.MPJLambdaWrapper;
 import com.xjrsoft.common.enums.OutInStatusEnum;
@@ -18,10 +17,10 @@ import com.xjrsoft.module.organization.entity.UserDeptRelation;
 import com.xjrsoft.module.outint.entity.CarOutInRecord;
 import com.xjrsoft.module.outint.entity.StudentOutInRecord;
 import com.xjrsoft.module.outint.entity.TeacherOutInRecord;
-import com.xjrsoft.module.outint.service.ICarOutInRecordService;
 import com.xjrsoft.module.outint.service.IStudentOutInRecordService;
 import com.xjrsoft.module.outint.service.ITeacherOutInRecordService;
 import com.xjrsoft.module.personnel.entity.CarMessageApply;
+import com.xjrsoft.module.personnel.service.ICarMessageApplyService;
 import com.xjrsoft.module.personnel.service.IReservationSchoolService;
 import com.xjrsoft.module.student.entity.BaseStudent;
 import com.xjrsoft.module.student.entity.BaseStudentSchoolRoll;
@@ -66,7 +65,7 @@ public class StatisticsController {
     private final IWfTeacherleaveService wfTeacherleaveService;
     private final IStudentLeaveService studentLeaveService;
     private final IReservationSchoolService reservationSchoolService;
-    private final ICarOutInRecordService carOutInRecordService;
+    private final ICarMessageApplyService carMessageApplyService;
 
     @GetMapping(value = "/teacher-statistics")
     @ApiOperation(value="教职工考勤统计")
@@ -110,10 +109,9 @@ public class StatisticsController {
                             .orderByAsc(TeacherOutInRecord::getRecordTime)
             );
 
-            List<CarOutInRecord> list = carOutInRecordService.list(
-                    new MPJLambdaWrapper<CarOutInRecord>()
-                            .select(CarOutInRecord.class, x -> VoToColumnUtil.fieldsToColumns(CarOutInRecord.class).contains(x.getProperty()))
-                            .leftJoin(CarMessageApply.class, CarMessageApply::getId, CarOutInRecord::getCarMessageApplyId)
+            long count = carMessageApplyService.count(
+                    new MPJLambdaWrapper<CarMessageApply>()
+                            .innerJoin(CarOutInRecord.class, CarOutInRecord::getCarMessageApplyId, CarMessageApply::getId)
                             .le(CarOutInRecord::getRecordTime, endTime)
                             .eq("DATE_FORMAT(record_time, '%Y-%m-%d')", endTime.toLocalDate())
                             .ge(dto.getTimePeriod() == 2 && amEndTime != null, CarOutInRecord::getRecordTime, amEndTime)
@@ -122,9 +120,8 @@ public class StatisticsController {
             );
 
             Set<Long> collect = outInRecords.stream().map(TeacherOutInRecord::getUserId).collect(Collectors.toSet());
-            Set<Long> userIds = new HashSet<>(collect);
             //实到人数
-            statisticsVo.setActualCount(Long.valueOf(collect.size()));
+            statisticsVo.setActualCount(Long.valueOf(collect.size()) + count);
 
             //查询教师请假人数
             Long leaveCount = wfTeacherleaveService.getLeaveCount(startTime, endTime);
@@ -133,7 +130,7 @@ public class StatisticsController {
             }
             statisticsVo.setLeaveCount(leaveCount);
             //通过考勤规则和实到人数信息,计算迟到的
-            userIds = new HashSet<>();
+            Set<Long> userIds = new HashSet<>();
             Long lateCount = 0L;
             for (TeacherOutInRecord outInRecord : outInRecords) {
                 if("迟到".equals(outInRecord.getAttendanceStatus()) && !userIds.contains(outInRecord.getUserId())){
@@ -208,7 +205,7 @@ public class StatisticsController {
             Set<Long> collect = outInRecords.stream().map(StudentOutInRecord::getUserId).collect(Collectors.toSet());
             statisticsVo.setActualCount(Long.valueOf(collect.size()));
 
-            //查询教师请假人数
+            //查询学生请假人数
             Long leaveCount = studentLeaveService.getLeaveCount(startTime, endTime, dto);
             if(leaveCount == null){
                 leaveCount = 0L;

+ 40 - 32
src/main/java/com/xjrsoft/module/attendance/controller/StudentStatisticsController.java

@@ -17,16 +17,15 @@ import com.xjrsoft.common.page.PageOutput;
 import com.xjrsoft.common.utils.VoToColumnUtil;
 import com.xjrsoft.module.attendance.dto.AttendanceStatisticDto;
 import com.xjrsoft.module.attendance.dto.StudentDetailsDto;
-import com.xjrsoft.module.attendance.service.IAttendanceRuleCategoryService;
 import com.xjrsoft.module.attendance.vo.ClassStatisticsVo;
 import com.xjrsoft.module.attendance.vo.StudentStatisticsPageVo;
+import com.xjrsoft.module.attendance.vo.TimeRangeVo;
 import com.xjrsoft.module.base.entity.BaseClass;
 import com.xjrsoft.module.base.service.IBaseClassService;
 import com.xjrsoft.module.holiday.entity.HolidayDate;
 import com.xjrsoft.module.holiday.service.IHolidayDateService;
 import com.xjrsoft.module.organization.entity.User;
 import com.xjrsoft.module.organization.service.IUserService;
-import com.xjrsoft.module.outint.entity.CarOutInRecord;
 import com.xjrsoft.module.outint.entity.StudentOutInRecord;
 import com.xjrsoft.module.outint.service.IStudentOutInRecordService;
 import com.xjrsoft.module.outint.vo.StudentOutInRecordVo;
@@ -77,7 +76,6 @@ public class StudentStatisticsController {
     private final IStudentLeaveService studentLeaveService;
     private final IBaseClassService classService;
     private final IHolidayDateService holidayDateService;
-    private final IAttendanceRuleCategoryService ruleCategoryService;
     private final IBaseClassService baseClassService;
     @GetMapping(value = "/class-statistics")
     @ApiOperation(value="班级考勤统计")
@@ -143,27 +141,20 @@ public class StudentStatisticsController {
                 record.setLeaveCount(leaveCount);
                 int actualCount = 0;
                 Set<Long> userIds = new HashSet<>();
+                Integer lateCount = 0, playTruantCount = 0;
                 for (StudentOutInRecordVo outInRecordVo : notStayMap.get(record.getId())) {
                     if(userIds.contains(outInRecordVo.getUserId())){
                         continue;
                     }
-                    actualCount ++;
-                    userIds.add(outInRecordVo.getUserId());
-                }
-                record.setActualCount(actualCount);
-
-                Integer lateCount = 0, playTruantCount = 0;
-                for (StudentOutInRecordVo outInRecord : notStayMap.get(record.getId())) {
-                    if(userIds.contains(outInRecord.getUserId())){
-                        continue;
-                    }
-                    if("迟到".equals(outInRecord.getAttendanceStatus())){
+                    if("迟到".equals(outInRecordVo.getAttendanceStatus())){
                         lateCount ++;
-                    }else if("旷课".equals(outInRecord.getAttendanceStatus())){
+                    }else if("旷课".equals(outInRecordVo.getAttendanceStatus())){
                         playTruantCount ++;
                     }
-                    userIds.add(outInRecord.getUserId());
+                    actualCount ++;
+                    userIds.add(outInRecordVo.getUserId());
                 }
+                record.setActualCount(actualCount);
                 record.setPlayTruantCount(playTruantCount);
                 record.setLateCount(lateCount);
 
@@ -293,41 +284,58 @@ public class StudentStatisticsController {
             DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE;
             LocalDateTime startTime = LocalDate.parse(dto.getStartTime(), formatter).atTime(0, 0, 0);
             LocalDateTime endTime = LocalDate.parse(dto.getEndTime(), formatter).atTime(23, 59, 59);
+            //如果查询天数只有一天
+            if(startTime.toLocalDate().isEqual(endTime.toLocalDate())){
+                HolidayDate holidayDate = holidayDateService.getOne(
+                        new QueryWrapper<HolidayDate>().lambda()
+                                .eq(HolidayDate::getDate, endTime.toLocalDate())
+                );
+                if(holidayDate != null && holidayDate.getWay() != null && holidayDate.getWay() != 0){
+                    return RT.ok(ConventPage.getPageOutput(attendancePage, ClassStatisticsVo.class));
+                }
+            }
 
 
             //查询每个班的走读生实到人数
             Map<Long, List<StudentOutInRecordVo>> notStayMap = studentOutInRecordService.getNotStayList(startTime, endTime, classIds);
             //查询住校生的实到情况
-            Map<Long, List<StudentOutInRecordVo>> stayMap = studentOutInRecordService.getStayList(startTime, endTime, classIds);
+//            Map<Long, List<StudentOutInRecordVo>> stayMap = studentOutInRecordService.getStayList(startTime, endTime, classIds);
 
             //查询各班的请假人数
-            Map<Long, Integer> classLeaveCount = studentLeaveService.getClassLeaveCount(startTime, endTime);
+            //Map<Long, Integer> classLeaveCount = studentLeaveService.getClassLeaveCount(startTime, endTime);
 
             //计算2个时间相差的天数
             long days = ChronoUnit.DAYS.between(startTime.toLocalDate(), endTime.toLocalDate());
             List<String> dayOfWeeks = new ArrayList<>();
+            List<TimeRangeVo> timeRangeList = new ArrayList<>();
             for (int i = 0; i <= days; i ++){
                 dayOfWeeks.add(startTime.plusDays(i).getDayOfWeek().name());
+                TimeRangeVo rangeVo = new TimeRangeVo();
+                rangeVo.setStartTime(startTime.plusDays(i));
+                rangeVo.setStartTime(startTime.plusDays(i).withHour(23).withMinute(59).withSecond(59));
+                timeRangeList.add(rangeVo);
             }
 
             for (ClassStatisticsVo record: attendancePage.getRecords()) {
-                record.setLeaveCount(classLeaveCount.get(record.getId()) == null ? 0:classLeaveCount.get(record.getId()));
-                Set<Long> collect = notStayMap.get(record.getId()).stream().map(StudentOutInRecordVo::getUserId).collect(Collectors.toSet());
+                //查询班级的请假总人次
+                Integer allLeaveCount = 0;
+                for (TimeRangeVo rangeVo : timeRangeList) {
+                    AttendanceStatisticDto statisticDto = new AttendanceStatisticDto();
+                    statisticDto.setClassId(record.getId());
+                    Long leaveCount = studentLeaveService.getLeaveCount(rangeVo.getStartTime(), rangeVo.getEndTime(), statisticDto);
+                    allLeaveCount += (leaveCount.intValue() * 3);
+                }
+                record.setLeaveCount(allLeaveCount);
+
+                List<Long> collect = notStayMap.get(record.getId()).stream().map(StudentOutInRecordVo::getUserId).collect(Collectors.toList());
 
                 record.setActualCount(collect.size());
                 record.setStudentCount(record.getStudentCount() * dayOfWeeks.size() * 3);
 
                 Integer lateCount = 0;
-                for (String dayOfWeek : dayOfWeeks) {
-                    for (StudentOutInRecordVo outInRecord : notStayMap.get(record.getId())) {
-                        if("迟到".equals(outInRecord.getAttendanceStatus())){
-                            lateCount ++;
-                        }
-                    }
-                    for (StudentOutInRecordVo outInRecord : stayMap.get(record.getId())) {
-                        if("迟到".equals(outInRecord.getAttendanceStatus())){
-                            lateCount ++;
-                        }
+                for (StudentOutInRecordVo outInRecord : notStayMap.get(record.getId())) {
+                    if("迟到".equals(outInRecord.getAttendanceStatus())){
+                        lateCount ++;
                     }
                 }
 
@@ -393,7 +401,7 @@ public class StudentStatisticsController {
 
                 Integer lateCount = 0;
                 for (StudentOutInRecordVo outInRecord : notStayMap.get(record.getId())) {
-                    if(outInRecord.getStatus() == 1){
+                    if(outInRecord.getStatus() == OutInStatusEnum.enter.getCode()){
                         continue;
                     }
                     if("迟到".equals(outInRecord.getAttendanceStatus())){
@@ -401,7 +409,7 @@ public class StudentStatisticsController {
                     }
                 }
                 for (StudentOutInRecordVo outInRecord : stayMap.get(record.getId())) {
-                    if(outInRecord.getStatus() == 1){
+                    if(outInRecord.getStatus() == OutInStatusEnum.enter.getCode()){
                         continue;
                     }
                     if("迟到".equals(outInRecord.getAttendanceStatus())){

+ 4 - 0
src/main/java/com/xjrsoft/module/attendance/controller/TeacherStatisticsController.java

@@ -12,6 +12,7 @@ import com.xjrsoft.common.page.ConventPage;
 import com.xjrsoft.common.page.PageOutput;
 import com.xjrsoft.common.utils.VoToColumnUtil;
 import com.xjrsoft.module.attendance.dto.TeacherDetailsDto;
+import com.xjrsoft.module.attendance.entity.AttendanceUserRelation;
 import com.xjrsoft.module.attendance.service.IAttendanceRuleCategoryService;
 import com.xjrsoft.module.attendance.vo.AttendanceRuleDetailsUserVo;
 import com.xjrsoft.module.attendance.vo.TeacherStatisticsPageVo;
@@ -76,6 +77,8 @@ public class TeacherStatisticsController {
         MPJLambdaWrapper<User> queryUser = new MPJLambdaWrapper<>();
         queryUser.disableSubLogicDel().distinct()
                 .eq(ObjectUtil.isNotNull(dto.getDeptId()), UserDeptRelation::getDeptId, dto.getDeptId())
+                .eq(StrUtil.isNotEmpty(dto.getAttendanceMode()), AttendanceUserRelation::getAttendanceMode, dto.getAttendanceMode())
+                .like(StrUtil.isNotEmpty(dto.getCarNumber()), AttendanceUserRelation::getCarNumber, dto.getCarNumber())
                 .like(StrUtil.isNotEmpty(dto.getName()), User::getName, dto.getName())
                 .selectAs(User::getName, TeacherStatisticsPageVo::getTeacherName)
                 .selectAs(User::getId, TeacherStatisticsPageVo::getUserId)
@@ -83,6 +86,7 @@ public class TeacherStatisticsController {
                 .selectAs(Department::getName, TeacherStatisticsPageVo::getDeptName)
                 .innerJoin(BaseTeacher.class, BaseTeacher::getUserId, User::getId)
                 .innerJoin(UserDeptRelation.class, UserDeptRelation::getUserId, User::getId)
+                .leftJoin(AttendanceUserRelation.class, AttendanceUserRelation::getUserId, User::getId)
                 .leftJoin(Department.class, Department::getId, UserDeptRelation::getDeptId);
         IPage<TeacherStatisticsPageVo> voIPage = xjrUserService.selectJoinListPage(ConventPage.getPage(dto), TeacherStatisticsPageVo.class, queryUser);
 

+ 6 - 0
src/main/java/com/xjrsoft/module/attendance/dto/TeacherDetailsDto.java

@@ -23,4 +23,10 @@ public class TeacherDetailsDto extends PageInput {
 
     @ApiModelProperty("部门id")
     private Long deptId;
+
+    @ApiModelProperty("考勤方式")
+    private String attendanceMode;
+
+    @ApiModelProperty("车牌号")
+    private String carNumber;
 }

+ 156 - 0
src/main/java/com/xjrsoft/module/base/controller/WhitelistManagementController.java

@@ -0,0 +1,156 @@
+package com.xjrsoft.module.base.controller;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.xjrsoft.common.constant.GlobalConstant;
+import com.baomidou.mybatisplus.core.toolkit.StringPool;
+import com.xjrsoft.common.page.ConventPage;
+import com.xjrsoft.common.page.PageOutput;
+import com.xjrsoft.common.model.result.RT;
+import com.xjrsoft.common.utils.VoToColumnUtil;
+import com.xjrsoft.module.base.dto.AddWhitelistManagementDto;
+import com.xjrsoft.module.base.dto.UpdateWhitelistManagementDto;
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import com.alibaba.excel.EasyExcel;
+import com.xjrsoft.module.base.entity.TreeNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.multipart.MultipartFile;
+import java.io.IOException;
+
+import com.xjrsoft.module.base.dto.WhitelistManagementPageDto;
+import com.xjrsoft.module.base.entity.WhitelistManagement;
+import com.xjrsoft.module.base.service.IWhitelistManagementService;
+import com.xjrsoft.module.base.vo.WhitelistManagementPageVo;
+
+import com.xjrsoft.module.base.vo.WhitelistManagementVo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.AllArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+* @title: 白名单管理
+* @Author brealinxx
+* @Date: 2024-06-24
+* @Version 1.0
+*/
+@RestController
+@RequestMapping("/base" + "/whitelistManagement")
+@Api(value = "/base"  + "/whitelistManagement",tags = "白名单管理代码")
+@AllArgsConstructor
+public class WhitelistManagementController {
+
+
+    private static final Logger log = LoggerFactory.getLogger(WhitelistManagementController.class);
+    private final IWhitelistManagementService whitelistManagementService;
+
+    @GetMapping(value = "/page")
+    @ApiOperation(value="白名单管理列表(分页)")
+    @SaCheckPermission("whitelistmanagement:detail")
+    public RT<PageOutput<WhitelistManagementPageVo>> page(@Valid WhitelistManagementPageDto dto){
+        Page<WhitelistManagementPageVo> page = whitelistManagementService.getPage(new Page<>(dto.getLimit(), dto.getSize()), dto);
+        PageOutput<WhitelistManagementPageVo> pageOutput = ConventPage.getPageOutput(page, WhitelistManagementPageVo.class);
+        return RT.ok(pageOutput);
+    }
+
+    @GetMapping(value = "/info")
+    @ApiOperation(value="根据id查询白名单管理信息")
+    @SaCheckPermission("whitelistmanagement:detail")
+    public RT<WhitelistManagementVo> info(@RequestParam Long id){
+        WhitelistManagement whitelistManagement = whitelistManagementService.getById(id);
+        if (whitelistManagement == null) {
+           return RT.error("找不到此数据!");
+        }
+        return RT.ok(BeanUtil.toBean(whitelistManagement, WhitelistManagementVo.class));
+    }
+
+
+    @PostMapping
+    @ApiOperation(value = "新增白名单管理")
+    @SaCheckPermission("whitelistmanagement:add")
+    public RT<Boolean> add(@Valid @RequestBody AddWhitelistManagementDto dto){
+        WhitelistManagement whitelistManagement = BeanUtil.toBean(dto, WhitelistManagement.class);
+        boolean isSuccess = whitelistManagementService.save(whitelistManagement);
+    return RT.ok(isSuccess);
+    }
+
+    @PutMapping
+    @ApiOperation(value = "修改白名单管理")
+    @SaCheckPermission("whitelistmanagement:edit")
+    public RT<Boolean> update(@Valid @RequestBody UpdateWhitelistManagementDto dto){
+
+        WhitelistManagement whitelistManagement = BeanUtil.toBean(dto, WhitelistManagement.class);
+        return RT.ok(whitelistManagementService.updateById(whitelistManagement));
+
+    }
+
+    @DeleteMapping
+    @ApiOperation(value = "删除白名单管理")
+    @SaCheckPermission("whitelistmanagement:delete")
+    public RT<Boolean> delete(@Valid @RequestBody List<Long> ids){
+        return RT.ok(whitelistManagementService.removeBatchByIds(ids));
+
+    }
+
+    @GetMapping("/structure")
+    @ApiOperation(value = "获取年级班级树结构")
+    public ResponseEntity<List<TreeNode>> getTreeStructure() {
+        List<TreeNode> treeStructure = whitelistManagementService.getTreeStructure();
+        return ResponseEntity.ok(treeStructure);
+    }
+
+    @PostMapping("/import")
+    @ApiOperation(value = "导入")
+    public RT<Boolean> importData(@RequestParam MultipartFile file) throws IOException {
+        List<WhitelistManagementPageVo> savedDataList = EasyExcel.read(file.getInputStream()).headRowNumber(3).head(WhitelistManagementPageVo.class).sheet().doReadSync();
+        List<WhitelistManagement> whitelistManagements = new ArrayList<>();
+        List<String> errorLogs = new ArrayList<>();
+
+        for (WhitelistManagementPageVo vo : savedDataList) {
+            try {
+                if (whitelistManagementService.checkExist(vo.getCredentialNumber())) continue;
+
+                String name = whitelistManagementService.GetName(vo.getName()).toString();
+                String credentialNumber = whitelistManagementService.GetCredentialNumber(vo.getCredentialNumber()).toString();
+                Long userId = whitelistManagementService.getUserId(credentialNumber);
+                Long phone = whitelistManagementService.GetPhone(Long.parseLong(vo.getPhone().toString()));
+
+                if (!name.isEmpty() && !credentialNumber.isEmpty() && !phone.toString().isEmpty()) {
+                    WhitelistManagement whitelistManagement = new WhitelistManagement();
+                    whitelistManagement.setCreateDate(new Date());
+                    whitelistManagement.setDeleteMark(0);
+                    whitelistManagement.setEnabledMark(0);
+                    whitelistManagement.setUserId(userId);
+                    whitelistManagement.setName(name);
+                    whitelistManagement.setCredentialNumber(credentialNumber);
+                    whitelistManagement.setPhone(phone);
+                    whitelistManagements.add(whitelistManagement);
+                }
+            } catch (Exception e) {
+                errorLogs.add(String.format("[意外错误(检查输入的是否正确且存在,输入错误可能返回 null)] 姓名: %s, 身份证: %s, 手机号: %s - 错误信息:%s", vo.getName(), vo.getCredentialNumber(), vo.getPhone(), e.getMessage()));
+            }
+        }
+
+        Boolean result = whitelistManagementService.saveBatch(whitelistManagements);
+        if (!errorLogs.isEmpty()) {
+            String detailedMessage = String.format("[导入完成但存在问题(检查输入的是否正确且存在,输入错误可能返回 null)] ", String.join("; ", errorLogs));
+            return RT.error(400, detailedMessage);
+        }
+
+        return RT.ok(result);
+    }
+
+}

+ 48 - 0
src/main/java/com/xjrsoft/module/base/dto/AddWhitelistManagementDto.java

@@ -0,0 +1,48 @@
+package com.xjrsoft.module.base.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import java.io.Serializable;
+import com.fasterxml.jackson.annotation.JsonFormat;
+
+import java.time.LocalTime;
+import java.time.LocalDateTime;
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.Date;
+
+
+
+/**
+* @title: 白名单管理
+* @Author brealinxx
+* @Date: 2024-06-24
+* @Version 1.0
+*/
+@Data
+public class AddWhitelistManagementDto implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+    * 用户id
+    */
+    @ApiModelProperty("用户id")
+    private Long userId;
+    /**
+    * 姓名
+    */
+    @ApiModelProperty("姓名")
+    private String name;
+    /**
+    * 身份证
+    */
+    @ApiModelProperty("身份证")
+    private String credentialNumber;
+    /**
+    * 手机号
+    */
+    @ApiModelProperty("手机号")
+    private Long phone;
+
+}

+ 32 - 0
src/main/java/com/xjrsoft/module/base/dto/UpdateWhitelistManagementDto.java

@@ -0,0 +1,32 @@
+package com.xjrsoft.module.base.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import java.io.Serializable;
+
+import java.time.LocalTime;
+import java.time.LocalDateTime;
+import java.math.BigDecimal;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import java.util.List;
+import java.util.Date;
+
+
+
+/**
+* @title: 白名单管理
+* @Author brealinxx
+* @Date: 2024-06-24
+* @Version 1.0
+*/
+@Data
+public class UpdateWhitelistManagementDto extends AddWhitelistManagementDto {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+    * 主键编号
+    */
+    @ApiModelProperty("主键编号")
+    private Long id;
+}

+ 40 - 0
src/main/java/com/xjrsoft/module/base/dto/WhitelistManagementPageDto.java

@@ -0,0 +1,40 @@
+package com.xjrsoft.module.base.dto;
+
+import com.tencentcloudapi.cam.v20190116.models.StrategyInfo;
+import com.xjrsoft.common.page.PageInput;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalTime;
+import java.time.LocalDateTime;
+import java.math.BigDecimal;
+import java.util.Date;
+
+
+/**
+* @title: 白名单管理分页查询入参
+* @Author brealinxx
+* @Date: 2024-06-24
+* @Version 1.0
+*/
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class WhitelistManagementPageDto extends PageInput {
+
+    @ApiModelProperty("学号")
+    private String credentialNumber;
+
+    @ApiModelProperty("姓名")
+    private String name;
+
+    @ApiModelProperty("手机号码")
+    private Long phone;
+
+    @ApiModelProperty("班级id")
+    private Long classId;
+
+    @ApiModelProperty("就读方式")
+    private String readWay;
+}

+ 12 - 0
src/main/java/com/xjrsoft/module/base/entity/TreeNode.java

@@ -0,0 +1,12 @@
+package com.xjrsoft.module.base.entity;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class TreeNode {
+    private String id;
+    private String name;
+    private List<TreeNode> children;
+}

+ 22 - 0
src/main/java/com/xjrsoft/module/base/entity/WhiteBaseClass.java

@@ -0,0 +1,22 @@
+package com.xjrsoft.module.base.entity;
+
+public class WhiteBaseClass {
+    private String id;
+    private String name;
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+}

+ 22 - 0
src/main/java/com/xjrsoft/module/base/entity/WhiteBaseGrade.java

@@ -0,0 +1,22 @@
+package com.xjrsoft.module.base.entity;
+
+public class WhiteBaseGrade {
+    private String id;
+    private String name;
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+}

+ 86 - 0
src/main/java/com/xjrsoft/module/base/entity/WhitelistManagement.java

@@ -0,0 +1,86 @@
+package com.xjrsoft.module.base.entity;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.github.yulichang.annotation.EntityMapping;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import java.io.Serializable;
+import java.time.LocalTime;
+import java.time.LocalDateTime;
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.Date;
+
+
+/**
+* @title: 白名单管理
+* @Author brealinxx
+* @Date: 2024-06-24
+* @Version 1.0
+*/
+@Data
+@TableName("whitelist_management")
+@ApiModel(value = "whitelist_management", description = "白名单管理")
+public class WhitelistManagement implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+    * 主键编号
+    */
+    @ApiModelProperty("主键编号")
+    @TableId
+    private Long id;
+    /**
+    * 创建时间
+    */
+    @ApiModelProperty("创建时间")
+    @TableField(fill = FieldFill.INSERT)
+    private Date createDate;
+    /**
+    * 修改时间
+    */
+    @ApiModelProperty("修改时间")
+    @TableField(fill = FieldFill.UPDATE)
+    private Date modifyDate;
+    /**
+    * 删除标记
+    */
+    @ApiModelProperty("删除标记")
+    @TableField(fill = FieldFill.INSERT)
+    @TableLogic
+    private Integer deleteMark;
+    /**
+    * 有效标志
+    */
+    @ApiModelProperty("有效标志")
+    @TableField(fill = FieldFill.INSERT)
+    private Integer enabledMark;
+    /**
+    * 用户id
+    */
+    @ApiModelProperty("用户id")
+    private Long userId;
+    /**
+    * 姓名
+    */
+    @ApiModelProperty("姓名")
+    private String name;
+    /**
+    * 身份证
+    */
+    @ApiModelProperty("身份证")
+    private String credentialNumber;
+    /**
+    * 手机号
+    */
+    @ApiModelProperty("手机号")
+    private Long phone;
+
+
+}

+ 45 - 0
src/main/java/com/xjrsoft/module/base/mapper/WhitelistManagementMapper.java

@@ -0,0 +1,45 @@
+package com.xjrsoft.module.base.mapper;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.github.yulichang.base.MPJBaseMapper;
+import com.xjrsoft.module.base.dto.WhitelistManagementPageDto;
+import com.xjrsoft.module.base.entity.BaseClass;
+import com.xjrsoft.module.base.entity.WhiteBaseClass;
+import com.xjrsoft.module.base.entity.WhiteBaseGrade;
+import com.xjrsoft.module.base.entity.WhitelistManagement;
+import com.xjrsoft.module.base.service.impl.WhitelistManagementServiceImpl;
+import com.xjrsoft.module.base.vo.WhitelistManagementPageVo;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+/**
+* @title: 白名单管理
+* @Author brealinxx
+* @Date: 2024-06-24
+* @Version 1.0
+*/
+@Mapper
+public interface WhitelistManagementMapper extends MPJBaseMapper<WhitelistManagement> {
+
+    Page<WhitelistManagementPageVo> getPage(Page<Object> objectPage, WhitelistManagementPageDto dto);
+
+    String getName(String name);
+
+    String getCredentialNumber(String credentialNumber);
+
+    Long getPhone(long phone);
+
+    Long getUserId(String credentialNumber);
+
+    boolean checkExits(String credentialNumber);
+
+    @Select("SELECT id, name FROM base_grade")
+    List<WhiteBaseGrade> getAllGrades();
+
+    @Select("SELECT id, name FROM base_class WHERE grade_id = #{gradeId}")
+    List<WhiteBaseClass> getClassesByGradeId(@Param("gradeId") String gradeId);
+}
+

+ 38 - 0
src/main/java/com/xjrsoft/module/base/service/IWhitelistManagementService.java

@@ -0,0 +1,38 @@
+package com.xjrsoft.module.base.service;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.github.yulichang.base.MPJBaseService;
+import com.xjrsoft.module.base.dto.WhitelistManagementPageDto;
+import com.xjrsoft.module.base.entity.TreeNode;
+import com.xjrsoft.module.base.entity.WhitelistManagement;
+import com.xjrsoft.module.base.vo.WhitelistManagementPageVo;
+
+import java.util.List;
+
+/**
+* @title: 白名单管理
+* @Author brealinxx
+* @Date: 2024-06-24
+* @Version 1.0
+*/
+
+public interface IWhitelistManagementService extends MPJBaseService<WhitelistManagement> {
+    Page<WhitelistManagementPageVo> getPage(Page<Object> objectPage, WhitelistManagementPageDto dto);
+
+    String GetName(String name);
+
+    String GetCredentialNumber(String credentialNumber);
+
+    Long GetPhone(long l);
+
+    Long getUserId(String credentialNumber);
+
+    boolean checkExist(String credentialNumber);
+
+    List<TreeNode> getTreeStructure();
+
+    /**
+     * 所有学生电信开卡用户缓存
+     */
+    void loadCaches();
+}

+ 108 - 0
src/main/java/com/xjrsoft/module/base/service/impl/WhitelistManagementServiceImpl.java

@@ -0,0 +1,108 @@
+package com.xjrsoft.module.base.service.impl;
+
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.github.yulichang.base.MPJBaseServiceImpl;
+import com.xjrsoft.common.constant.GlobalConstant;
+import com.xjrsoft.common.utils.RedisUtil;
+import com.xjrsoft.module.base.dto.WhitelistManagementPageDto;
+import com.xjrsoft.module.base.entity.TreeNode;
+import com.xjrsoft.module.base.entity.WhiteBaseClass;
+import com.xjrsoft.module.base.entity.WhiteBaseGrade;
+import com.xjrsoft.module.base.entity.WhitelistManagement;
+import com.xjrsoft.module.base.mapper.WhitelistManagementMapper;
+import com.xjrsoft.module.base.service.IWhitelistManagementService;
+import com.xjrsoft.module.base.vo.WhitelistManagementPageVo;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+* @title: 白名单管理
+* @Author brealinxx
+* @Date: 2024-06-24
+* @Version 1.0
+*/
+@Slf4j
+@Service
+@AllArgsConstructor
+public class WhitelistManagementServiceImpl extends MPJBaseServiceImpl<WhitelistManagementMapper, WhitelistManagement> implements IWhitelistManagementService {
+    private final WhitelistManagementMapper whitelistManagementMapper;
+
+    private RedisUtil redisUtil;
+
+    @Override
+    public Page<WhitelistManagementPageVo> getPage(Page<Object> objectPage, WhitelistManagementPageDto dto) {
+        return whitelistManagementMapper.getPage(objectPage, dto);
+    }
+
+    @Override
+    public String GetName(String name) {
+        return whitelistManagementMapper.getName(name);
+    }
+
+    @Override
+    public String GetCredentialNumber(String credentialNumber) {
+        return whitelistManagementMapper.getCredentialNumber(credentialNumber);
+    }
+
+    @Override
+    public Long GetPhone(long phone) {
+        return whitelistManagementMapper.getPhone(phone);
+    }
+
+    @Override
+    public Long getUserId(String credentialNumber) {
+        return whitelistManagementMapper.getUserId(credentialNumber);
+    }
+
+    @Override
+    public boolean checkExist(String credentialNumber) {
+        return whitelistManagementMapper.checkExits(credentialNumber);
+    }
+
+    @Override
+    public List<TreeNode> getTreeStructure() {
+        List<WhiteBaseGrade> grades = whitelistManagementMapper.getAllGrades();
+        List<TreeNode> treeNodes = new ArrayList<>();
+
+        for (WhiteBaseGrade grade : grades) {
+            TreeNode gradeNode = new TreeNode();
+            gradeNode.setId(grade.getId());
+            gradeNode.setName(grade.getName());
+
+            List<WhiteBaseClass> classes = whitelistManagementMapper.getClassesByGradeId(grade.getId());
+            List<TreeNode> classNodes = new ArrayList<>();
+
+            for (WhiteBaseClass clazz : classes) {
+                TreeNode classNode = new TreeNode();
+                classNode.setId(clazz.getId());
+                classNode.setName(clazz.getName());
+                classNodes.add(classNode);
+            }
+
+            gradeNode.setChildren(classNodes);
+            treeNodes.add(gradeNode);
+        }
+
+        return treeNodes;
+    }
+
+    /**
+     * 所有学生电信开卡用户缓存
+     */
+    @Async
+    public void loadCaches() {
+        log.info("XJRSOFT: 加载所有学生电信开卡用户缓存开始");
+        List<WhitelistManagement> list = whitelistManagementMapper.selectList(Wrappers.<WhitelistManagement>query().lambda().select(WhitelistManagement::getUserId));
+        Map<Long, Long> map = list.stream().collect(Collectors.toMap(WhitelistManagement::getUserId, WhitelistManagement::getUserId));
+        redisUtil.set(GlobalConstant.WHITE_MANAGEMENT_CACHE_KEY, map);
+        log.info("XJRSOFT: 加载所有学生电信开卡用户缓存结束");
+    }
+}

+ 98 - 0
src/main/java/com/xjrsoft/module/base/vo/WhitelistManagementPageVo.java

@@ -0,0 +1,98 @@
+package com.xjrsoft.module.base.vo;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.alibaba.excel.annotation.ExcelIgnore;
+import com.alibaba.excel.annotation.write.style.ContentStyle;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import com.xjrsoft.common.annotation.Trans;
+import com.xjrsoft.common.enums.TransType;
+import java.time.LocalTime;
+import java.time.LocalDateTime;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+* @title: 白名单管理分页列表出参
+* @Author brealinxx
+* @Date: 2024-06-24
+* @Version 1.0
+*/
+@Data
+public class WhitelistManagementPageVo {
+
+    /**
+    * 主键编号
+    */
+    @ContentStyle(dataFormat = 49)
+    @ApiModelProperty("主键编号")
+    private String id;
+    /**
+    * 创建时间
+    */
+    @ContentStyle(dataFormat = 49)
+    @ApiModelProperty("创建时间")
+    private Date createDate;
+    /**
+    * 修改时间
+    */
+    @ContentStyle(dataFormat = 49)
+    @ApiModelProperty("修改时间")
+    private Date modifyDate;
+    /**
+    * 删除标记
+    */
+    @ContentStyle(dataFormat = 49)
+    @ApiModelProperty("删除标记")
+    private Integer deleteMark;
+    /**
+    * 有效标志
+    */
+    @ContentStyle(dataFormat = 49)
+    @ApiModelProperty("有效标志")
+    private Integer enabledMark;
+    /**
+    * 用户id
+    */
+    @ContentStyle(dataFormat = 49)
+    @ApiModelProperty("用户id")
+    private Long userId;
+    /**
+    * 姓名
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("姓名")
+    @ApiModelProperty("姓名")
+    private String name;
+    /**
+    * 身份证
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("身份证")
+    @ApiModelProperty("身份证")
+    private String credentialNumber;
+    /**
+    * 手机号
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("手机号")
+    @ApiModelProperty("手机号")
+    private Long phone;
+
+    @ApiModelProperty("性别")
+    private String gender;
+
+    @ApiModelProperty("班级id")
+    private Long classId;
+
+    @ApiModelProperty("班级名称")
+    private String className;
+
+    @ApiModelProperty("就读方式")
+    private String readWay;
+
+    @ApiModelProperty("班主任")
+    private String teacher;
+}

+ 49 - 0
src/main/java/com/xjrsoft/module/base/vo/WhitelistManagementVo.java

@@ -0,0 +1,49 @@
+package com.xjrsoft.module.base.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.time.LocalTime;
+import java.time.LocalDateTime;
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.Date;
+
+/**
+* @title: 白名单管理表单出参
+* @Author brealinxx
+* @Date: 2024-06-24
+* @Version 1.0
+*/
+@Data
+public class WhitelistManagementVo {
+
+    /**
+    * 主键编号
+    */
+    @ApiModelProperty("主键编号")
+    private Long id;
+    /**
+    * 用户id
+    */
+    @ApiModelProperty("用户id")
+    private Long userId;
+    /**
+    * 姓名
+    */
+    @ApiModelProperty("姓名")
+    private String name;
+    /**
+    * 身份证
+    */
+    @ApiModelProperty("身份证")
+    private String credentialNumber;
+    /**
+    * 手机号
+    */
+    @ApiModelProperty("手机号")
+    private Long phone;
+
+
+
+}

+ 40 - 8
src/main/java/com/xjrsoft/module/hikvision/util/DataUtil.java

@@ -1,5 +1,6 @@
 package com.xjrsoft.module.hikvision.util;
 
+import cn.hutool.db.Entity;
 import com.google.gson.JsonArray;
 import com.google.gson.JsonElement;
 import com.google.gson.JsonObject;
@@ -12,7 +13,6 @@ import com.xjrsoft.module.hikvision.mapper.HikvisionDataMapper;
 import com.xjrsoft.module.organization.entity.Department;
 import com.xjrsoft.module.personnel.entity.CarMessageApply;
 import com.xjrsoft.module.system.entity.DictionaryDetail;
-import com.xjrsoft.module.teacher.mapper.FaceImportMapper;
 import lombok.extern.slf4j.Slf4j;
 import lombok.var;
 
@@ -287,8 +287,9 @@ public class DataUtil {
             paramJson.addProperty("birthday", objectMap.get("birthday")==null?"":objectMap.get("birthday").toString());
             paramJson.addProperty("personType", 2);
 
-            int gender;
-            switch (objectMap.get("gender").toString()) {
+            int gender = 0;
+            String genderData = objectMap.get("gender") == null ? "" : objectMap.get("gender").toString();
+            switch (genderData) {
                 case "SB10001":
                     gender = 1;
                     break;
@@ -406,12 +407,10 @@ public class DataUtil {
                 " WHERE t1.delete_mark = 0 AND t2.delete_mark = 0 AND t4.delete_mark = 0";
         List<Map<String, Object>> list = SqlRunnerAdapter.db().selectList(sql, String[].class);
         JsonArray paramArray = new JsonArray();
+        ApiUtil apiUtil = new ApiUtil();
         Map<Integer, String> clientMap = new HashMap<>();
         for(int i = 0; i < list.size(); i ++){
             Map<String, Object> objectMap = list.get(i);
-            if(tableData != null && tableData.containsKey(objectMap.get("id").toString())){
-                continue;
-            }
             JsonObject paramJson = new JsonObject();
             paramJson.addProperty("clientId", i);
             paramJson.addProperty("personId", objectMap.get("id").toString());
@@ -423,7 +422,8 @@ public class DataUtil {
             paramJson.addProperty("personType", 1);
 
             int gender;
-            switch (objectMap.get("gender").toString()) {
+            String genderData = objectMap.get("gender") == null ? "" : objectMap.get("gender").toString();
+            switch (genderData) {
                 case "SB10001":
                     gender = 1;
                     break;
@@ -435,6 +435,11 @@ public class DataUtil {
                     break;
             }
             paramJson.addProperty("gender", gender);
+            if(tableData != null && tableData.containsKey(objectMap.get("id").toString())){
+                String apiPath = "/api/resource/v1/person/single/update";
+                apiUtil.doPost(apiPath, paramJson.toString(), null);
+                continue;
+            }
             paramArray.add(paramJson);
 
             clientMap.put(i, objectMap.get("id").toString());
@@ -443,7 +448,7 @@ public class DataUtil {
         String apiPath = "/api/resource/v1/person/batch/add";
         Map<String, String> idMap = new HashMap<>();
         JsonParser jsonParser = new JsonParser();
-        ApiUtil apiUtil = new ApiUtil();
+
         Map<String, String> header = new HashMap<>();
         header.put("tagId", "insert_teacher");
 
@@ -570,4 +575,31 @@ public class DataUtil {
 //        }
 //        db.executeBatch(sqls);
 //    };
+
+    /**
+     * 根据用用户id,删除海康人员信息
+     * @param userIds
+     */
+    public void deletePerson(List<Long> userIds){
+        String tableName = "hikvision_data";
+        Entity where = Entity.create(tableName);
+        where.set("source_id", userIds);
+
+        List<Map<String, Object>> maps = SqlRunnerAdapter.db().dynamicSelect(tableName, where);
+        if(maps.isEmpty()){
+            return;
+        }
+        String apiPath = "/api/resource/v1/person/batch/delete";
+        JsonArray personIds = new JsonArray();
+
+        for (Map<String, Object> map : maps) {
+            personIds.add(map.get("hikvision_id").toString());
+        }
+        ApiUtil apiUtil = new ApiUtil();
+
+        JsonObject param = new JsonObject();
+        param.add("personIds", personIds);
+        String result = apiUtil.doPost(apiPath, param.toString(), null);
+        log.info("海康人员删除:param:" + param + ",result:" + result);
+    }
 }

+ 4 - 4
src/main/java/com/xjrsoft/module/hikvision/util/OutInRecordUtil.java

@@ -330,17 +330,17 @@ public class OutInRecordUtil {
                 }else{//进
                     if(recordTime.isBefore(amEndTime) && recordTime.isAfter(amStartTime)){
                         attendanceStatus = "迟到";
-                        if(recordTime.isAfter(amStartTime.plusMinutes(40))){
+                        if(recordTime.isAfter(amStartTime.plusMinutes(ruleDetails.getOverMinutes()))){
                             attendanceStatus = "旷课";
                         }
                     }else if(recordTime.isBefore(pmEndTime) && recordTime.isAfter(pmStartTime)){
                         attendanceStatus = "迟到";
-                        if(recordTime.isAfter(pmStartTime.plusMinutes(40))){
+                        if(recordTime.isAfter(pmStartTime.plusMinutes(ruleDetails.getOverMinutes()))){
                             attendanceStatus = "旷课";
                         }
                     }else if(recordTime.isBefore(eveningEndTime) && recordTime.isAfter(eveningStartTime)){
                         attendanceStatus = "迟到";
-                        if(recordTime.isAfter(eveningStartTime.plusMinutes(40))){
+                        if(recordTime.isAfter(eveningStartTime.plusMinutes(ruleDetails.getOverMinutes()))){
                             attendanceStatus = "旷课";
                         }
                     }else{
@@ -599,7 +599,7 @@ public class OutInRecordUtil {
                     LocalDateTime recordTimeDate = LocalDateTime.parse(recordTimeStr, formatter);
                     String attendanceStatus = discernStudentStatus(recordTimeDate, status, Long.valueOf(idNum));
                     studentInsertRecord(Long.valueOf(idNum), faceImportMapper.GetTeacherIdByPersonId(Long.valueOf(idNum)),
-                            faceImportMapper.GetClassIdByPersonId(Long.valueOf(idNum)), ApiUtil.GetRedirectURL(extEventPictureURL), recordTimeStr, status,eventId, attendanceStatus);
+                            faceImportMapper.GetClassIdByPersonId(Long.valueOf(idNum)), ApiUtil.GetRedirectURL(extEventPictureURL), recordTimeStr, status, eventId, attendanceStatus);
                 }
             }
         } catch (Exception e) {

+ 52 - 33
src/main/java/com/xjrsoft/module/job/AttenDanceWarnNoticeTask.java

@@ -1,10 +1,11 @@
 package com.xjrsoft.module.job;
 
 import cn.hutool.core.util.IdUtil;
+import cn.hutool.db.Entity;
 import cn.hutool.extra.spring.SpringUtil;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.xjrsoft.common.utils.VoToColumnUtil;
+import com.xjrsoft.common.mybatis.SqlRunnerAdapter;
 import com.xjrsoft.common.utils.WeChatUtil;
 import com.xjrsoft.module.attendance.entity.AttendanceRuleDetails;
 import com.xjrsoft.module.attendance.entity.AttendanceUserRelation;
@@ -13,8 +14,6 @@ import com.xjrsoft.module.attendance.service.IAttendanceRuleCategoryService;
 import com.xjrsoft.module.concat.service.IXjrUserService;
 import com.xjrsoft.module.organization.dto.WeChatSendMessageDto;
 import com.xjrsoft.module.organization.service.IWeChatService;
-import com.xjrsoft.module.system.entity.WechatMessageLog;
-import com.xjrsoft.module.system.service.IWechatMessageLogService;
 import com.xjrsoft.module.teacher.entity.XjrUser;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -56,10 +55,7 @@ public class AttenDanceWarnNoticeTask {
     @Autowired
     private WeChatUtil weChatUtil;
 
-    @Autowired
-    private IWechatMessageLogService wechatMessageLogService;
-
-    @Scheduled(cron = "0 */5 * * * ?")
+    @Scheduled(cron = "0 */1 * * * ?")
     public void RefreshConnectionPool() {
         String active = SpringUtil.getActiveProfile();
         if("dev".equals(active)){
@@ -101,17 +97,18 @@ public class AttenDanceWarnNoticeTask {
 
         //获取最近的时间
         LocalDateTime recentlyTime = getRecentlyTime(ruleDetailsList, now);
-        if(recentlyTime.getHour() != now.getHour() && Math.abs(recentlyTime.getMinute() - now.getMinute()) <= 2){
+        long minute = Math.abs(ChronoUnit.MINUTES.between(now, recentlyTime));
+        if(minute >= 1){
             log.info("未到时间,不进行推送");
             return;
         }
         String wechatTemplate = weChatUtil.getAttenDanceWarnTemplate();
-        List<WechatMessageLog> list = wechatMessageLogService.list(
-                new QueryWrapper<WechatMessageLog>().lambda()
-                        .select(WechatMessageLog.class, x -> VoToColumnUtil.fieldsToColumns(WechatMessageLog.class).contains(x.getProperty()))
-                        .eq(WechatMessageLog::getSendTime, recentlyTime)
-                        .eq(WechatMessageLog::getTemplateId, wechatTemplate)
-        );
+//        List<WechatMessageLog> list = wechatMessageLogService.list(
+//                new QueryWrapper<WechatMessageLog>().lambda()
+//                        .select(WechatMessageLog.class, x -> VoToColumnUtil.fieldsToColumns(WechatMessageLog.class).contains(x.getProperty()))
+//                        .eq(WechatMessageLog::getSendTime, recentlyTime)
+//                        .eq(WechatMessageLog::getTemplateId, wechatTemplate)
+//        );
 //        if(!list.isEmpty()){//已经推送过,不再进行推送
 //            return;
 //        }
@@ -121,10 +118,6 @@ public class AttenDanceWarnNoticeTask {
         //判断所有当前时间下,哪几条规则需要进行提醒
         Map<Long, Integer> ruleDetailsJudgeMap = judgeExecuteNotice(now, ruleDetailsList, recentlyTime);
 
-        WechatMessageLog messageLog = new WechatMessageLog();
-        messageLog.setTemplateId(wechatTemplate);
-        messageLog.setSendTime(recentlyTime);
-
         List<XjrUser> userList = getUserList(allTodyRule.keySet());
         for (XjrUser xjrUser : userList) {
             AttendanceRuleDetails ruleDetails = allTodyRule.get(xjrUser.getId());
@@ -173,9 +166,13 @@ public class AttenDanceWarnNoticeTask {
 
         }
 
-        messageLog.setCreateDate(new Date());
-        messageLog.setContent("消息推送人数:" + userList.size());
-        wechatMessageLogService.save(messageLog);
+        String table = "wechat_message_log";
+        Entity entity = Entity.create(table);
+        entity.set("content", "消息推送人数:" + userList.size());
+        entity.set("create_date", new Date());
+        entity.set("template_id", wechatTemplate);
+        entity.set("send_time", recentlyTime);
+        SqlRunnerAdapter.db().dynamicInsert(table, entity);
 
     }
 
@@ -193,18 +190,22 @@ public class AttenDanceWarnNoticeTask {
                 if(ruleDetails.getAmStartTime() != null){
                     LocalDateTime amStartTime = judgeTime.with(ruleDetails.getAmStartTime().toLocalTime());
                     Long amBetween = Math.abs(ChronoUnit.MINUTES.between(judgeTime, amStartTime));
-                    if(recentlyTime.isEqual(amStartTime.plusMinutes(- ruleDetails.getAgoMinutes())) && amBetween >= ruleDetails.getAgoMinutes() - 1 && amBetween <= ruleDetails.getAgoMinutes() + 1){//相差分钟数小于0
+                    if(ruleDetails.getAgoMinutes() != null && recentlyTime.isEqual(amStartTime.plusMinutes(- ruleDetails.getAgoMinutes()))
+                            && amBetween >= ruleDetails.getAgoMinutes() - 1 && amBetween <= ruleDetails.getAgoMinutes() + 1){//相差分钟数小于0
                         result.put(ruleDetails.getId(), 1);
-                    }else if(recentlyTime.isEqual(amStartTime.plusMinutes(ruleDetails.getOverMinutes())) && amBetween >= ruleDetails.getOverMinutes() - 1 && amBetween <= ruleDetails.getOverMinutes() + 1){
+                    }else if(ruleDetails.getOverMinutes() != null && recentlyTime.isEqual(amStartTime.plusMinutes(ruleDetails.getOverMinutes()))
+                            && amBetween >= ruleDetails.getOverMinutes() - 1 && amBetween <= ruleDetails.getOverMinutes() + 1){
                         result.put(ruleDetails.getId(), 2);
                     }
                 }
                 if(ruleDetails.getPmStartTime() != null){
                     LocalDateTime pmStartTime = judgeTime.with(ruleDetails.getPmStartTime().toLocalTime());
                     Long pmBetween = Math.abs(ChronoUnit.MINUTES.between(judgeTime, pmStartTime));
-                    if(recentlyTime.isEqual(pmStartTime.plusMinutes(- ruleDetails.getAgoMinutes())) && pmBetween >= ruleDetails.getAgoMinutes() - 1 && pmBetween <= ruleDetails.getAgoMinutes() + 1){//相差分钟数小于0
+                    if(ruleDetails.getAgoMinutes() != null && recentlyTime.isEqual(pmStartTime.plusMinutes(- ruleDetails.getAgoMinutes()))
+                            && pmBetween >= ruleDetails.getAgoMinutes() - 1 && pmBetween <= ruleDetails.getAgoMinutes() + 1){//相差分钟数小于0
                         result.put(ruleDetails.getId(), 1);
-                    }else if(recentlyTime.isEqual(pmStartTime.plusMinutes(ruleDetails.getOverMinutes())) && pmBetween >= ruleDetails.getOverMinutes() - 1 && pmBetween <= ruleDetails.getOverMinutes() + 1){
+                    }else if(ruleDetails.getOverMinutes() != null && recentlyTime.isEqual(pmStartTime.plusMinutes(ruleDetails.getOverMinutes()))
+                            && pmBetween >= ruleDetails.getOverMinutes() - 1 && pmBetween <= ruleDetails.getOverMinutes() + 1){
                         result.put(ruleDetails.getId(), 2);
                     }
                 }
@@ -212,9 +213,11 @@ public class AttenDanceWarnNoticeTask {
                 if(ruleDetails.getEveningStartTime() != null){
                     LocalDateTime eveningStartTime = judgeTime.with(ruleDetails.getEveningStartTime().toLocalTime());
                     Long eveningBetween = Math.abs(ChronoUnit.MINUTES.between(judgeTime, eveningStartTime));
-                    if(recentlyTime.isEqual(eveningStartTime.plusMinutes(- ruleDetails.getAgoMinutes())) && eveningBetween >= ruleDetails.getAgoMinutes() - 1 && eveningBetween <= ruleDetails.getAgoMinutes() + 1){//相差分钟数小于0
+                    if(ruleDetails.getAgoMinutes() != null && recentlyTime.isEqual(eveningStartTime.plusMinutes(- ruleDetails.getAgoMinutes()))
+                            && eveningBetween >= ruleDetails.getAgoMinutes() - 1 && eveningBetween <= ruleDetails.getAgoMinutes() + 1){//相差分钟数小于0
                         result.put(ruleDetails.getId(), 1);
-                    }else if(recentlyTime.isEqual(eveningStartTime.plusMinutes(ruleDetails.getOverMinutes())) && eveningBetween >= ruleDetails.getOverMinutes() - 1 && eveningBetween <= ruleDetails.getOverMinutes() + 1){
+                    }else if(ruleDetails.getOverMinutes() != null && recentlyTime.isEqual(eveningStartTime.plusMinutes(ruleDetails.getOverMinutes()))
+                            && eveningBetween >= ruleDetails.getOverMinutes() - 1 && eveningBetween <= ruleDetails.getOverMinutes() + 1){
                         result.put(ruleDetails.getId(), 2);
                     }
                 }
@@ -249,19 +252,35 @@ public class AttenDanceWarnNoticeTask {
                     && ruleDetail.getIsAttendance() != null && ruleDetail.getIsAttendance() == 1){
                 if(ruleDetail.getAmStartTime() != null){
                     LocalDateTime amStartTime = now.with(ruleDetail.getAmStartTime().toLocalTime());
-                    result.add(amStartTime.plusMinutes(- ruleDetail.getAgoMinutes()));
-                    result.add(amStartTime.plusMinutes(ruleDetail.getOverMinutes()));
+                    if(ruleDetail.getAgoMinutes() != null){
+                        result.add(amStartTime.plusMinutes(- ruleDetail.getAgoMinutes()));
+                    }
+
+                    if(ruleDetail.getOverMinutes() != null){
+                        result.add(amStartTime.plusMinutes(ruleDetail.getOverMinutes()));
+                    }
+
                 }
                 if(ruleDetail.getPmStartTime() != null){
                     LocalDateTime pmStartTime = now.with(ruleDetail.getPmStartTime().toLocalTime());
-                    result.add(pmStartTime.plusMinutes(- ruleDetail.getAgoMinutes()));
-                    result.add(pmStartTime.plusMinutes(ruleDetail.getOverMinutes()));
+                    if(ruleDetail.getAgoMinutes() != null){
+                        result.add(pmStartTime.plusMinutes(- ruleDetail.getAgoMinutes()));
+                    }
+
+                    if(ruleDetail.getOverMinutes() != null){
+                        result.add(pmStartTime.plusMinutes(ruleDetail.getOverMinutes()));
+                    }
                 }
 
                 if(ruleDetail.getEveningStartTime() != null){
                     LocalDateTime eveningStartTime = now.with(ruleDetail.getEveningStartTime().toLocalTime());
-                    result.add(eveningStartTime.plusMinutes(- ruleDetail.getAgoMinutes()));
-                    result.add(eveningStartTime.plusMinutes(ruleDetail.getOverMinutes()));
+                    if(ruleDetail.getAgoMinutes() != null){
+                        result.add(eveningStartTime.plusMinutes(- ruleDetail.getAgoMinutes()));
+                    }
+
+                    if(ruleDetail.getOverMinutes() != null){
+                        result.add(eveningStartTime.plusMinutes(ruleDetail.getOverMinutes()));
+                    }
                 }
             }
         }

+ 118 - 48
src/main/java/com/xjrsoft/module/job/AttendanceMessageTask.java

@@ -100,38 +100,13 @@ public class AttendanceMessageTask {
             new QueryWrapper<HolidayDate>().lambda()
             .eq(HolidayDate::getDate, now.toLocalDate())
         );
-        if(holidayDate != null && holidayDate.getWay() != null && holidayDate.getWay() != 0){
+        if(holidayDate != null && holidayDate.getWay() != null && holidayDate.getWay() != 0 && holidayDate.getWay() != 2){
             log.info("非工作日,不需要提醒");
             return;
         }
         //查询今天的考勤规则
         List<AttendanceRuleDetails> ruleDetails = ruleCategoryService.getTodayRules();
-        //获取最近的时间
-        LocalDateTime recentlyTime = getRecentlyTime(ruleDetails, now);
-        if(now.isBefore(recentlyTime)){
-            log.info("未到时间,不需要提醒");
-            return;
-        }
-
-
-        String wechatTemplate = weChatUtil.getAttendanceMessageTemplate();
-        WechatMessageLog log = wechatMessageLogService.getOne(
-                new QueryWrapper<WechatMessageLog>().lambda()
-                        .select(WechatMessageLog.class, x -> VoToColumnUtil.fieldsToColumns(WechatMessageLog.class).contains(x.getProperty()))
-                        .eq(WechatMessageLog::getSendTime, recentlyTime)
-                        .eq(WechatMessageLog::getTemplateId, wechatTemplate)
-        );
-        if(log != null){//已经推送过,不再进行推送
-            return;
-        }
-
-        WechatMessageLog messageLog = new WechatMessageLog();
-        messageLog.setTemplateId(wechatTemplate);
-        messageLog.setSendTime(recentlyTime);
-
-        List<AttendanceMessageSet> list = messageSetService.list(
-                new QueryWrapper<AttendanceMessageSet>().lambda()
-        );
+        List<AttendanceMessageSet> list = messageSetService.list();
         //判断是上午还是下午
         Integer timePeriod = null;
         String timePeriodStr = null;
@@ -147,35 +122,81 @@ public class AttendanceMessageTask {
         }
 
         DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
-        String format = recentlyTime.format(formatter);
 
         int userCount = 0;
         Set<Integer> roleTypes = list.stream().map(AttendanceMessageSet::getRoleType).collect(Collectors.toSet());
-        Set<Long> setIds = list.stream().map(AttendanceMessageSet::getId).collect(Collectors.toSet());
 
         //查询需要通知的人
-        List<XjrUser> userList = userService.list(
-                new MPJLambdaWrapper<XjrUser>().distinct()
-                        .select(XjrUser::getId)
-                        .select(XjrUser.class, x -> VoToColumnUtil.fieldsToColumns(XjrUser.class).contains(x.getProperty()))
-                        .leftJoin(UserRoleRelation.class, UserRoleRelation::getUserId, XjrUser::getId)
-                        .leftJoin(AttendanceMessageUserRelation.class, AttendanceMessageUserRelation::getUserId, XjrUser::getId)
-                        .in(UserRoleRelation::getRoleId, roleTypes)
-                        .in(AttendanceMessageUserRelation::getAttendanceMessageSetId, setIds)
-        );
-
 
         for (AttendanceMessageSet messageSet : list) {
+            LocalDateTime recentlyTime = null;
+            String characterKey = "character_string18";
+            String wechatTemplate = weChatUtil.getAttendanceMsgLateTemplate();
+            if(messageSet.getMessageCategory() != null && messageSet.getMessageCategory() == 1){
+                wechatTemplate = weChatUtil.getAttendanceMsgLateTemplate();
+                characterKey = "character_string18";
+                //获取最近的时间
+                recentlyTime = getRecentlyTime(ruleDetails, now);
+                long minute = Math.abs(ChronoUnit.MINUTES.between(now, recentlyTime));
+                if(minute >= 1){
+                    log.info("未到时间,不进行推送");
+                    continue;
+                }
+                long count = wechatMessageLogService.count(
+                        new QueryWrapper<WechatMessageLog>().lambda()
+                                .eq(WechatMessageLog::getSendTime, recentlyTime)
+                                .eq(WechatMessageLog::getTemplateId, wechatTemplate)
+                );
+                if(count > 0){//已经推送过,不再进行推送
+                    log.info("已推送过,不进行推送");
+                    continue;
+                }
+            }else if(messageSet.getMessageCategory() != null && messageSet.getMessageCategory() == 3){
+                wechatTemplate = weChatUtil.getAttendanceMsgAbsenceTemplate();
+                recentlyTime = getRecentlyOverTime(ruleDetails, now);
+                characterKey = "character_string36";
+                long minute = Math.abs(ChronoUnit.MINUTES.between(now, recentlyTime));
+                if(minute >= 1){
+                    log.info("未到时间,不进行推送");
+                    continue;
+                }
+                long count = wechatMessageLogService.count(
+                        new QueryWrapper<WechatMessageLog>().lambda()
+                                .eq(WechatMessageLog::getSendTime, recentlyTime)
+                                .eq(WechatMessageLog::getTemplateId, wechatTemplate)
+                );
+                if(count > 0){//已经推送过,不再进行推送
+                    log.info("已推送过,不进行推送");
+                    continue;
+                }
+            }
+
             if(!messageSet.getTimePeriod().contains(timePeriod + "")){
                 continue;
             }
 
+            List<XjrUser> userList = userService.list(
+                    new MPJLambdaWrapper<XjrUser>().distinct()
+                            .select(XjrUser::getId)
+                            .select(XjrUser.class, x -> VoToColumnUtil.fieldsToColumns(XjrUser.class).contains(x.getProperty()))
+                            .leftJoin(UserRoleRelation.class, UserRoleRelation::getUserId, XjrUser::getId)
+                            .leftJoin(AttendanceMessageUserRelation.class, AttendanceMessageUserRelation::getUserId, XjrUser::getId)
+                            .in(UserRoleRelation::getRoleId, roleTypes)
+                            .eq(AttendanceMessageUserRelation::getAttendanceMessageSetId, messageSet.getId())
+            );
+
             //没有需要通知的,直接跳过
             if(userList.isEmpty()){
                 continue;
             }
+            if(recentlyTime == null){
+                continue;
+            }
+
+            String format = recentlyTime.format(formatter);
+
             userCount += userList.size();
-            if(messageSet.getRoleType() != null && messageSet.getRoleType() == 2){
+            if(messageSet.getRoleType() != null && messageSet.getRoleType() == 1){
                 //教师总人数
                 long teacherCout = userService.count(
                         new MPJLambdaWrapper<XjrUser>()
@@ -206,9 +227,10 @@ public class AttendanceMessageTask {
                 const23.put("value", timePeriodStr);
                 paramJson.put("const23", const23);
 
+                //迟到人数或者缺勤人数
                 JSONObject character_string18 = new JSONObject();
                 character_string18.put("value", teacherCout - collect.size());
-                paramJson.put("character_string18", character_string18);
+                paramJson.put(characterKey, character_string18);
 
                 JSONObject character_string16 = new JSONObject();
                 character_string16.put("value", teacherCout);
@@ -222,7 +244,7 @@ public class AttendanceMessageTask {
                     weChatSendMessageDto.setUserId(xjrUser.getOpenId());
                     weChatService.sendTemplateMessage(weChatSendMessageDto);
                 }
-            }else if(messageSet.getRoleType() != null && messageSet.getRoleType() == 3){
+            }else if(messageSet.getRoleType() != null && messageSet.getRoleType() == 2){
                 //教师总人数
                 long teacherCout = userService.count(
                         new MPJLambdaWrapper<XjrUser>()
@@ -236,11 +258,11 @@ public class AttendanceMessageTask {
                 );
 
                 WeChatSendMessageDto weChatSendMessageDto = new WeChatSendMessageDto();
-                weChatSendMessageDto.setTemplateId(weChatUtil.getAttendanceMessageTemplate());
+                weChatSendMessageDto.setTemplateId(wechatTemplate);
                 JSONObject paramJson = new JSONObject();
 
                 JSONObject thing6 = new JSONObject();
-                thing6.put("value", "教职工");
+                thing6.put("value", "学生");
                 paramJson.put("thing6", thing6);
 
                 JSONObject time11 = new JSONObject();
@@ -253,7 +275,7 @@ public class AttendanceMessageTask {
 
                 JSONObject character_string18 = new JSONObject();
                 character_string18.put("value", teacherCout - outInRecords);
-                paramJson.put("character_string18", character_string18);
+                paramJson.put(characterKey, character_string18);
 
                 JSONObject character_string16 = new JSONObject();
                 character_string16.put("value", teacherCout);
@@ -268,10 +290,15 @@ public class AttendanceMessageTask {
                     weChatService.sendTemplateMessage(weChatSendMessageDto);
                 }
             }
+
+            WechatMessageLog messageLog = new WechatMessageLog();
+            messageLog.setTemplateId(wechatTemplate);
+            messageLog.setSendTime(recentlyTime);
+
+            messageLog.setCreateDate(new Date());
+            messageLog.setContent("消息推送人数:" + userCount);
+            wechatMessageLogService.save(messageLog);
         }
-        messageLog.setCreateDate(new Date());
-        messageLog.setContent("消息推送人数:" + userCount);
-        wechatMessageLogService.save(messageLog);
     }
 
     LocalDateTime getRecentlyTime(List<AttendanceRuleDetails> ruleDetails, LocalDateTime now){
@@ -308,5 +335,48 @@ public class AttendanceMessageTask {
         return timeMap.get(collect.get(0));
     }
 
+    LocalDateTime getRecentlyOverTime(List<AttendanceRuleDetails> ruleDetails, LocalDateTime now){
+        List<LocalDateTime> result = new ArrayList<>();
+        for (AttendanceRuleDetails ruleDetail : ruleDetails) {
+            if(ruleDetail.getIsAllowInOutSchool() != null && ruleDetail.getIsAllowInOutSchool() == 1
+                    && ruleDetail.getIsAttendance() != null && ruleDetail.getIsAttendance() == 1){
+                if(ruleDetail.getAmStartTime() != null){
+                    LocalDateTime amStartTime = now.with(ruleDetail.getAmStartTime().toLocalTime());
+                    if(ruleDetail.getOverMinutes() != null){
+                        amStartTime.plusMinutes(ruleDetail.getOverMinutes());
+                    }
+                    result.add(amStartTime);
+                }
+                if(ruleDetail.getPmStartTime() != null){
+                    LocalDateTime pmStartTime = now.with(ruleDetail.getPmStartTime().toLocalTime());
+                    if(ruleDetail.getOverMinutes() != null){
+                        pmStartTime.plusMinutes(ruleDetail.getOverMinutes());
+                    }
+                    result.add(pmStartTime);
+                }
+
+                if(ruleDetail.getEveningStartTime() != null){
+                    LocalDateTime eveningStartTime = now.with(ruleDetail.getEveningStartTime().toLocalTime());
+                    if(ruleDetail.getOverMinutes() != null){
+                        eveningStartTime.plusMinutes(ruleDetail.getOverMinutes());
+                    }
+                    result.add(eveningStartTime);
+                }
+            }
+        }
+        if(result.isEmpty()){
+            return null;
+        }
+        Map<Long, LocalDateTime> timeMap = new HashMap<>();
+        for (LocalDateTime localDateTime : result) {
+            long between = ChronoUnit.SECONDS.between(now, localDateTime);
+            timeMap.put(Math.abs(between), localDateTime);
+        }
+        List<Long> collect = timeMap.keySet().stream().collect(Collectors.toList());
+        Collections.sort(collect, Long::compare);
+
+        return timeMap.get(collect.get(0));
+    }
+
 
 }

+ 0 - 3
src/main/java/com/xjrsoft/module/job/HikvisionBaseDataTask.java

@@ -6,7 +6,6 @@ import com.xjrsoft.common.utils.SqlRunnerAdapterUtil;
 import com.xjrsoft.module.hikvision.entity.HikvisionData;
 import com.xjrsoft.module.hikvision.mapper.HikvisionDataMapper;
 import com.xjrsoft.module.hikvision.util.DataUtil;
-import com.xjrsoft.module.teacher.mapper.FaceImportMapper;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.scheduling.annotation.Scheduled;
@@ -25,8 +24,6 @@ import java.util.Set;
 @Component
 @Slf4j
 public class HikvisionBaseDataTask {
-    @Autowired
-    private FaceImportMapper faceImportMapper;
 
     @Autowired
     private HikvisionDataMapper hikvisionDataMapper;

+ 1 - 1
src/main/java/com/xjrsoft/module/job/InsertOutInRecordTask.java

@@ -20,7 +20,7 @@ public class InsertOutInRecordTask {
 
     OutInRecordUtil out_in_recordUtil = new OutInRecordUtil();
 
-    @Scheduled(cron = "*/60 * * * * ?")
+    @Scheduled(cron = "* */60 * * * ?")
     public void RefreshConnectionPool() {
         String active = SpringUtil.getActiveProfile();
         if(!"prod".equals(active)){

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

@@ -33,6 +33,7 @@ import com.xjrsoft.module.base.entity.BaseClass;
 import com.xjrsoft.module.base.entity.BaseGrade;
 import com.xjrsoft.module.base.service.IBaseClassService;
 import com.xjrsoft.module.base.service.IBaseGradeService;
+import com.xjrsoft.module.hikvision.util.DataUtil;
 import com.xjrsoft.module.organization.dto.AddUserDto;
 import com.xjrsoft.module.organization.dto.BindOpenidDto;
 import com.xjrsoft.module.organization.dto.LoginResetPasswordDto;
@@ -409,6 +410,11 @@ public class UserController {
         List<String> processIds = historicProcessInstances.stream().map(HistoricProcessInstance::getId).collect(Collectors.toList());
         int myApplicationCount = 0;
         for (HistoricProcessInstance historicProcessInstance : historicProcessInstances) {
+            Long countByProcessId = workflowExecuteService.getCountByProcessId(historicProcessInstance.getId());
+            if(countByProcessId == 0L){
+                continue;
+
+            }
             if (!ObjectUtil.isNotNull(historicProcessInstance.getEndTime())) {
                 myApplicationCount ++;
             }
@@ -591,6 +597,9 @@ public class UserController {
         if (ids.contains(StpUtil.getLoginIdAsLong())) {
             R.error("当前登录账户不能删除!");
         }
+        //删除海康的用户信息
+        DataUtil dataUtil = new DataUtil();
+        dataUtil.deletePerson(ids);
         //删除时需要同时删除用户部门关联表和用户角色关联表和用户岗位关系表数据。
         return R.ok(userService.deleteBatch(ids));
     }

+ 4 - 0
src/main/java/com/xjrsoft/module/outint/controller/StudentOutInRecordController.java

@@ -100,6 +100,10 @@ public class StudentOutInRecordController {
             if(classList != null && !classList.isEmpty() &&  dto.getClassId() == null){
                 dto.setClassId(classList.get(0).getId());
             }
+
+            if((ObjectUtil.isNotNull(dto.getUserId()) && dto.getUserId() != 0)){
+                queryWrapper.eq(StudentOutInRecord::getUserId, dto.getUserId());
+            }
         }
         queryWrapper.eq((ObjectUtil.isNotNull(dto.getClassId()) && dto.getClassId() != 0), StudentOutInRecord::getClassId, dto.getClassId());
         IPage<StudentOutInRecordPageVo> page = studentOutInRecordService.selectJoinListPage(ConventPage.getPage(dto),StudentOutInRecordPageVo.class, queryWrapper);

+ 6 - 3
src/main/java/com/xjrsoft/module/personnel/controller/StundentFaceProcessController.java

@@ -26,12 +26,14 @@ import com.xjrsoft.common.utils.VoToColumnUtil;
 import com.xjrsoft.module.base.entity.BaseClass;
 import com.xjrsoft.module.base.service.IBaseClassService;
 import com.xjrsoft.module.base.vo.StudentClassVo;
+import com.xjrsoft.module.hikvision.mapper.HikvisionDataMapper;
 import com.xjrsoft.module.hikvision.util.ApiUtil;
 import com.xjrsoft.module.personnel.dto.AddStundentFaceProcessDto;
 import com.xjrsoft.module.personnel.dto.StundentFaceProcessPageDto;
 import com.xjrsoft.module.personnel.dto.UpdateStundentFaceProcessDto;
 import com.xjrsoft.module.personnel.entity.FaceManagement;
 import com.xjrsoft.module.personnel.entity.StundentFaceProcess;
+import com.xjrsoft.module.personnel.entity.TeacherFaceProcess;
 import com.xjrsoft.module.personnel.service.IFaceManagementService;
 import com.xjrsoft.module.personnel.service.IStundentFaceProcessService;
 import com.xjrsoft.module.personnel.vo.StundentFaceProcessPageVo;
@@ -89,7 +91,7 @@ public class StundentFaceProcessController {
     private final IFileService fileService;
     private final IFaceManagementService faceManagementService;
     private final IBaseClassService classService;
-
+    private final HikvisionDataMapper hikvisionDataMapper;
     @GetMapping(value = "/page")
     @ApiOperation(value="学生人脸信息审核列表(分页)")
     @SaCheckPermission("stundentfaceprocess:detail")
@@ -112,6 +114,7 @@ public class StundentFaceProcessController {
                         .select(StundentFaceProcess::getId,StundentFaceProcess::getUserId,StundentFaceProcess::getClassId,StundentFaceProcess::getFacePhoto)
                         .innerJoin(XjrUser.class,XjrUser::getId, StundentFaceProcess::getUserId)
                         .leftJoin(File.class,File::getFolderId,StundentFaceProcess::getFacePhoto)
+                        .leftJoin(FaceManagement.class,FaceManagement::getFileId, StundentFaceProcess::getFacePhoto)
                         .leftJoin(DictionaryDetail.class,DictionaryDetail::getCode,StundentFaceProcess::getGender, ext->ext.selectAs(DictionaryDetail::getName, StundentFaceProcessPageVo::getGender))
                         .leftJoin(BaseStudentSchoolRoll.class,BaseStudentSchoolRoll::getUserId,StundentFaceProcess::getUserId)
                         .leftJoin(DictionaryDetail.class,DictionaryDetail::getCode,BaseStudentSchoolRoll::getStduyStatus, ext->ext.selectAs(DictionaryDetail::getName, StundentFaceProcessPageVo::getStduyStatus))
@@ -160,7 +163,7 @@ public class StundentFaceProcessController {
     @ApiOperation(value = "删除学生人脸信息审核")
     @SaCheckPermission("stundentfaceprocess:delete")
     public RT<Boolean> delete(@Valid @RequestBody List<Long> ids){
-        return RT.ok(stundentFaceProcessService.removeBatchByIds(ids));
+        return RT.ok(stundentFaceProcessService.removeByIds(ids));
     }
 
     @PostMapping(value = "/batch-import")
@@ -302,7 +305,7 @@ public class StundentFaceProcessController {
 
                 //将人脸上传海康
                 JsonObject paramJson = new JsonObject();
-                paramJson.addProperty("personId", studentUser.getId());
+                paramJson.addProperty("personId", hikvisionDataMapper.getStudentHikvisionId(studentUser.getId()));
                 paramJson.addProperty("faceData", base64String);
 
                 Map<String, String> querys = new HashMap<>();

+ 20 - 4
src/main/java/com/xjrsoft/module/personnel/controller/TeacherFaceProcessController.java

@@ -96,6 +96,7 @@ public class TeacherFaceProcessController {
                 .select(TeacherFaceProcess::getId,TeacherFaceProcess::getUserId,TeacherFaceProcess::getDepId,TeacherFaceProcess::getFacePhoto)
                 .innerJoin(XjrUser.class,XjrUser::getId, TeacherFaceProcess::getUserId)
                 .leftJoin(File.class,File::getFolderId,TeacherFaceProcess::getFacePhoto)
+                .leftJoin(FaceManagement.class,FaceManagement::getFileId,TeacherFaceProcess::getFacePhoto)
                 .leftJoin(DictionaryDetail.class,DictionaryDetail::getCode,TeacherFaceProcess::getGender, ext->ext.selectAs(DictionaryDetail::getName, TeacherFaceProcessPageVo::getGender))
                 .selectAs(XjrUser::getName,TeacherFaceProcessPageVo::getName)
                 .select("t2.file_url AS face_photo_url,t1.user_name AS user_name,t1.mobile")
@@ -147,7 +148,7 @@ public class TeacherFaceProcessController {
     @ApiOperation(value = "删除人脸信息审核")
     @SaCheckPermission("teacherfaceprocess:delete")
     public RT<Boolean> delete(@Valid @RequestBody List<Long> ids){
-        return RT.ok(teacherFaceProcessService.removeBatchByIds(ids));
+        return RT.ok(teacherFaceProcessService.removeByIds(ids));
 
     }
 
@@ -350,9 +351,24 @@ public class TeacherFaceProcessController {
                 teacherFaceProcessService.updateById(process);
 
                 FaceManagement faceManagement = faceManagementMap.get(Long.parseLong(teacherUser.getId()));
-                faceManagement.setVerifyStatus(2);
-                faceManagement.setRegisterBase64(base64String);
-                faceManagementService.update(faceManagement);
+                if(faceManagement == null){
+                    faceManagement = new FaceManagement();
+                    faceManagement.setUserType(2L);
+                    faceManagement.setUserId(Long.parseLong(teacherUser.getId()));
+                    faceManagement.setFileId(folderId);
+                    faceManagement.setIdno(teacherUser.getCredentialNumber());
+                    faceManagement.setName(teacherUser.getName());
+                    faceManagement.setSyncStatus(1);
+                    faceManagement.setSex(teacherUser.getGender());
+                    faceManagement.setVerifyStatus(2);
+                    faceManagement.setRegisterBase64(base64String);
+                    faceManagementService.save(faceManagement);
+                }else{
+                    faceManagement.setVerifyStatus(2);
+                    faceManagement.setRegisterBase64(base64String);
+                    faceManagementService.update(faceManagement);
+                }
+
             }
         }
         return RT.ok(true);

+ 4 - 0
src/main/java/com/xjrsoft/module/personnel/service/IStundentFaceProcessService.java

@@ -3,6 +3,8 @@ package com.xjrsoft.module.personnel.service;
 import com.github.yulichang.base.MPJBaseService;
 import com.xjrsoft.module.personnel.entity.StundentFaceProcess;
 
+import java.util.List;
+
 /**
 * @title: 学生人脸信息审核
 * @Author dzx
@@ -11,4 +13,6 @@ import com.xjrsoft.module.personnel.entity.StundentFaceProcess;
 */
 
 public interface IStundentFaceProcessService extends MPJBaseService<StundentFaceProcess> {
+
+    Boolean removeByIds(List<Long> ids);
 }

+ 4 - 0
src/main/java/com/xjrsoft/module/personnel/service/ITeacherFaceProcessService.java

@@ -3,6 +3,8 @@ package com.xjrsoft.module.personnel.service;
 import com.github.yulichang.base.MPJBaseService;
 import com.xjrsoft.module.personnel.entity.TeacherFaceProcess;
 
+import java.util.List;
+
 /**
 * @title: 人脸信息审核
 * @Author dzx
@@ -11,4 +13,6 @@ import com.xjrsoft.module.personnel.entity.TeacherFaceProcess;
 */
 
 public interface ITeacherFaceProcessService extends MPJBaseService<TeacherFaceProcess> {
+
+    Boolean removeByIds(List<Long> ids);
 }

+ 48 - 0
src/main/java/com/xjrsoft/module/personnel/service/impl/StundentFaceProcessServiceImpl.java

@@ -1,12 +1,23 @@
 package com.xjrsoft.module.personnel.service.impl;
 
+import cn.dev33.satoken.stp.StpUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.github.yulichang.base.MPJBaseServiceImpl;
+import com.google.gson.JsonObject;
+import com.xjrsoft.common.enums.DeleteMark;
+import com.xjrsoft.module.hikvision.mapper.HikvisionDataMapper;
+import com.xjrsoft.module.hikvision.util.ApiUtil;
+import com.xjrsoft.module.personnel.entity.FaceManagement;
 import com.xjrsoft.module.personnel.entity.StundentFaceProcess;
 import com.xjrsoft.module.personnel.mapper.StundentFaceProcessMapper;
+import com.xjrsoft.module.personnel.service.IFaceManagementService;
 import com.xjrsoft.module.personnel.service.IStundentFaceProcessService;
 import lombok.AllArgsConstructor;
 import org.springframework.stereotype.Service;
 
+import java.util.Date;
+import java.util.List;
+
 /**
 * @title: 学生人脸信息审核
 * @Author dzx
@@ -16,4 +27,41 @@ import org.springframework.stereotype.Service;
 @Service
 @AllArgsConstructor
 public class StundentFaceProcessServiceImpl extends MPJBaseServiceImpl<StundentFaceProcessMapper, StundentFaceProcess> implements IStundentFaceProcessService {
+
+    private final HikvisionDataMapper hikvisionDataMapper;
+
+    private final IFaceManagementService faceManagementService;
+
+
+    //删除人脸后,移除海康那边的人脸
+    @Override
+    public Boolean removeByIds(List<Long> ids) {
+        List<StundentFaceProcess> list = this.baseMapper.selectBatchIds(ids);
+        ApiUtil apiUtil = new ApiUtil();
+        String apiPath = "/api/resource/v1/face/single/delete";
+        for (StundentFaceProcess process : list) {
+            String studentHikvisionId = hikvisionDataMapper.getStudentHikvisionId(process.getUserId());
+
+            JsonObject paramJson = new JsonObject();
+            paramJson.addProperty("faceId", studentHikvisionId);
+
+            String result = apiUtil.doPost(apiPath, paramJson.toString(), null);
+            process.setExamStatus(2);
+            process.setHikvisionResult(result);
+            process.setDeleteMark(DeleteMark.DELETED.getCode());
+            process.setModifyUserId(StpUtil.getLoginIdAsLong());
+            process.setModifyDate(new Date());
+            this.baseMapper.updateById(process);
+
+            FaceManagement faceManagement = faceManagementService.getOne(
+                    new QueryWrapper<FaceManagement>().lambda()
+                            .eq(FaceManagement::getUserId, process.getUserId())
+                            .eq(FaceManagement::getFileId, process.getFacePhoto())
+            );
+
+            faceManagement.setRegisterBase64(null);
+            faceManagementService.update(faceManagement);
+        }
+        return true;
+    }
 }

+ 47 - 0
src/main/java/com/xjrsoft/module/personnel/service/impl/TeacherFaceProcessServiceImpl.java

@@ -1,12 +1,23 @@
 package com.xjrsoft.module.personnel.service.impl;
 
+import cn.dev33.satoken.stp.StpUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.github.yulichang.base.MPJBaseServiceImpl;
+import com.google.gson.JsonObject;
+import com.xjrsoft.common.enums.DeleteMark;
+import com.xjrsoft.module.hikvision.mapper.HikvisionDataMapper;
+import com.xjrsoft.module.hikvision.util.ApiUtil;
+import com.xjrsoft.module.personnel.entity.FaceManagement;
 import com.xjrsoft.module.personnel.entity.TeacherFaceProcess;
 import com.xjrsoft.module.personnel.mapper.TeacherFaceProcessMapper;
+import com.xjrsoft.module.personnel.service.IFaceManagementService;
 import com.xjrsoft.module.personnel.service.ITeacherFaceProcessService;
 import lombok.AllArgsConstructor;
 import org.springframework.stereotype.Service;
 
+import java.util.Date;
+import java.util.List;
+
 /**
 * @title: 人脸信息审核
 * @Author dzx
@@ -16,4 +27,40 @@ import org.springframework.stereotype.Service;
 @Service
 @AllArgsConstructor
 public class TeacherFaceProcessServiceImpl extends MPJBaseServiceImpl<TeacherFaceProcessMapper, TeacherFaceProcess> implements ITeacherFaceProcessService {
+    private final HikvisionDataMapper hikvisionDataMapper;
+
+    private final IFaceManagementService faceManagementService;
+
+
+    //删除人脸后,移除海康那边的人脸
+    @Override
+    public Boolean removeByIds(List<Long> ids) {
+        List<TeacherFaceProcess> list = this.baseMapper.selectBatchIds(ids);
+        ApiUtil apiUtil = new ApiUtil();
+        String apiPath = "/api/resource/v1/face/single/delete";
+        for (TeacherFaceProcess process : list) {
+            String studentHikvisionId = hikvisionDataMapper.getStudentHikvisionId(process.getUserId());
+
+            JsonObject paramJson = new JsonObject();
+            paramJson.addProperty("faceId", studentHikvisionId);
+
+            String result = apiUtil.doPost(apiPath, paramJson.toString(), null);
+            process.setExamStatus(2);
+            process.setHikvisionResult(result);
+            process.setDeleteMark(DeleteMark.DELETED.getCode());
+            process.setModifyUserId(StpUtil.getLoginIdAsLong());
+            process.setModifyDate(new Date());
+            this.baseMapper.updateById(process);
+
+            FaceManagement faceManagement = faceManagementService.getOne(
+                    new QueryWrapper<FaceManagement>().lambda()
+                            .eq(FaceManagement::getUserId, process.getUserId())
+                            .eq(FaceManagement::getFileId, process.getFacePhoto())
+            );
+
+            faceManagement.setRegisterBase64(null);
+            faceManagementService.update(faceManagement);
+        }
+        return true;
+    }
 }

+ 4 - 0
src/main/java/com/xjrsoft/module/student/controller/StudentManagerController.java

@@ -26,6 +26,7 @@ import com.xjrsoft.module.base.entity.BaseGrade;
 import com.xjrsoft.module.base.service.IBaseClassService;
 import com.xjrsoft.module.base.service.IBaseGradeService;
 import com.xjrsoft.module.concat.service.IXjrUserService;
+import com.xjrsoft.module.hikvision.util.DataUtil;
 import com.xjrsoft.module.organization.entity.UserDeptRelation;
 import com.xjrsoft.module.organization.service.IUserDeptRelationService;
 import com.xjrsoft.module.room.service.IRoomBedService;
@@ -217,6 +218,9 @@ public class StudentManagerController {
     @ApiOperation(value = "删除")
     @SaCheckPermission("studentmanager:delete")
     public R delete(@Valid @RequestBody List<Long> ids) {
+        //删除海康的用户信息
+        DataUtil dataUtil = new DataUtil();
+        dataUtil.deletePerson(ids);
         return R.ok(studentManagerService.delete(ids));
     }
 

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

@@ -375,6 +375,9 @@ public class LoginServiceImpl implements ILoginService {
         //根据登录信息  将post  和 department 信息存入用户信息中
         tokenSession.set(GlobalConstant.LOGIN_USER_INFO_KEY, loginUser);
 
+        // 存入用户类型
+        tokenSession.set(GlobalConstant.LOGIN_USER_TYPE, result.getUserType());
+
         result.setToken(StpUtil.getTokenValue());
 
         // 判断是不是OAuth2

+ 4 - 0
src/main/java/com/xjrsoft/module/teacher/controller/TeacherbaseManagerController.java

@@ -14,6 +14,7 @@ import com.xjrsoft.common.model.result.R;
 import com.xjrsoft.common.page.ConventPage;
 import com.xjrsoft.common.page.PageOutput;
 import com.xjrsoft.common.utils.VoToColumnUtil;
+import com.xjrsoft.module.hikvision.util.DataUtil;
 import com.xjrsoft.module.organization.entity.UserDeptRelation;
 import com.xjrsoft.module.organization.service.IUserDeptRelationService;
 import com.xjrsoft.module.system.entity.DictionaryDetail;
@@ -140,6 +141,9 @@ public class TeacherbaseManagerController {
     @ApiOperation(value = "删除")
     @SaCheckPermission("teacherbasemanager:delete")
     public R delete(@Valid @RequestBody List<Long> ids){
+        //删除海康的用户信息
+        DataUtil dataUtil = new DataUtil();
+        dataUtil.deletePerson(ids);
         return R.ok(teacherbaseManagerService.delete(ids));
 
     }

+ 1 - 0
src/main/java/com/xjrsoft/module/workflow/service/IWorkflowExecuteService.java

@@ -459,4 +459,5 @@ public interface IWorkflowExecuteService {
 
     List<UserDefinedProcessRecordListVo> listAuditApproveRecord(ApproveRecordListDto dto);
 
+    Long getCountByProcessId(String processId);
 }

+ 9 - 0
src/main/java/com/xjrsoft/module/workflow/service/impl/WorkflowExecuteServiceImpl.java

@@ -13,6 +13,7 @@ import cn.hutool.core.util.StrUtil;
 import cn.hutool.db.Session;
 import cn.hutool.extra.spring.SpringUtil;
 import cn.hutool.json.JSONUtil;
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -6107,6 +6108,14 @@ public class WorkflowExecuteServiceImpl implements IWorkflowExecuteService {
         return userDefinedProcessRecordListVos;
     }
 
+    @Override
+    public Long getCountByProcessId(String processId) {
+        return xjrWorkflowExtraMapper.selectCount(
+                new QueryWrapper<WorkflowExtra>().lambda()
+                        .eq(WorkflowExtra::getProcessId, processId)
+        );
+    }
+
     /**
      * 获取上一节点信息
      * 分两种情况:

+ 2 - 1
src/main/resources/application-dev.yml

@@ -138,7 +138,8 @@ xjrsoft:
   weChatMessageTemplate:
     commonTemplate: qmpXORPM1Cocqn503Qa4OkNNQ0uxlj2-ed9m6uWO-v4
     assessmentTemplate: ehYfXni7exZUmt6dJX4Ukbm9ETarFfKLfXVYwNnjKMc
-    attendanceMessageTemplate: uPPJkWOSronnB_GJolcnajRSdnIf8GCoCk4c0v1szPA
+    attendanceMsgLateTemplate: o-KboOcqcJ3YpjPN2xwgM_NcjN-0yzwWlDDXYfTM0Q4 # 迟到消息
+    attendanceMsgAbsenceTemplate: uPPJkWOSronnB_GJolcnarbl8qosDvsadxl0qL_4jdQ # 缺勤
     outInTemplate: ERkMebHjsziZO6WBrlzsbENiEuRR4vrlhJw5LR4aDr8
     attenDanceWarnTemplate: Fg4AWVQRGernl0PiJQ8gRgCUFHEGZuizlClQNuVhqu4
   dingtalk:

+ 2 - 1
src/main/resources/application-pre.yml

@@ -118,7 +118,8 @@ xjrsoft:
   weChatMessageTemplate:
     commonTemplate: qmpXORPM1Cocqn503Qa4OkNNQ0uxlj2-ed9m6uWO-v4
     assessmentTemplate: ehYfXni7exZUmt6dJX4Ukbm9ETarFfKLfXVYwNnjKMc
-    attendanceMessageTemplate: o-KboOcqcJ3YpjPN2xwgM_NcjN-0yzwWlDDXYfTM0Q4
+    attendanceMsgLateTemplate: o-KboOcqcJ3YpjPN2xwgM_NcjN-0yzwWlDDXYfTM0Q4 # 迟到消息
+    attendanceMsgAbsenceTemplate: uPPJkWOSronnB_GJolcnarbl8qosDvsadxl0qL_4jdQ # 缺勤
     outInTemplate: ERkMebHjsziZO6WBrlzsbENiEuRR4vrlhJw5LR4aDr8
     attenDanceWarnTemplate: vdFsy-QUk5L56OmGgBsRC_RB-45qRTkLzMPQotV2A4Y
   appletWeChat:

+ 2 - 1
src/main/resources/application-prod.yml

@@ -114,7 +114,8 @@ xjrsoft:
   weChatMessageTemplate:
     commonTemplate: qmpXORPM1Cocqn503Qa4OkNNQ0uxlj2-ed9m6uWO-v4
     assessmentTemplate: ehYfXni7exZUmt6dJX4Ukbm9ETarFfKLfXVYwNnjKMc
-    attendanceMessageTemplate: uPPJkWOSronnB_GJolcnajRSdnIf8GCoCk4c0v1szPA
+    attendanceMsgLateTemplate: uPPJkWOSronnB_GJolcnajRSdnIf8GCoCk4c0v1szPA # 迟到消息
+    attendanceMsgAbsenceTemplate: uPPJkWOSronnB_GJolcnarbl8qosDvsadxl0qL_4jdQ # 缺勤
     outInTemplate: ERkMebHjsziZO6WBrlzsbENiEuRR4vrlhJw5LR4aDr8
     attenDanceWarnTemplate: Fg4AWVQRGernl0PiJQ8gRgCUFHEGZuizlClQNuVhqu4
   appletWeChat:

+ 82 - 0
src/main/resources/mapper/base/WhitelistManagement.xml

@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+                PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+                "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.xjrsoft.module.base.mapper.WhitelistManagementMapper">
+    <select id="getPage" parameterType="com.xjrsoft.module.base.dto.WhitelistManagementPageDto" resultType="com.xjrsoft.module.base.vo.WhitelistManagementPageVo">
+        SELECT t.id, t.credential_number as credentialNumber, t.name, t.phone,
+            CASE
+               WHEN t1.gender = 'SB1001' THEN '男'
+               WHEN t1.gender = 'SB1002' THEN '女'
+               ELSE '其他'
+            END AS gender, t3.name as className, t4.name as readWay, t5.name as teacher, t3.id as classId
+        from whitelist_management t
+        left JOIN xjr_user t1 ON t1.id = t.user_id
+        left join base_student_school_roll t2 on t2.user_id = t.user_id
+        left join base_class t3 on t3.id = t2.class_id
+        left join xjr_dictionary_detail t4 on t4.code = t2.stduy_status
+        left join xjr_user t5 ON t5.id = t3.teacher_id
+        WHERE t.delete_mark = 0
+        <if test="dto.credentialNumber != null and dto.credentialNumber != ''">
+            AND t.credential_number like concat('%', #{dto.credentialNumber}, '%')
+        </if>
+        <if test="dto.name != null and dto.name != ''">
+            AND t.name like concat('%', #{dto.name}, '%')
+        </if>
+        <if test="dto.phone != null">
+            AND t.phone = #{dto.phone}
+        </if>
+        <if test="dto.readWay != null">
+            AND t4.code like concat('%', #{dto.readWay}, '%')
+        </if>
+        <if test="dto.classId != null">
+            AND t3.id = #{dto.classId}
+        </if>
+    </select>
+
+    <select id="getName" resultType="java.lang.String">
+        select name
+        from xjr_user
+        where delete_mark = 0
+        <if test="name != null">
+            AND name = #{name}
+        </if>
+    </select>
+
+    <select id="getCredentialNumber" resultType="java.lang.String">
+        select credential_number
+        from xjr_user
+        where delete_mark = 0
+        <if test="credentialNumber != null">
+            AND credential_number = #{credentialNumber}
+        </if>
+    </select>
+
+    <select id="getPhone" resultType="java.lang.Long">
+        select mobile
+        from xjr_user
+        where delete_mark = 0
+        <if test="phone != null">
+            AND mobile = #{phone}
+        </if>
+    </select>
+
+    <select id="getUserId" resultType="java.lang.Long">
+        select id
+        from xjr_user
+        where delete_mark = 0
+        <if test="credentialNumber != null">
+            AND credential_number = #{credentialNumber}
+        </if>
+    </select>
+
+    <select id="checkExits" resultType="java.lang.Boolean">
+        select case when count(1) > 0 then true else false end
+        from whitelist_management
+        where delete_mark = 0
+        <if test="credentialNumber != null">
+            AND credential_number = #{credentialNumber}
+        </if>
+    </select>
+
+</mapper>

+ 11 - 3
src/main/resources/mapper/outin/StudentOutInRecordMapper.xml

@@ -15,7 +15,7 @@
         SELECT t1.class_id AS id,COUNT(t1.user_id) FROM student_out_in_record t1
         INNER JOIN base_student_school_roll t2 ON t1.user_id = t2.user_id
         WHERE t1.delete_mark = 0 AND t1.status = 0 AND t2.delete_mark = 0
-        AND t2.stduy_status = 'FB3001'
+        AND t2.stduy_status = 'FB3002'
         AND t1.record_time BETWEEN #{startTime} AND #{endTime}
         GROUP BY t1.class_id
     </select>
@@ -24,15 +24,23 @@
         SELECT t1.* FROM student_out_in_record t1
         INNER JOIN base_student_school_roll t2 ON t1.user_id = t2.user_id
         WHERE t1.delete_mark = 0 AND t2.delete_mark = 0
-        AND t2.stduy_status = 'FB3002'
+        AND t2.stduy_status = 'FB3001'
         AND t1.record_time BETWEEN #{startTime} AND #{endTime}
+        and DATE_FORMAT(t1.record_time, '%Y-%m-%d') not in (
+            SELECT holiday_date.date FROM holiday_date WHERE STATUS IN (0, 2) AND delete_status = 0
+            AND holiday_date.date BETWEEN DATE_FORMAT(#{startTime}, '%Y-%m-%d') AND DATE_FORMAT(#{endTime}, '%Y-%m-%d')
+        )
     </select>
     <select id="getStayList" resultType="com.xjrsoft.module.outint.vo.StudentOutInRecordVo">
         SELECT t1.* FROM student_out_in_record t1
         INNER JOIN base_student_school_roll t2 ON t1.user_id = t2.user_id
         WHERE t1.delete_mark = 0 AND t2.delete_mark = 0
-        AND t2.stduy_status = 'FB3001'
+        AND t2.stduy_status = 'FB3002'
         AND t1.record_time BETWEEN #{startTime} AND #{endTime}
+        and DATE_FORMAT(t1.record_time, '%Y-%m-%d') not in (
+            SELECT holiday_date.date FROM holiday_date WHERE STATUS IN (0, 2) AND delete_status = 0
+            AND holiday_date.date BETWEEN DATE_FORMAT(#{startTime}, '%Y-%m-%d') AND DATE_FORMAT(#{endTime}, '%Y-%m-%d')
+        )
     </select>
     <select id="getList" resultType="com.xjrsoft.module.outint.vo.StudentOutInRecordVo">
         SELECT t1.* FROM student_out_in_record t1

+ 1 - 1
src/main/resources/mapper/teacher/TeacherFaceImportMapper.xml

@@ -46,10 +46,10 @@
         select t.hikvision_id
         from hikvision_data t
         left join car_message_apply t1 on t1.user_id = t.source_id
+        where t1.status = 1
         <if test="id != null">
             and t1.id = #{id}
         </if>
-        and t1.status = 1
     </select>
 
     <select id="IsStudentTypeByPersonId" parameterType="long" resultType="java.lang.String">

+ 16 - 0
src/main/resources/sqlScript/20240531_sql.sql

@@ -0,0 +1,16 @@
+-- ----------------------------------------------
+-- 节假日
+-- ----------------------------------------------
+DROP TABLE IF EXISTS holiday_date;
+CREATE TABLE `holiday_date` (
+  `id` BIGINT NOT NULL COMMENT '主键编号',
+  `date` VARCHAR(20) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '日期yyyy-MM-dd',
+  `year` INT NOT NULL,
+  `month` INT NOT NULL,
+  `day` INT NOT NULL,
+  `status` INT DEFAULT '0' COMMENT '0=普通工作日 1=周末 2=需要补班的工作日 3=法定节假日',
+  `way` INT NOT NULL DEFAULT '1' COMMENT '方式 1=系统数据 2=用户数据',
+  `delete_status` INT NOT NULL DEFAULT '0' COMMENT '删除状态 0=正常 1=删除',
+  PRIMARY KEY (`id`) USING BTREE,
+  UNIQUE KEY `only` (`date`) USING BTREE
+) ENGINE=INNODB DEFAULT CHARSET=utf8mb3;

+ 123 - 0
src/main/resources/sqlScript/20240604_sql.sql

@@ -0,0 +1,123 @@
+-- ------------------------------------------------
+-- 班级课程
+-- ------------------------------------------------
+DROP TABLE IF EXISTS base_class_course;
+CREATE TABLE `base_class_course` (
+  `id` BIGINT NOT NULL,
+  `create_user_id` BIGINT DEFAULT NULL,
+  `create_date` DATETIME(3) DEFAULT NULL,
+  `modify_user_id` BIGINT DEFAULT NULL,
+  `modify_date` DATETIME(3) DEFAULT NULL,
+  `delete_mark` INT DEFAULT NULL,
+  `enabled_mark` INT DEFAULT NULL,
+  `sort_code` INT DEFAULT NULL,
+  `class_id` BIGINT DEFAULT NULL COMMENT '班级id(base_class)',
+  `course_id` BIGINT DEFAULT NULL COMMENT '课程id(base_course_subject)',
+  `textbook_id` BIGINT DEFAULT NULL COMMENT '教材id(textbook)',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='班级课程';
+
+-- ------------------------------------------------
+-- 教师奖项
+-- ------------------------------------------------
+DROP TABLE IF EXISTS teacher_award_item;
+CREATE TABLE `teacher_award_item` (
+  `id` BIGINT NOT NULL,
+  `create_user_id` BIGINT DEFAULT NULL,
+  `create_date` DATETIME(3) DEFAULT NULL,
+  `modify_user_id` BIGINT DEFAULT NULL,
+  `modify_date` DATETIME(3) DEFAULT NULL,
+  `delete_mark` INT DEFAULT NULL,
+  `enabled_mark` INT DEFAULT NULL,
+  `sort_code` INT DEFAULT NULL,
+  `name` VARCHAR(200) DEFAULT NULL COMMENT '奖项名称',
+  `is_thesis` INT DEFAULT NULL COMMENT '是否论文(1:是 0:否)',
+  `is_standard` INT DEFAULT NULL COMMENT '是否频分标准(1:是 0:否)',
+  `score` DECIMAL(6,2) DEFAULT NULL COMMENT '分数',
+  `parent_id` BIGINT DEFAULT NULL COMMENT '父级id',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='教师奖项';
+
+
+ALTER TABLE `teacher_award`   
+  ADD COLUMN `teacher_award_item_id` BIGINT NULL   COMMENT '奖项id(teacher_award_item)' AFTER `status`;
+  
+ALTER TABLE `xjr_user`   
+  CHANGE `avatar` `avatar` MEDIUMBLOB NULL   COMMENT '头像';
+  
+ALTER TABLE textbook
+    ADD use_type INT NULL COMMENT '使用类型(单位:学期)';
+
+ALTER TABLE `base_student_school_roll`   
+  ADD INDEX (`learn_status`);
+ALTER TABLE `xjr_dictionary_detail`   
+  ADD INDEX (`name`, `code`);
+
+DROP TABLE IF EXISTS `base_system_config`;
+CREATE TABLE `base_system_config`  (
+  `id` BIGINT NOT NULL,
+  `code` VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '编号',
+  `value` VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '值',
+  `remark` VARCHAR(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '说明',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE = INNODB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '系统参数配置' ROW_FORMAT = DYNAMIC;
+
+DROP TABLE IF EXISTS `base_user_student`;
+CREATE TABLE `base_user_student` (
+  `id` BIGINT NOT NULL COMMENT '主键',
+  `create_date` DATE DEFAULT NULL COMMENT '创建时间',
+  `modify_date` DATE DEFAULT NULL COMMENT '修改时间',
+  `user_id` BIGINT NOT NULL COMMENT '家长ID(xjr_user)',
+  `user_phone` VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '家长手机号',
+  `student_id` BIGINT NOT NULL COMMENT '学生ID(xjr_user)',
+  `student_nane` VARCHAR(255) DEFAULT NULL COMMENT '学生姓名',
+  `student_identity` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '学生身份证号',
+  `class_id` BIGINT DEFAULT NULL COMMENT '学生班级id(base_class)',
+  `teacher_id` BIGINT DEFAULT NULL COMMENT '学生班主任id(xjr_user)',
+  `status` INT DEFAULT NULL COMMENT '流程状态(0:审核中,1:通过,2:拒绝)',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='家长学生关联表';
+
+ALTER TABLE wf_textbook_subscription_item
+    ADD textbook_id BIGINT NULL COMMENT '教材id';
+ALTER TABLE wf_textbook_subscription
+    ADD subscription_method INT NULL COMMENT '征订方式(1:按班级征订 2:按教材征订)';
+
+ALTER TABLE `jianyue_data`   
+  CHANGE `source_id` `source_id` VARCHAR(100) NULL COMMENT '数据id';
+
+
+DROP TABLE IF EXISTS `teacher_award`;
+CREATE TABLE `teacher_award` (
+  `id` BIGINT NOT NULL COMMENT '主键编号',
+  `create_user_id` BIGINT DEFAULT NULL COMMENT '创建人',
+  `create_date` DATETIME DEFAULT NULL COMMENT '创建时间',
+  `modify_user_id` BIGINT DEFAULT NULL COMMENT '修改人',
+  `modify_date` DATETIME DEFAULT NULL COMMENT '修改时间',
+  `delete_mark` INT NOT NULL COMMENT '删除标记',
+  `enabled_mark` INT NOT NULL COMMENT '有效标志',
+  `sort_code` INT DEFAULT NULL COMMENT '序号',
+  `applicant_user_id` BIGINT DEFAULT NULL COMMENT '申请人',
+  `award_type` VARCHAR(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '获奖类型',
+  `award_level` VARCHAR(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '奖项级别',
+  `competition_name` VARCHAR(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '奖项名称',
+  `award_grade` VARCHAR(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '获奖等级',
+  `award_score` DECIMAL(6,2) DEFAULT NULL COMMENT '奖项分数',
+  `paper_name` VARCHAR(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '作品名称',
+  `issn` VARCHAR(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '国际标准刊号字',
+  `media_type` VARCHAR(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '媒体类型(期刊、图书、报纸、音像、论文集)',
+  `journal_name` VARCHAR(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '媒体名称',
+  `journal_number` VARCHAR(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '国内统一刊号CN',
+  `journal_level` VARCHAR(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '期刊级别(核心期刊、一般期刊、(校级、内部论文))',
+  `issue_date` DATE DEFAULT NULL COMMENT '发表时间',
+  `approval_user_id` BIGINT DEFAULT NULL COMMENT '审核人',
+  `remark` VARCHAR(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '备注',
+  `file_id` BIGINT DEFAULT NULL COMMENT '附件文件id',
+  `status` INT NOT NULL DEFAULT '0' COMMENT '状态(1:结束 0:未结束)',
+  `teacher_award_item_id` BIGINT DEFAULT NULL COMMENT '奖项id(teacher_award_item)',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='教师获奖登记';
+
+
+ALTER TABLE teacher_award
+    ADD whole_competition_name VARCHAR(256) NULL COMMENT '奖项名称全称';

+ 16 - 0
src/main/resources/sqlScript/20240618_sql.sql

@@ -0,0 +1,16 @@
+-- 给每个绑定考勤规则的用户增加考勤相关状态
+ALTER TABLE `attendance_user_relation`   
+  ADD COLUMN `attendance_status` VARCHAR(20) DEFAULT 0  NULL COMMENT '考勤状态' AFTER `attendance_rule_category_id`,
+  ADD COLUMN `attendance_time` DATETIME NULL   COMMENT '最新考勤时间' AFTER `attendance_status`;
+
+ALTER TABLE `attendance_user_relation`   
+  ADD COLUMN `attendance_mode` VARCHAR(20) DEFAULT 0  NULL COMMENT '考勤方式',
+  ADD COLUMN `car_number` VARCHAR(20) NULL COMMENT '车牌号' AFTER `attendance_mode`;
+
+
+ALTER TABLE wf_textbook_subscription_item
+    ADD instockroom_num INT DEFAULT 0 NULL COMMENT '当前征订任务征订项已经入库数量';
+ALTER TABLE wf_textbook_subscription_item
+    ADD alteration_type INT DEFAULT 0 NULL COMMENT '变更类型(0:未变更,1:变更征订数量,2:变更课程)';
+ALTER TABLE wf_textbook_subscription_item
+    CHANGE instockroom_num in_stockroom_num INT DEFAULT 0 NULL COMMENT '当前征订任务征订项已经入库数量';

+ 2 - 2
src/test/java/com/xjrsoft/module/job/AttendanceMessageTaskTest.java

@@ -158,7 +158,7 @@ class AttendanceMessageTaskTest {
         List<AttendanceRuleDetails> ruleDetails = ruleCategoryService.getTodayRules();
         //获取最近的时间
         LocalDateTime recentlyTime = getRecentlyTime(ruleDetails, now);
-        String wechatTemplate = weChatUtil.getAttendanceMessageTemplate();
+        String wechatTemplate = weChatUtil.getAttendanceMsgLateTemplate();
         WechatMessageLog log = wechatMessageLogService.getOne(
                 new QueryWrapper<WechatMessageLog>().lambda()
                         .select(WechatMessageLog.class, x -> VoToColumnUtil.fieldsToColumns(WechatMessageLog.class).contains(x.getProperty()))
@@ -272,7 +272,7 @@ class AttendanceMessageTaskTest {
                 );
 
                 WeChatSendMessageDto weChatSendMessageDto = new WeChatSendMessageDto();
-                weChatSendMessageDto.setTemplateId(weChatUtil.getAttendanceMessageTemplate());
+                weChatSendMessageDto.setTemplateId(weChatUtil.getAttenDanceWarnTemplate());
                 JSONObject paramJson = new JSONObject();
 
                 JSONObject thing6 = new JSONObject();

+ 33 - 13
src/test/java/com/xjrsoft/module/job/HikvisionBaseDataTaskTest.java

@@ -138,6 +138,14 @@ class HikvisionBaseDataTaskTest {
 //        selectResource(use);
     }
 
+    @Test
+    void selectPerson(){
+        String sql = "SELECT * FROM xjr_user WHERE id IN (\n" +
+                "SELECT source_id FROM hikvision_data WHERE hikvision_id LIKE '%-%' AND table_name = 'base_teacher'\n" +
+                ")";
+        List<Map<String, Object>> list = SqlRunnerAdapter.db().selectList(sql, String[].class);
+    }
+
     @Test
     void testCarInsert() throws Exception {
         outInRecordUtil.GetVehicleRecord(faceImportMapper);
@@ -290,26 +298,38 @@ class HikvisionBaseDataTaskTest {
     void selecAllPersonById() throws SQLException {
         String apiPath = "/api/resource/v2/person/advance/personList";
 
-        String sql = "SELECT * FROM xjr_user WHERE id IN (" +
-                " SELECT source_id FROM hikvision_data WHERE table_name IN( 'base_teacher','base_student')" +
-                " AND hikvision_id LIKE '%-%'" +
-                " )";
+        String sql = "SELECT t1.id, t1.name,t1.user_name,t2.dept_id FROM xjr_user t1\n" +
+                "INNER JOIN xjr_user_dept_relation t2 ON t1.id = t2.user_id\n" +
+                " WHERE t1.id IN (\n" +
+                "SELECT source_id FROM hikvision_data WHERE hikvision_id LIKE '%-%' AND table_name = 'base_teacher'\n" +
+                ")";
         List<Map<String, Object>> maps = SqlRunnerAdapter.db().selectList(sql);
         ApiUtil apiUtil = new ApiUtil();
-        JsonObject jsonObject = new JsonObject();
-        jsonObject.addProperty("pageNo", 1);
-        jsonObject.addProperty("pageSize", 500);
-        jsonObject.addProperty("personName", "彭兴玲");
-        String result = apiUtil.doPost(apiPath, jsonObject.toString(), null, null);
-        System.out.println(result);
 
+        Map<String, String> userInfoMap = new HashMap<>();
 
+        JsonParser parser = new JsonParser();
         for (Map<String, Object> map : maps) {
             String name = map.get("name").toString();
-
-
+            JsonObject jsonObject = new JsonObject();
+            jsonObject.addProperty("pageNo", 1);
+            jsonObject.addProperty("pageSize", 500);
+            jsonObject.addProperty("personName", name);
+            jsonObject.addProperty("orgIndexCodes", map.get("dept_id").toString());
+            String result = apiUtil.doPost(apiPath, jsonObject.toString(), null, null);
+            JsonObject asJsonObject = parser.parse(result).getAsJsonObject();
+            if("0".equals(asJsonObject.get("code").getAsString())){
+                JsonArray jsonArray = asJsonObject.get("data").getAsJsonObject().get("list").getAsJsonArray();
+                if(jsonArray.size() == 0){
+                    continue;
+                }
+                JsonObject object = jsonArray.get(0).getAsJsonObject();
+                if(name.equals(object.get("personName").getAsString()) && map.get("user_name").toString().equals(object.get("jobNo").getAsString())){
+                    userInfoMap.put(map.get("id").toString(), object.get("personId").getAsString());
+                }
+            }
         }
-
+        System.out.println(userInfoMap);
     }
 
     void selecAllPerson(Db db) throws SQLException {

+ 25 - 0
src/test/java/com/xjrsoft/xjrsoftboot/FreeMarkerGeneratorTest.java

@@ -3312,4 +3312,29 @@ public class FreeMarkerGeneratorTest {
 
         apiGeneratorService.generateCodes(params);
     }
+
+    @Test
+    public void gcWhiteListManagement() throws IOException {
+        List<TableConfig> tableConfigs = new ArrayList<>();
+        TableConfig mainTable = new TableConfig();
+        mainTable.setTableName("whitelist_management");//init_sql中的表名
+        mainTable.setIsMain(true);//是否是主表,一般默认为true
+        mainTable.setPkField(GlobalConstant.DEFAULT_PK);//设置主键
+        mainTable.setPkType(GlobalConstant.DEFAULT_PK_TYPE);//设置主键类型
+        tableConfigs.add(mainTable);
+
+        ApiGenerateCodesDto params = new ApiGenerateCodesDto();
+        params.setAuthor("brealinxx");//作者名称
+        params.setPackageName("base");//包名
+        params.setTableConfigs(tableConfigs);
+        params.setPage(true);//是否生成分页接口
+        params.setImport(true);//是否生成导入接口
+        params.setExport(false);//是否生成导出接口
+        params.setOutMainDir(true);//是否生成在主目录,前期测试可设置成false
+        params.setDs(ds);
+
+        IApiGeneratorService apiGeneratorService = new ApiGeneratorServiceImpl();
+
+        apiGeneratorService.generateCodes(params);
+    }
 }