Ver código fonte

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

大数据与最优化研究所 1 ano atrás
pai
commit
fd3cef0d48
100 arquivos alterados com 6875 adições e 78 exclusões
  1. 1 0
      pom.xml
  2. 48 0
      src/main/java/com/xjrsoft/common/enums/GenderIntEnum.java
  3. 23 0
      src/main/java/com/xjrsoft/common/utils/FileZipUtil.java
  4. 66 0
      src/main/java/com/xjrsoft/common/utils/HolidayUtil.java
  5. 11 1
      src/main/java/com/xjrsoft/common/utils/UploadUtil.java
  6. 26 0
      src/main/java/com/xjrsoft/config/HikvisionConfig.java
  7. 160 0
      src/main/java/com/xjrsoft/module/attendance/controller/AttendanceMessageSetController.java
  8. 10 3
      src/main/java/com/xjrsoft/module/attendance/controller/AttendanceRuleCategoryController.java
  9. 222 0
      src/main/java/com/xjrsoft/module/attendance/controller/StatisticsController.java
  10. 203 0
      src/main/java/com/xjrsoft/module/attendance/controller/StudentAttendanceRecordController.java
  11. 365 0
      src/main/java/com/xjrsoft/module/attendance/controller/StudentStatisticsController.java
  12. 126 0
      src/main/java/com/xjrsoft/module/attendance/controller/TeacherAttendanceRecordController.java
  13. 124 0
      src/main/java/com/xjrsoft/module/attendance/controller/TeacherStatisticsController.java
  14. 59 0
      src/main/java/com/xjrsoft/module/attendance/dto/AddAttendanceMessageSetDto.java
  15. 53 0
      src/main/java/com/xjrsoft/module/attendance/dto/AddAttendanceMessageUserRelationDto.java
  16. 58 0
      src/main/java/com/xjrsoft/module/attendance/dto/AddStudentAttendanceRecordDto.java
  17. 48 0
      src/main/java/com/xjrsoft/module/attendance/dto/AddTeacherAttendanceRecordDto.java
  18. 15 0
      src/main/java/com/xjrsoft/module/attendance/dto/AttendanceMessageSetDto.java
  19. 26 0
      src/main/java/com/xjrsoft/module/attendance/dto/AttendanceMessageSetPageDto.java
  20. 34 0
      src/main/java/com/xjrsoft/module/attendance/dto/AttendanceStatisticDto.java
  21. 37 0
      src/main/java/com/xjrsoft/module/attendance/dto/StudentAttendanceRecordClassPageDto.java
  22. 67 0
      src/main/java/com/xjrsoft/module/attendance/dto/StudentAttendanceRecordPageDto.java
  23. 29 0
      src/main/java/com/xjrsoft/module/attendance/dto/StudentDetailsDto.java
  24. 69 0
      src/main/java/com/xjrsoft/module/attendance/dto/TeacherAttendanceRecordPageDto.java
  25. 26 0
      src/main/java/com/xjrsoft/module/attendance/dto/TeacherDetailsDto.java
  26. 44 0
      src/main/java/com/xjrsoft/module/attendance/dto/UpdateAttendanceMessageSetDto.java
  27. 32 0
      src/main/java/com/xjrsoft/module/attendance/dto/UpdateStudentAttendanceRecordDto.java
  28. 32 0
      src/main/java/com/xjrsoft/module/attendance/dto/UpdateTeacherAttendanceRecordDto.java
  29. 110 0
      src/main/java/com/xjrsoft/module/attendance/entity/AttendanceMessageSet.java
  30. 109 0
      src/main/java/com/xjrsoft/module/attendance/entity/AttendanceMessageSet.java.1716253865126.bak
  31. 103 0
      src/main/java/com/xjrsoft/module/attendance/entity/AttendanceMessageUserRelation.java
  32. 103 0
      src/main/java/com/xjrsoft/module/attendance/entity/AttendanceMessageUserRelation.java.1716253865128.bak
  33. 3 0
      src/main/java/com/xjrsoft/module/attendance/entity/AttendanceRuleDetails.java
  34. 108 0
      src/main/java/com/xjrsoft/module/attendance/entity/StudentAttendanceRecord.java
  35. 102 0
      src/main/java/com/xjrsoft/module/attendance/entity/TeacherAttendanceRecord.java
  36. 17 0
      src/main/java/com/xjrsoft/module/attendance/mapper/AttendanceMessageSetMapper.java
  37. 17 0
      src/main/java/com/xjrsoft/module/attendance/mapper/AttendanceMessageUserRelationMapper.java
  38. 9 0
      src/main/java/com/xjrsoft/module/attendance/mapper/AttendanceRuleDetailsMapper.java
  39. 17 0
      src/main/java/com/xjrsoft/module/attendance/mapper/StudentAttendanceRecordMapper.java
  40. 17 0
      src/main/java/com/xjrsoft/module/attendance/mapper/TeacherAttendanceRecordMapper.java
  41. 49 0
      src/main/java/com/xjrsoft/module/attendance/service/IAttendanceMessageSetService.java
  42. 17 0
      src/main/java/com/xjrsoft/module/attendance/service/IAttendanceRuleCategoryService.java
  43. 17 0
      src/main/java/com/xjrsoft/module/attendance/service/IStudentAttendanceRecordService.java
  44. 17 0
      src/main/java/com/xjrsoft/module/attendance/service/ITeacherAttendanceRecordService.java
  45. 113 0
      src/main/java/com/xjrsoft/module/attendance/service/impl/AttendanceMessageSetServiceImpl.java
  46. 75 0
      src/main/java/com/xjrsoft/module/attendance/service/impl/AttendanceRuleCategoryServiceImpl.java
  47. 25 0
      src/main/java/com/xjrsoft/module/attendance/service/impl/StudentAttendanceRecordServiceImpl.java
  48. 25 0
      src/main/java/com/xjrsoft/module/attendance/service/impl/TeacherAttendanceRecordServiceImpl.java
  49. 84 0
      src/main/java/com/xjrsoft/module/attendance/vo/AttendanceMessageSetPageVo.java
  50. 60 0
      src/main/java/com/xjrsoft/module/attendance/vo/AttendanceMessageSetVo.java
  51. 58 0
      src/main/java/com/xjrsoft/module/attendance/vo/AttendanceMessageUserRelationVo.java
  52. 3 0
      src/main/java/com/xjrsoft/module/attendance/vo/AttendanceRuleCategoryPageVo.java
  53. 172 0
      src/main/java/com/xjrsoft/module/attendance/vo/AttendanceRuleDetailsUserVo.java
  54. 2 1
      src/main/java/com/xjrsoft/module/attendance/vo/AttendanceRuleDetailsVo.java
  55. 60 0
      src/main/java/com/xjrsoft/module/attendance/vo/ClassStatisticsVo.java
  56. 83 0
      src/main/java/com/xjrsoft/module/attendance/vo/StudentAttendanceRecordClassPageVo.java
  57. 123 0
      src/main/java/com/xjrsoft/module/attendance/vo/StudentAttendanceRecordPageVo.java
  58. 59 0
      src/main/java/com/xjrsoft/module/attendance/vo/StudentAttendanceRecordVo.java
  59. 46 0
      src/main/java/com/xjrsoft/module/attendance/vo/StudentStatisticsPageVo.java
  60. 41 0
      src/main/java/com/xjrsoft/module/attendance/vo/StudentStatisticsVo.java
  61. 108 0
      src/main/java/com/xjrsoft/module/attendance/vo/TeacherAttendanceRecordPageVo.java
  62. 49 0
      src/main/java/com/xjrsoft/module/attendance/vo/TeacherAttendanceRecordVo.java
  63. 34 0
      src/main/java/com/xjrsoft/module/attendance/vo/TeacherStatisticsPageVo.java
  64. 45 0
      src/main/java/com/xjrsoft/module/attendance/vo/TeacherStatisticsVo.java
  65. 44 0
      src/main/java/com/xjrsoft/module/attendance/vo/VisitorInfoVo.java
  66. 10 0
      src/main/java/com/xjrsoft/module/base/mapper/BaseClassMapper.java
  67. 7 0
      src/main/java/com/xjrsoft/module/base/service/IBaseClassService.java
  68. 13 0
      src/main/java/com/xjrsoft/module/base/service/impl/BaseClassServiceImpl.java
  69. 31 0
      src/main/java/com/xjrsoft/module/base/vo/StudentClassVo.java
  70. 55 0
      src/main/java/com/xjrsoft/module/hikvision/entity/HikvisionData.java
  71. 30 0
      src/main/java/com/xjrsoft/module/hikvision/mapper/HikvisionDataMapper.java
  72. 24 9
      src/main/java/com/xjrsoft/module/hikvision/util/ApiUtil.java
  73. 536 34
      src/main/java/com/xjrsoft/module/hikvision/util/DataUtil.java
  74. 123 0
      src/main/java/com/xjrsoft/module/hikvision/util/EventController.java
  75. 69 0
      src/main/java/com/xjrsoft/module/hikvision/util/FaceImportUtil.java
  76. 587 0
      src/main/java/com/xjrsoft/module/hikvision/util/Out_In_RecordUtil.java
  77. 137 0
      src/main/java/com/xjrsoft/module/holiday/controller/HolidayDateController.java
  78. 39 0
      src/main/java/com/xjrsoft/module/holiday/dto/AddHolidayDateDto.java
  79. 40 0
      src/main/java/com/xjrsoft/module/holiday/dto/HolidayDateListDto.java
  80. 26 0
      src/main/java/com/xjrsoft/module/holiday/dto/HolidayDatePageDto.java
  81. 13 0
      src/main/java/com/xjrsoft/module/holiday/dto/InitYearDto.java
  82. 32 0
      src/main/java/com/xjrsoft/module/holiday/dto/UpdateHolidayDateDto.java
  83. 78 0
      src/main/java/com/xjrsoft/module/holiday/entity/HolidayDate.java
  84. 17 0
      src/main/java/com/xjrsoft/module/holiday/mapper/HolidayDateMapper.java
  85. 28 0
      src/main/java/com/xjrsoft/module/holiday/service/IHolidayDateService.java
  86. 179 0
      src/main/java/com/xjrsoft/module/holiday/service/impl/HolidayDateServiceImpl.java
  87. 27 0
      src/main/java/com/xjrsoft/module/holiday/vo/AlmanacVo.java
  88. 83 0
      src/main/java/com/xjrsoft/module/holiday/vo/HolidayDateListVo.java
  89. 83 0
      src/main/java/com/xjrsoft/module/holiday/vo/HolidayDatePageVo.java
  90. 64 0
      src/main/java/com/xjrsoft/module/holiday/vo/HolidayDateVo.java
  91. 45 0
      src/main/java/com/xjrsoft/module/job/AttendanceMessageTask.java
  92. 30 30
      src/main/java/com/xjrsoft/module/job/HikvisionBaseDataTask.java
  93. 37 0
      src/main/java/com/xjrsoft/module/job/HikvisionLeaveTask.java
  94. 32 0
      src/main/java/com/xjrsoft/module/job/HolidayTask.java
  95. 51 0
      src/main/java/com/xjrsoft/module/job/InsertOutInRecordTask.java
  96. 37 0
      src/main/java/com/xjrsoft/module/liteflow/node/CarMessageApplyNode.java
  97. 49 0
      src/main/java/com/xjrsoft/module/liteflow/node/ImportStudentFaceNode.java
  98. 49 0
      src/main/java/com/xjrsoft/module/liteflow/node/ImportTeacherFaceNode.java
  99. 39 0
      src/main/java/com/xjrsoft/module/liteflow/node/ReservationSchoolNode.java
  100. 37 0
      src/main/java/com/xjrsoft/module/liteflow/node/StudentAdmissionApplicationNode.java

+ 1 - 0
pom.xml

@@ -562,6 +562,7 @@
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.10.1</version>
                 <configuration>
                     <source>8</source>
                     <target>8</target>

+ 48 - 0
src/main/java/com/xjrsoft/common/enums/GenderIntEnum.java

@@ -0,0 +1,48 @@
+package com.xjrsoft.common.enums;
+
+public enum GenderIntEnum {
+    /**
+     * 男
+     */
+    MALE("SB10001", 1),
+    /**
+     * 女
+     */
+    FEMALE("SB10002", 2);
+
+    final String code;
+    final Integer value;
+
+    public String getCode() {
+        return this.code;
+    }
+
+    public Integer getValue() {
+        return this.value;
+    }
+
+    public static Integer getValue(String code) {
+        for (GenderIntEnum item : values()) {
+            if (item.getCode().equals(code)) {
+                return  item.getValue();
+            }
+        }
+        return null;
+    }
+
+    GenderIntEnum(final String code, final Integer message) {
+        this.code = code;
+        this.value = message;
+    }
+
+    public static String getCode(Integer value) {
+        for (GenderIntEnum item : values()) {
+            if (item.getValue() == value) {
+                return  item.getCode();
+            }
+        }
+        return null;
+    }
+
+
+}

+ 23 - 0
src/main/java/com/xjrsoft/common/utils/FileZipUtil.java

@@ -1,9 +1,15 @@
 package com.xjrsoft.common.utils;
 
+import org.springframework.web.multipart.MultipartFile;
+
 import java.io.*;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.List;
 import java.util.Map;
 import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
 import java.util.zip.ZipOutputStream;
 
 /**
@@ -163,4 +169,21 @@ public class FileZipUtil {
         }
         return file.getPath();
     }
+
+    /**
+     * 将MultipartFile转成ZipFile
+     * @param multipartFile
+     * @return
+     * @throws IOException
+     */
+    public static ZipFile convertToZipFile(MultipartFile multipartFile) throws IOException {
+        // 创建临时文件
+        String originalFilename = multipartFile.getOriginalFilename();
+        Path tempPath = Files.createTempFile("temp", originalFilename.substring(originalFilename.lastIndexOf('.')));
+        multipartFile.transferTo(tempPath); // 将MultipartFile内容写入临时文件
+
+        // 使用ZipFile读取临时文件
+        ZipFile zipfile = new ZipFile(tempPath.toFile(), Charset.forName("GBK"));
+        return zipfile;
+    }
 }

+ 66 - 0
src/main/java/com/xjrsoft/common/utils/HolidayUtil.java

@@ -0,0 +1,66 @@
+package com.xjrsoft.common.utils;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.util.EntityUtils;
+
+import java.io.IOException;
+
+/**
+ * 获取法定节假日
+ */
+public class HolidayUtil {
+    public static String getMonth(String year, String month){
+        String result = "fail";
+        String query;
+        query = year+"年"+month+"月";
+        long timeMillis = System.currentTimeMillis();
+        String apiUrl = "https://sp1.baidu.com/8aQDcjqpAAV3otqbppnN2DJv/api.php?tn=wisetpl&format=json&query="+query+"&co=&resource_id=39043&t="+ timeMillis +"&cb=op_aladdin_callback"+timeMillis;
+        CloseableHttpClient httpclient = null;
+        CloseableHttpResponse hResponse = null;
+        try {
+            HttpGet method = new HttpGet(apiUrl);
+            httpclient = HttpClientBuilder.create().build();
+            method.setHeader("User-Agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36");
+            hResponse = httpclient.execute(method);
+            HttpEntity repEntity = hResponse.getEntity();
+            int statusCode = hResponse.getStatusLine().getStatusCode();
+            if (statusCode != HttpStatus.SC_OK) {
+                method.abort();
+            }
+            String content = EntityUtils.toString(repEntity, "UTF-8");
+            result = reParseJson(content);
+            return  result;
+        } catch (Exception e) {
+            throw new Exception(e);
+        }finally {
+            if (hResponse != null) {
+                try {
+                    hResponse.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+            if (httpclient != null) {
+                try {
+                    httpclient.close();
+                } catch (IOException e) {
+                }
+            }
+            return result;
+        }
+    }
+
+    /**
+     * 解析json
+     */
+    public static String  reParseJson(String  old){
+        int start = old.indexOf("{");
+        int end = old.lastIndexOf("}");
+        return old.substring(start,end+1);
+    }
+}

+ 11 - 1
src/main/java/com/xjrsoft/common/utils/UploadUtil.java

@@ -42,7 +42,7 @@ public class UploadUtil {
         try {
             OkHttpClient client = new OkHttpClient();
             Request req = new Request.Builder().url(path).build();
-            InputStream inputStream=null;
+            InputStream inputStream = null;
                 okhttp3.Response resp = client.newCall(req).execute();
                 if (resp.isSuccessful()) {
                     ResponseBody body = resp.body();
@@ -57,4 +57,14 @@ public class UploadUtil {
     public static boolean delete(String path) {
      return Objects.requireNonNull(OssFactory.build()).delete(path);
     }
+
+
+    public static String  uploadFileByte(String fileName, byte[] file) throws Exception {
+        if (file.length == 0) {
+            throw new RuntimeException("上传文件不能为空");
+        }
+        //上传文件
+        String suffix = Objects.requireNonNull(fileName).substring(fileName.lastIndexOf(StringPool.DOT));
+        return Objects.requireNonNull(OssFactory.build()).uploadSuffix(file, suffix);
+    }
 }

+ 26 - 0
src/main/java/com/xjrsoft/config/HikvisionConfig.java

@@ -0,0 +1,26 @@
+package com.xjrsoft.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * @Author: dzx
+ * @Date: 2024年5月30日
+ */
+@Data
+@Component
+@ConfigurationProperties("xjrsoft.hikvision")
+public class HikvisionConfig {
+
+    private String host;
+
+    private String appKey;
+
+    private String appSecret;
+
+    private String peopleUrl;
+
+    private String carUrl;
+
+}

+ 160 - 0
src/main/java/com/xjrsoft/module/attendance/controller/AttendanceMessageSetController.java

@@ -0,0 +1,160 @@
+package com.xjrsoft.module.attendance.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.github.yulichang.toolkit.MPJWrappers;
+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.attendance.dto.AddAttendanceMessageSetDto;
+import com.xjrsoft.module.attendance.dto.AttendanceMessageSetDto;
+import com.xjrsoft.module.attendance.dto.UpdateAttendanceMessageSetDto;
+import cn.dev33.satoken.annotation.SaCheckPermission;
+
+import com.xjrsoft.module.attendance.dto.AttendanceMessageSetPageDto;
+import com.xjrsoft.module.attendance.entity.AttendanceMessageSet;
+import com.xjrsoft.module.attendance.service.IAttendanceMessageSetService;
+import com.xjrsoft.module.attendance.vo.AttendanceMessageSetPageVo;
+
+import com.xjrsoft.module.attendance.vo.AttendanceMessageSetVo;
+import com.xjrsoft.module.attendance.vo.AttendanceMessageUserRelationVo;
+import com.xjrsoft.module.base.entity.BaseClass;
+import com.xjrsoft.module.base.service.IBaseClassService;
+import com.xjrsoft.module.concat.service.IXjrUserService;
+import com.xjrsoft.module.organization.entity.Department;
+import com.xjrsoft.module.organization.service.IDepartmentService;
+import com.xjrsoft.module.teacher.entity.XjrUser;
+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.List;
+
+/**
+* @title: 考勤消息设置
+* @Author dzx
+* @Date: 2024-05-21
+* @Version 1.0
+*/
+@RestController
+@RequestMapping("/attendance" + "/attendanceMessageSet")
+@Api(value = "/attendance"  + "/attendanceMessageSet",tags = "考勤消息设置代码")
+@AllArgsConstructor
+public class AttendanceMessageSetController {
+
+
+    private final IAttendanceMessageSetService attendanceMessageSetService;
+    private final IBaseClassService classService;
+    private final IDepartmentService departmentService;
+    private final IXjrUserService xjrUserService;
+
+    @GetMapping(value = "/page")
+    @ApiOperation(value="考勤消息设置列表(分页)")
+    @SaCheckPermission("attendancemessageset:detail")
+    public RT<PageOutput<AttendanceMessageSetPageVo>> page(@Valid AttendanceMessageSetPageDto dto){
+
+        LambdaQueryWrapper<AttendanceMessageSet> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper
+                    .orderByDesc(AttendanceMessageSet::getId)
+                .select(AttendanceMessageSet.class,x -> VoToColumnUtil.fieldsToColumns(AttendanceMessageSetPageVo.class).contains(x.getProperty()));
+        IPage<AttendanceMessageSet> page = attendanceMessageSetService.page(ConventPage.getPage(dto), queryWrapper);
+        PageOutput<AttendanceMessageSetPageVo> pageOutput = ConventPage.getPageOutput(page, AttendanceMessageSetPageVo.class);
+        return RT.ok(pageOutput);
+    }
+
+    @GetMapping(value = "/list")
+    @ApiOperation(value="考勤消息设置列表")
+    @SaCheckPermission("attendancemessageset:detail")
+    public RT<List<AttendanceMessageSetVo>> list(@Valid AttendanceMessageSetDto dto) {
+        List<AttendanceMessageSet> list = attendanceMessageSetService.list(MPJWrappers.<AttendanceMessageSet>lambdaJoin().eq(ObjectUtil.isNotNull(dto.getRoleType()) && dto.getRoleType() != 0, AttendanceMessageSet::getRoleType, dto.getRoleType()));
+        List<AttendanceMessageSetVo> res = new ArrayList<>();
+        for (AttendanceMessageSet item : list) {
+            AttendanceMessageSet attendanceMessageSet = attendanceMessageSetService.getByIdDeep(item.getId());
+            if (attendanceMessageSet != null) {
+
+                AttendanceMessageSetVo attendanceMessageSetVo=BeanUtil.toBean(attendanceMessageSet, AttendanceMessageSetVo.class);
+
+                for (AttendanceMessageUserRelationVo attendanceMessageUserRelationVo:attendanceMessageSetVo.getAttendanceMessageUserRelationList()){
+                    if(attendanceMessageUserRelationVo.getUserId() != null){
+                        XjrUser xjrUser = xjrUserService.getById(attendanceMessageUserRelationVo.getUserId());
+                        if(xjrUser != null){
+                            attendanceMessageUserRelationVo.setName(xjrUser.getName());
+                        }
+                    }else if(attendanceMessageUserRelationVo.getDeptId() != null){
+                        Department department = departmentService.getById(attendanceMessageUserRelationVo.getDeptId());
+                        if(department != null){
+                            attendanceMessageUserRelationVo.setName(department.getName());
+                        }
+
+                    }else if(attendanceMessageUserRelationVo.getClassId() != null){
+                        BaseClass aClass = classService.getById(attendanceMessageUserRelationVo.getClassId());
+                        if(aClass != null){
+                            attendanceMessageUserRelationVo.setName(aClass.getName());
+                        }
+                    }
+                }
+                res.add(attendanceMessageSetVo);
+            }
+        }
+        return RT.ok(res);
+    }
+
+    @GetMapping(value = "/info")
+    @ApiOperation(value="根据id查询考勤消息设置信息")
+    @SaCheckPermission("attendancemessageset:detail")
+    public RT<AttendanceMessageSetVo> info(@RequestParam Long id){
+        AttendanceMessageSet attendanceMessageSet = attendanceMessageSetService.getByIdDeep(id);
+        if (attendanceMessageSet == null) {
+           return RT.error("找不到此数据!");
+        }
+        return RT.ok(BeanUtil.toBean(attendanceMessageSet, AttendanceMessageSetVo.class));
+    }
+
+
+    @PostMapping
+    @ApiOperation(value = "新增考勤消息设置")
+    @SaCheckPermission("attendancemessageset:add")
+    public RT<Boolean> add(@Valid @RequestBody AddAttendanceMessageSetDto dto){
+        AttendanceMessageSet attendanceMessageSet = BeanUtil.toBean(dto, AttendanceMessageSet.class);
+        boolean isSuccess = attendanceMessageSetService.add(attendanceMessageSet);
+    return RT.ok(isSuccess);
+    }
+
+    @PutMapping
+    @ApiOperation(value = "修改考勤消息设置")
+    @SaCheckPermission("attendancemessageset:edit")
+    public RT<Boolean> update(@Valid @RequestBody UpdateAttendanceMessageSetDto dto){
+
+        AttendanceMessageSet attendanceMessageSet = BeanUtil.toBean(dto, AttendanceMessageSet.class);
+        return RT.ok(attendanceMessageSetService.update(attendanceMessageSet));
+
+    }
+
+    @PostMapping("edit")
+    @ApiOperation(value = "新增考勤消息设置")
+    @SaCheckPermission("attendancemessageset:add")
+    public RT<Boolean> edit(@Valid @RequestBody List<UpdateAttendanceMessageSetDto> dtos) {
+        boolean isSuccess = attendanceMessageSetService.edit(dtos);
+        return RT.ok(isSuccess);
+    }
+
+    @DeleteMapping
+    @ApiOperation(value = "删除考勤消息设置")
+    @SaCheckPermission("attendancemessageset:delete")
+    public RT<Boolean> delete(@Valid @RequestBody List<Long> ids){
+        return RT.ok(attendanceMessageSetService.delete(ids));
+
+    }
+
+}

+ 10 - 3
src/main/java/com/xjrsoft/module/attendance/controller/AttendanceRuleCategoryController.java

@@ -91,13 +91,20 @@ public class AttendanceRuleCategoryController {
                 AddAttendanceUserRelationDto relationDto = JSONUtil.toBean(jsonElement.getAsJsonObject().toString(), AddAttendanceUserRelationDto.class);
                 if(relationDto.getUserId() != null){
                     XjrUser xjrUser = xjrUserService.getById(relationDto.getUserId());
-                    relationDto.setName(xjrUser.getName());
+                    if(xjrUser != null){
+                        relationDto.setName(xjrUser.getName());
+                    }
                 }else if(relationDto.getDeptId() != null){
                     Department department = departmentService.getById(relationDto.getDeptId());
-                    relationDto.setName(department.getName());
+                    if(department != null){
+                        relationDto.setName(department.getName());
+                    }
+
                 }else if(relationDto.getClassId() != null){
                     BaseClass aClass = classService.getById(relationDto.getClassId());
-                    relationDto.setName(aClass.getName());
+                    if(aClass != null){
+                        relationDto.setName(aClass.getName());
+                    }
                 }
                 attendanceUserRelationList.add(relationDto);
             }

+ 222 - 0
src/main/java/com/xjrsoft/module/attendance/controller/StatisticsController.java

@@ -0,0 +1,222 @@
+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.model.result.RT;
+import com.xjrsoft.module.attendance.dto.AttendanceStatisticDto;
+import com.xjrsoft.module.attendance.vo.TeacherStatisticsVo;
+import com.xjrsoft.module.attendance.vo.VisitorInfoVo;
+import com.xjrsoft.module.concat.service.IXjrUserService;
+import com.xjrsoft.module.organization.entity.UserDeptRelation;
+import com.xjrsoft.module.outint.entity.StudentOutInRecord;
+import com.xjrsoft.module.outint.entity.TeacherOutInRecord;
+import com.xjrsoft.module.outint.service.IStudentOutInRecordService;
+import com.xjrsoft.module.outint.service.ITeacherOutInRecordService;
+import com.xjrsoft.module.personnel.service.IReservationSchoolService;
+import com.xjrsoft.module.student.entity.BaseStudent;
+import com.xjrsoft.module.student.entity.BaseStudentSchoolRoll;
+import com.xjrsoft.module.student.service.IStudentLeaveService;
+import com.xjrsoft.module.teacher.entity.BaseTeacher;
+import com.xjrsoft.module.teacher.entity.XjrUser;
+import com.xjrsoft.module.teacher.service.IWfTeacherleaveService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.AllArgsConstructor;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.validation.Valid;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+* @title: 考勤消息设置
+* @Author dzx
+* @Date: 2024-05-21
+* @Version 1.0
+*/
+@RestController
+@RequestMapping("/statistics")
+@Api(value = "/statistics" ,tags = "考勤统计")
+@AllArgsConstructor
+public class StatisticsController {
+
+
+    private final IXjrUserService xjrUserService;
+    private final ITeacherOutInRecordService teacherOutInRecordService;
+    private final IStudentOutInRecordService studentOutInRecordService;
+    private final IWfTeacherleaveService wfTeacherleaveService;
+    private final IStudentLeaveService studentLeaveService;
+    private final IReservationSchoolService reservationSchoolService;
+
+    @GetMapping(value = "/teacher-statistics")
+    @ApiOperation(value="教职工考勤统计")
+    @SaCheckPermission("statistics:detail")
+    public RT<TeacherStatisticsVo> teacherStatistics(@Valid AttendanceStatisticDto dto){
+        TeacherStatisticsVo statisticsVo = new TeacherStatisticsVo();
+        //查询总人数
+        MPJLambdaWrapper<XjrUser> queryWrapper = MPJWrappers.<XjrUser>lambdaJoin()
+                .disableSubLogicDel()
+                .eq(ObjectUtil.isNotNull(dto.getDeptId()), UserDeptRelation::getDeptId, dto.getDeptId())
+                .innerJoin(BaseTeacher.class,BaseTeacher::getUserId,XjrUser::getId)
+                .innerJoin(UserDeptRelation.class, UserDeptRelation::getUserId, XjrUser::getId);
+        long allCount = xjrUserService.count(queryWrapper);
+        statisticsVo.setAllCount(allCount);
+        if(dto.getDate() != null && !"".equals(dto.getDate())){
+            DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE;
+            LocalDate queryDate = LocalDate.parse(dto.getDate(), formatter);
+            LocalDateTime startTime, endTime;
+            if(dto.getTimePeriod() != null && dto.getTimePeriod() == 1){
+                startTime = queryDate.atTime(5, 0, 0);
+                endTime = queryDate.atTime(12, 0, 0);
+            }else if(dto.getTimePeriod() != null && dto.getTimePeriod() == 2){
+                startTime = queryDate.atTime(12, 0, 0);
+                endTime = queryDate.atTime(18, 0, 0);
+            }else if(dto.getTimePeriod() != null && dto.getTimePeriod() == 3){
+                startTime = queryDate.atTime(18, 0, 0);
+                endTime = queryDate.atTime(23, 59, 59);
+            }else{
+                startTime = queryDate.atTime(0, 0, 0);
+                endTime = queryDate.atTime(23, 59, 59);
+            }
+
+            List<TeacherOutInRecord> outInRecords = teacherOutInRecordService.list(
+                    new QueryWrapper<TeacherOutInRecord>().lambda()
+                            .between(TeacherOutInRecord::getRecordTime, startTime, endTime)
+                            .eq(TeacherOutInRecord::getStatus, 1)
+                            .orderByAsc(TeacherOutInRecord::getRecordTime)
+            );
+
+            List<Long> collect = outInRecords.stream().map(TeacherOutInRecord::getUserId).collect(Collectors.toList());
+            Set<Long> userIds = new HashSet<>(collect);
+            //实到人数
+            statisticsVo.setActualCount(Long.valueOf(userIds.size()));
+
+            //查询教师请假人数
+            Long leaveCount = wfTeacherleaveService.getLeaveCount(startTime, endTime);
+            if(leaveCount == null){
+                leaveCount = 0L;
+            }
+            statisticsVo.setLeaveCount(leaveCount);
+            //通过考勤规则和实到人数信息,计算迟到的
+            userIds = new HashSet<>();
+            Long lateCount = 0L;
+            for (TeacherOutInRecord outInRecord : outInRecords) {
+                if("迟到".equals(outInRecord.getAttendanceStatus()) && !userIds.contains(outInRecord.getUserId())){
+                    lateCount ++;
+                    userIds.add(outInRecord.getUserId());
+                }
+            }
+            statisticsVo.setLateCount(lateCount);
+
+            //最后通过总人数-实到人数-请假人数计算出缺勤人数
+            statisticsVo.setAbsenteeismCount(statisticsVo.getAllCount() - statisticsVo.getLeaveCount() - statisticsVo.getActualCount());
+
+            //计算出勤率
+            BigDecimal divide = BigDecimal.ZERO;
+            if(statisticsVo.getAllCount() != null && statisticsVo.getAllCount() != 0){
+                divide = BigDecimal.valueOf(statisticsVo.getActualCount()).divide(BigDecimal.valueOf(statisticsVo.getAllCount()), 4, RoundingMode.HALF_UP);
+            }
+            statisticsVo.setAttendanceRate(divide.doubleValue());
+        }
+
+        return RT.ok(statisticsVo);
+    }
+
+
+    @GetMapping(value = "/student-statistics")
+    @ApiOperation(value="学生考勤统计")
+    @SaCheckPermission("statistics:detail")
+    public RT<TeacherStatisticsVo> studentStatistics(@Valid AttendanceStatisticDto dto){
+        TeacherStatisticsVo statisticsVo = new TeacherStatisticsVo();
+        //查询总人数
+        MPJLambdaWrapper<XjrUser> queryWrapper = MPJWrappers.<XjrUser>lambdaJoin()
+                .disableSubLogicDel()
+                .distinct()
+                .eq(ObjectUtil.isNotNull(dto.getGradeId()), BaseStudentSchoolRoll::getGradeId, dto.getGradeId())
+                .eq(ObjectUtil.isNotNull(dto.getClassId()), BaseStudentSchoolRoll::getClassId, dto.getClassId())
+                .innerJoin(BaseStudentSchoolRoll.class, BaseStudentSchoolRoll::getUserId, XjrUser::getId)
+                .innerJoin(BaseStudent.class, BaseStudent::getUserId, XjrUser::getId);
+        long allCount = xjrUserService.count(queryWrapper);
+        statisticsVo.setAllCount(allCount);
+        if(dto.getDate() != null && !"".equals(dto.getDate())){
+            DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE;
+            LocalDate queryDate = LocalDate.parse(dto.getDate(), formatter);
+            LocalDateTime startTime, endTime;
+            if(dto.getTimePeriod() != null && dto.getTimePeriod() == 1){
+                startTime = queryDate.atTime(5, 0, 0);
+                endTime = queryDate.atTime(12, 0, 0);
+            }else if(dto.getTimePeriod() != null && dto.getTimePeriod() == 2){
+                startTime = queryDate.atTime(12, 0, 0);
+                endTime = queryDate.atTime(18, 0, 0);
+            }else{
+                startTime = queryDate.atTime(0, 0, 0);
+                endTime = queryDate.atTime(23, 59, 59);
+            }
+
+            List<StudentOutInRecord> outInRecords = studentOutInRecordService.list(
+                    new QueryWrapper<StudentOutInRecord>().lambda()
+                            .between(StudentOutInRecord::getRecordTime, startTime, endTime)
+                            .eq(StudentOutInRecord::getStatus, 1)
+            );
+            //实到人数
+            statisticsVo.setActualCount(Long.valueOf(outInRecords.size()));
+
+            //查询教师请假人数
+            Long leaveCount = studentLeaveService.getLeaveCount(startTime, endTime, dto);
+            if(leaveCount == null){
+                leaveCount = 0L;
+            }
+            statisticsVo.setLeaveCount(leaveCount);
+
+            //通过考勤规则和实到人数信息,计算迟到的
+            Long lateCount = 0L;
+            Integer playTruantCount = 0;
+            for (StudentOutInRecord outInRecord : outInRecords) {
+                if("迟到".equals(outInRecord.getAttendanceStatus())){
+                    lateCount ++;
+                }else if("旷课".equals(outInRecord.getAttendanceStatus())){
+                    playTruantCount ++;
+                }
+            }
+            statisticsVo.setPlayTruantCount(playTruantCount);
+            statisticsVo.setLateCount(lateCount);
+
+
+            //计算出勤率
+            if(statisticsVo.getAllCount() != null && statisticsVo.getAllCount() != 0){
+                //最后通过总人数-实到人数-请假人数计算出缺勤人数
+                statisticsVo.setAbsenteeismCount(statisticsVo.getAllCount() - statisticsVo.getLeaveCount() - statisticsVo.getActualCount());
+                BigDecimal divide = BigDecimal.valueOf(statisticsVo.getActualCount()).divide(BigDecimal.valueOf(statisticsVo.getAllCount()), 4, RoundingMode.HALF_UP);
+                statisticsVo.setAttendanceRate(divide.doubleValue());
+            }else{
+                statisticsVo.setAttendanceRate(0D);
+                statisticsVo.setAbsenteeismCount(0L);
+            }
+
+        }
+
+        return RT.ok(statisticsVo);
+    }
+
+
+    @GetMapping(value = "/visitor-list")
+    @ApiOperation(value="访客列表")
+    @SaCheckPermission("statistics:detail")
+    public RT<List<VisitorInfoVo>> visitorList(@Valid AttendanceStatisticDto dto){
+        List<VisitorInfoVo> visionList = reservationSchoolService.getVisionList(dto.getDate());
+        return RT.ok(visionList);
+    }
+
+}

+ 203 - 0
src/main/java/com/xjrsoft/module/attendance/controller/StudentAttendanceRecordController.java

@@ -0,0 +1,203 @@
+package com.xjrsoft.module.attendance.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.github.yulichang.toolkit.MPJWrappers;
+import com.github.yulichang.wrapper.MPJLambdaWrapper;
+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.attendance.dto.AddStudentAttendanceRecordDto;
+import com.xjrsoft.module.attendance.dto.StudentAttendanceRecordClassPageDto;
+import com.xjrsoft.module.attendance.dto.UpdateStudentAttendanceRecordDto;
+import cn.dev33.satoken.annotation.SaCheckPermission;
+
+import com.xjrsoft.module.attendance.dto.StudentAttendanceRecordPageDto;
+import com.xjrsoft.module.attendance.entity.StudentAttendanceRecord;
+import com.xjrsoft.module.attendance.entity.TeacherAttendanceRecord;
+import com.xjrsoft.module.attendance.service.IStudentAttendanceRecordService;
+import com.xjrsoft.module.attendance.vo.StudentAttendanceRecordClassPageVo;
+import com.xjrsoft.module.attendance.vo.StudentAttendanceRecordPageVo;
+
+import com.xjrsoft.module.attendance.vo.StudentAttendanceRecordVo;
+import com.xjrsoft.module.attendance.vo.TeacherAttendanceRecordPageVo;
+import com.xjrsoft.module.base.entity.BaseClass;
+import com.xjrsoft.module.outint.entity.TeacherOutInRecord;
+import com.xjrsoft.module.system.entity.DictionaryDetail;
+import com.xjrsoft.module.teacher.entity.XjrUser;
+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.List;
+
+/**
+* @title: 学生考勤记录
+* @Author dzx
+* @Date: 2024-05-15
+* @Version 1.0
+*/
+@RestController
+@RequestMapping("/attendance" + "/studentAttendanceRecord")
+@Api(value = "/attendance"  + "/studentAttendanceRecord",tags = "学生考勤记录代码")
+@AllArgsConstructor
+public class StudentAttendanceRecordController {
+
+
+    private final IStudentAttendanceRecordService studentAttendanceRecordService;
+
+    @GetMapping(value = "/page")
+    @ApiOperation(value="学生考勤记录列表(分页)")
+    @SaCheckPermission("studentattendancerecord:detail")
+    public RT<PageOutput<StudentAttendanceRecordPageVo>> page(@Valid StudentAttendanceRecordPageDto dto){
+
+        MPJLambdaWrapper<StudentAttendanceRecord> queryWrapper =  MPJWrappers.<StudentAttendanceRecord>lambdaJoin()
+                    .orderByDesc(StudentAttendanceRecord::getId)
+                .like(StrUtil.isNotBlank(dto.getName()), XjrUser::getName,dto.getName())
+                .like(StrUtil.isNotBlank(dto.getIdentityCard()), XjrUser::getCredentialNumber,dto.getIdentityCard())
+                .ge(ObjectUtil.isNotNull(dto.getStartTime()), StudentAttendanceRecord::getCreateDate,dto.getStartTime()+" 00:00:00")
+                .le(ObjectUtil.isNotNull(dto.getStartTime()),StudentAttendanceRecord::getCreateDate,dto.getStartTime()+" 23:59:59")
+                .eq(ObjectUtil.isNotNull(dto.getTimeInterval())&&dto.getTimeInterval()!=0, StudentAttendanceRecord::getTimeInterval, dto.getTimeInterval())
+                .eq(ObjectUtil.isNotNull(dto.getClassId())&&dto.getClassId()!=0, StudentAttendanceRecord::getClassId, dto.getClassId())
+                .eq(StrUtil.isNotBlank(dto.getAttendanceStatus()), StudentAttendanceRecord::getAttendanceStatus,dto.getAttendanceStatus())
+                .eq(StrUtil.isNotBlank(dto.getStduyStatus()), StudentAttendanceRecord::getStduyStatus,dto.getStduyStatus())
+                .select(StudentAttendanceRecord::getId)
+                .select(XjrUser::getName,XjrUser::getMobile,XjrUser::getCredentialNumber)
+                .select(StudentAttendanceRecord.class,x -> VoToColumnUtil.fieldsToColumns(StudentAttendanceRecordPageVo.class).contains(x.getProperty()))
+                .leftJoin(XjrUser.class,XjrUser::getId, TeacherOutInRecord::getUserId)
+                .leftJoin(BaseClass.class,BaseClass::getId, StudentAttendanceRecord::getClassId,ext->ext.selectAs(BaseClass::getName,StudentAttendanceRecordPageVo::getClassCn))
+                .leftJoin(XjrUser.class,XjrUser::getId, BaseClass::getTeacherId,ext->ext.selectAs(XjrUser::getName,StudentAttendanceRecordPageVo::getTeacherCn))
+
+                .leftJoin(DictionaryDetail.class,DictionaryDetail::getCode, StudentAttendanceRecord::getStduyStatus, ext->ext.selectAs(DictionaryDetail::getName, StudentAttendanceRecordPageVo::getStduyStatusCn))
+                .leftJoin(DictionaryDetail.class,DictionaryDetail::getCode, XjrUser::getGender, ext->ext.selectAs(DictionaryDetail::getName, StudentAttendanceRecordPageVo::getGender))
+                .leftJoin(DictionaryDetail.class,DictionaryDetail::getCode, StudentAttendanceRecord::getAttendanceStatus, ext->ext.selectAs(DictionaryDetail::getName, StudentAttendanceRecordPageVo::getAttendanceStatusCn))
+                ;
+
+        IPage<StudentAttendanceRecordPageVo> page = studentAttendanceRecordService.selectJoinListPage(ConventPage.getPage(dto),StudentAttendanceRecordPageVo.class, queryWrapper);
+        PageOutput<StudentAttendanceRecordPageVo> pageOutput = ConventPage.getPageOutput(page, StudentAttendanceRecordPageVo.class);
+        return RT.ok(pageOutput);
+    }
+
+    @GetMapping(value = "/class-page")
+    @ApiOperation(value="班级考勤记录列表(分页)")
+    @SaCheckPermission("studentattendancerecord:detail")
+    public RT<PageOutput<StudentAttendanceRecordClassPageVo>> classPage(@Valid StudentAttendanceRecordClassPageDto dto){
+
+        MPJLambdaWrapper<StudentAttendanceRecord> queryWrapper = MPJWrappers.<StudentAttendanceRecord>lambdaJoin()
+                .orderByDesc(StudentAttendanceRecord::getId)
+
+                .eq(ObjectUtil.isNotNull(dto.getClassId())&&dto.getClassId()!=0, StudentAttendanceRecord::getClassId, dto.getClassId())
+                .ge(ObjectUtil.isNotNull(dto.getStartTime()), StudentAttendanceRecord::getCreateDate,dto.getStartTime()+" 00:00:00")
+                .le(ObjectUtil.isNotNull(dto.getStartTime()),StudentAttendanceRecord::getCreateDate,dto.getStartTime()+" 23:59:59")
+                .eq(ObjectUtil.isNotNull(dto.getTimeInterval())&&dto.getTimeInterval()!=0, StudentAttendanceRecord::getTimeInterval, dto.getTimeInterval())
+
+                .select(StudentAttendanceRecord::getId)
+                .select(StudentAttendanceRecord.class,x -> VoToColumnUtil.fieldsToColumns(StudentAttendanceRecordClassPageVo.class).contains(x.getProperty()))
+
+                .leftJoin(BaseClass.class,BaseClass::getId, StudentAttendanceRecord::getClassId,ext->ext.selectAs(BaseClass::getName,StudentAttendanceRecordClassPageVo::getClassCn))
+                .leftJoin(XjrUser.class,XjrUser::getId, BaseClass::getTeacherId,ext->ext.selectAs(XjrUser::getName,StudentAttendanceRecordClassPageVo::getTeacherCn))
+                .leftJoin(DictionaryDetail.class,DictionaryDetail::getCode, StudentAttendanceRecord::getStduyStatus, ext->ext.selectAs(DictionaryDetail::getName, StudentAttendanceRecordClassPageVo::getAttendanceStatusCn))
+                ;
+        IPage<StudentAttendanceRecordClassPageVo> page = studentAttendanceRecordService.selectJoinListPage(ConventPage.getPage(dto),StudentAttendanceRecordClassPageVo.class, queryWrapper);
+        PageOutput<StudentAttendanceRecordClassPageVo> pageOutput = ConventPage.getPageOutput(page, StudentAttendanceRecordClassPageVo.class);
+        return RT.ok(pageOutput);
+    }
+    @GetMapping(value = "/history-page")
+    @ApiOperation(value="历史考勤记录列表(分页)")
+    @SaCheckPermission("studentattendancerecord:detail")
+    public RT<PageOutput<StudentAttendanceRecordClassPageVo>> historyPage(@Valid StudentAttendanceRecordClassPageDto dto){
+
+        MPJLambdaWrapper<StudentAttendanceRecord> queryWrapper = MPJWrappers.<StudentAttendanceRecord>lambdaJoin()
+                .orderByDesc(StudentAttendanceRecord::getId)
+
+                .eq(ObjectUtil.isNotNull(dto.getClassId())&&dto.getClassId()!=0, StudentAttendanceRecord::getClassId, dto.getClassId())
+                .ge(ObjectUtil.isNotNull(dto.getStartTime()), StudentAttendanceRecord::getCreateDate,dto.getStartTime()+" 00:00:00")
+                .le(ObjectUtil.isNotNull(dto.getStartTime()),StudentAttendanceRecord::getCreateDate,dto.getEndTime()+" 23:59:59")
+
+                .select(StudentAttendanceRecord::getId)
+                .select(StudentAttendanceRecord.class,x -> VoToColumnUtil.fieldsToColumns(StudentAttendanceRecordClassPageVo.class).contains(x.getProperty()))
+
+                .leftJoin(BaseClass.class,BaseClass::getId, StudentAttendanceRecord::getClassId,ext->ext.selectAs(BaseClass::getName,StudentAttendanceRecordClassPageVo::getClassCn))
+                .leftJoin(XjrUser.class,XjrUser::getId, BaseClass::getTeacherId,ext->ext.selectAs(XjrUser::getName,StudentAttendanceRecordClassPageVo::getTeacherCn))
+                .leftJoin(DictionaryDetail.class,DictionaryDetail::getCode, StudentAttendanceRecord::getStduyStatus, ext->ext.selectAs(DictionaryDetail::getName, StudentAttendanceRecordClassPageVo::getAttendanceStatusCn))
+                ;
+        IPage<StudentAttendanceRecordClassPageVo> page = studentAttendanceRecordService.selectJoinListPage(ConventPage.getPage(dto),StudentAttendanceRecordClassPageVo.class, queryWrapper);
+        PageOutput<StudentAttendanceRecordClassPageVo> pageOutput = ConventPage.getPageOutput(page, StudentAttendanceRecordClassPageVo.class);
+        return RT.ok(pageOutput);
+    }
+
+    @GetMapping(value = "/leaving-school-page")
+    @ApiOperation(value="离校统计列表(分页)")
+    @SaCheckPermission("studentattendancerecord:detail")
+    public RT<PageOutput<StudentAttendanceRecordClassPageVo>> leavingSchoolPage(@Valid StudentAttendanceRecordClassPageDto dto){
+
+        MPJLambdaWrapper<StudentAttendanceRecord> queryWrapper = MPJWrappers.<StudentAttendanceRecord>lambdaJoin()
+                .orderByDesc(StudentAttendanceRecord::getId)
+
+                .eq(ObjectUtil.isNotNull(dto.getClassId())&&dto.getClassId()!=0, StudentAttendanceRecord::getClassId, dto.getClassId())
+                .ge(ObjectUtil.isNotNull(dto.getStartTime()), StudentAttendanceRecord::getCreateDate,dto.getStartTime()+" 00:00:00")
+                .le(ObjectUtil.isNotNull(dto.getStartTime()),StudentAttendanceRecord::getCreateDate,dto.getEndTime()+" 23:59:59")
+                .eq(ObjectUtil.isNotNull(dto.getTimeInterval())&&dto.getTimeInterval()!=0, StudentAttendanceRecord::getTimeInterval, dto.getTimeInterval())
+
+                .select(StudentAttendanceRecord::getId)
+                .select(StudentAttendanceRecord.class,x -> VoToColumnUtil.fieldsToColumns(StudentAttendanceRecordClassPageVo.class).contains(x.getProperty()))
+
+                .leftJoin(BaseClass.class,BaseClass::getId, StudentAttendanceRecord::getClassId,ext->ext.selectAs(BaseClass::getName,StudentAttendanceRecordClassPageVo::getClassCn))
+                .leftJoin(XjrUser.class,XjrUser::getId, BaseClass::getTeacherId,ext->ext.selectAs(XjrUser::getName,StudentAttendanceRecordClassPageVo::getTeacherCn))
+                .leftJoin(DictionaryDetail.class,DictionaryDetail::getCode, StudentAttendanceRecord::getStduyStatus, ext->ext.selectAs(DictionaryDetail::getName, StudentAttendanceRecordClassPageVo::getAttendanceStatusCn))
+                ;
+        IPage<StudentAttendanceRecordClassPageVo> page = studentAttendanceRecordService.selectJoinListPage(ConventPage.getPage(dto),StudentAttendanceRecordClassPageVo.class, queryWrapper);
+        PageOutput<StudentAttendanceRecordClassPageVo> pageOutput = ConventPage.getPageOutput(page, StudentAttendanceRecordClassPageVo.class);
+        return RT.ok(pageOutput);
+    }
+
+    @GetMapping(value = "/info")
+    @ApiOperation(value="根据id查询学生考勤记录信息")
+    @SaCheckPermission("studentattendancerecord:detail")
+    public RT<StudentAttendanceRecordVo> info(@RequestParam Long id){
+        StudentAttendanceRecord studentAttendanceRecord = studentAttendanceRecordService.getById(id);
+        if (studentAttendanceRecord == null) {
+           return RT.error("找不到此数据!");
+        }
+        return RT.ok(BeanUtil.toBean(studentAttendanceRecord, StudentAttendanceRecordVo.class));
+    }
+
+
+    @PostMapping
+    @ApiOperation(value = "新增学生考勤记录")
+    @SaCheckPermission("studentattendancerecord:add")
+    public RT<Boolean> add(@Valid @RequestBody AddStudentAttendanceRecordDto dto){
+        StudentAttendanceRecord studentAttendanceRecord = BeanUtil.toBean(dto, StudentAttendanceRecord.class);
+        boolean isSuccess = studentAttendanceRecordService.save(studentAttendanceRecord);
+    return RT.ok(isSuccess);
+    }
+
+    @PutMapping
+    @ApiOperation(value = "修改学生考勤记录")
+    @SaCheckPermission("studentattendancerecord:edit")
+    public RT<Boolean> update(@Valid @RequestBody UpdateStudentAttendanceRecordDto dto){
+
+        StudentAttendanceRecord studentAttendanceRecord = BeanUtil.toBean(dto, StudentAttendanceRecord.class);
+        return RT.ok(studentAttendanceRecordService.updateById(studentAttendanceRecord));
+
+    }
+
+    @DeleteMapping
+    @ApiOperation(value = "删除学生考勤记录")
+    @SaCheckPermission("studentattendancerecord:delete")
+    public RT<Boolean> delete(@Valid @RequestBody List<Long> ids){
+        return RT.ok(studentAttendanceRecordService.removeBatchByIds(ids));
+
+    }
+
+}

+ 365 - 0
src/main/java/com/xjrsoft/module/attendance/controller/StudentStatisticsController.java

@@ -0,0 +1,365 @@
+package com.xjrsoft.module.attendance.controller;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.github.yulichang.wrapper.MPJLambdaWrapper;
+import com.xjrsoft.common.enums.ArchivesStatusEnum;
+import com.xjrsoft.common.model.result.RT;
+import com.xjrsoft.common.page.ConventPage;
+import com.xjrsoft.common.page.PageOutput;
+import com.xjrsoft.module.attendance.dto.AttendanceStatisticDto;
+import com.xjrsoft.module.attendance.dto.StudentDetailsDto;
+import com.xjrsoft.module.attendance.vo.ClassStatisticsVo;
+import com.xjrsoft.module.attendance.vo.StudentStatisticsPageVo;
+import com.xjrsoft.module.base.entity.BaseClass;
+import com.xjrsoft.module.base.service.IBaseClassService;
+import com.xjrsoft.module.organization.entity.User;
+import com.xjrsoft.module.organization.service.IUserService;
+import com.xjrsoft.module.outint.entity.StudentOutInRecord;
+import com.xjrsoft.module.outint.service.IStudentOutInRecordService;
+import com.xjrsoft.module.outint.vo.StudentOutInRecordVo;
+import com.xjrsoft.module.student.entity.BaseStudentFamily;
+import com.xjrsoft.module.student.entity.BaseStudentSchoolRoll;
+import com.xjrsoft.module.student.entity.StudentLeave;
+import com.xjrsoft.module.student.service.IStudentLeaveService;
+import com.xjrsoft.module.system.entity.DictionaryDetail;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.AllArgsConstructor;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.validation.Valid;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.time.DayOfWeek;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.TemporalAdjusters;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+* @title: 考勤消息设置
+* @Author dzx
+* @Date: 2024-05-21
+* @Version 1.0
+*/
+@RestController
+@RequestMapping("/studentStatistics")
+@Api(value = "/studentStatistics" ,tags = "学生考勤统计")
+@AllArgsConstructor
+public class StudentStatisticsController {
+
+
+    private final IUserService xjrUserService;
+    private final IStudentOutInRecordService studentOutInRecordService;
+    private final IStudentLeaveService studentLeaveService;
+    private final IBaseClassService classService;
+
+    @GetMapping(value = "/class-statistics")
+    @ApiOperation(value="班级考勤统计")
+    @SaCheckPermission("statistics:detail")
+    public RT<PageOutput<ClassStatisticsVo>> classStatistics(@Valid AttendanceStatisticDto dto){
+        Page<ClassStatisticsVo> attendancePage = classService.getAttendancePage(new Page<>(dto.getLimit(), dto.getSize()), dto);
+        List<Long> classIds = new ArrayList<>();
+        for (ClassStatisticsVo record : attendancePage.getRecords()) {
+            classIds.add(record.getId());
+        }
+        if(dto.getDate() != null && !"".equals(dto.getDate())){
+            DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE;
+            LocalDate queryDate = LocalDate.parse(dto.getDate(), formatter);
+            LocalDateTime startTime, endTime;
+
+
+            if(dto.getTimePeriod() != null && dto.getTimePeriod() == 1){
+                startTime = queryDate.atTime(5, 0, 0);
+                endTime = queryDate.atTime(12, 0, 0);
+            }else if(dto.getTimePeriod() != null && dto.getTimePeriod() == 2){
+                startTime = queryDate.atTime(12, 0, 0);
+                endTime = queryDate.atTime(18, 0, 0);
+            }else if(dto.getTimePeriod() != null && dto.getTimePeriod() == 3){
+                startTime = queryDate.atTime(18, 0, 0);
+                endTime = queryDate.atTime(23, 59, 59);
+            }else{
+                startTime = queryDate.atTime(0, 0, 0);
+                endTime = queryDate.atTime(23, 59, 59);
+            }
+            LocalDateTime lastSundayStart = startTime.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)).plusDays(-1);
+            LocalDateTime lastSundayEnd = endTime.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)).plusDays(-1);
+
+            //查询每个班的走读生实到人数
+            Map<Long, List<StudentOutInRecordVo>> notStayMap = studentOutInRecordService.getList(startTime, endTime, classIds);
+
+            //查询各班的请假人数
+            Map<Long, Integer> classLeaveCount = studentLeaveService.getClassLeaveCount(startTime, endTime);
+
+            for (ClassStatisticsVo record: attendancePage.getRecords()) {
+                Integer leaveCount = 0;
+                if(classLeaveCount.get(record.getId()) != null){
+                    leaveCount = classLeaveCount.get(record.getId());
+                }
+                record.setLeaveCount(leaveCount);
+                int actualCount = 0;
+                for (StudentOutInRecordVo outInRecordVo : notStayMap.get(record.getId())) {
+                    if(outInRecordVo.getStatus() == 1){
+                        actualCount ++;
+                    }
+                }
+                record.setActualCount(actualCount);
+
+                Integer lateCount = 0, playTruantCount = 0;
+                for (StudentOutInRecordVo outInRecord : notStayMap.get(record.getId())) {
+                    if(outInRecord.getStatus() == 0){
+                        continue;
+                    }
+                    if("迟到".equals(outInRecord.getAttendanceStatus())){
+                        lateCount ++;
+                    }else if("旷课".equals(outInRecord.getAttendanceStatus())){
+                        playTruantCount ++;
+                    }
+                }
+                record.setPlayTruantCount(playTruantCount);
+                record.setLateCount(lateCount);
+
+                //最后通过总人数-实到人数-请假人数计算出缺勤人数
+                record.setAbsenteeismCount(record.getStudentCount() - record.getLeaveCount() - record.getActualCount());
+
+                //计算出勤率
+                BigDecimal divide = BigDecimal.ZERO;
+                if(record.getStudentCount() != null && record.getStudentCount() != 0){
+                    divide = BigDecimal.valueOf(record.getActualCount()).divide(BigDecimal.valueOf(record.getStudentCount()), 4, RoundingMode.HALF_UP);
+                }
+                record.setAttendanceRate(divide.doubleValue());
+            }
+        }
+        PageOutput<ClassStatisticsVo> pageOutput = ConventPage.getPageOutput(attendancePage, ClassStatisticsVo.class);
+        return RT.ok(pageOutput);
+    }
+
+
+    @GetMapping(value = "/student-details")
+    @ApiOperation(value="学生考勤")
+    @SaCheckPermission("statistics:detail")
+    public RT<PageOutput<StudentStatisticsPageVo>> studentDetails(@Valid StudentDetailsDto dto){
+        MPJLambdaWrapper<User> queryUser = new MPJLambdaWrapper<>();
+        queryUser.disableSubLogicDel().distinct()
+                .like(StrUtil.isNotEmpty(dto.getName()), User::getName, dto.getName())
+                .like(StrUtil.isNotEmpty(dto.getCredentialNumber()), User::getCredentialNumber, dto.getCredentialNumber())
+                .eq(StrUtil.isNotEmpty(dto.getStduyStatus()), BaseStudentSchoolRoll::getStduyStatus, dto.getStduyStatus())
+                .eq(ObjectUtil.isNotNull(dto.getClassId()), BaseStudentSchoolRoll::getClassId, dto.getClassId())
+                .eq(BaseStudentSchoolRoll::getArchivesStatus, ArchivesStatusEnum.FB2901.getCode())
+                .selectAs(BaseClass::getName, StudentStatisticsPageVo::getClassName)
+                .select("t3.name", StudentStatisticsPageVo::getTeacherName)
+                .selectAs(User::getName, StudentStatisticsPageVo::getStudentName)
+                .selectAs(User::getMobile, StudentStatisticsPageVo::getMobile)
+                .selectAs(User::getId, StudentStatisticsPageVo::getUserId)
+                .selectAs(BaseStudentFamily::getTelephone, StudentStatisticsPageVo::getGuardianPhone)
+                .selectAs(DictionaryDetail::getName, StudentStatisticsPageVo::getStduyStatusCn)
+                .selectAs(User::getCredentialNumber, StudentStatisticsPageVo::getCredentialNumber)
+                .innerJoin(BaseStudentSchoolRoll.class, BaseStudentSchoolRoll::getUserId, User::getId)
+                .innerJoin(BaseClass.class, BaseClass::getId, BaseStudentSchoolRoll::getClassId)
+                .leftJoin(User.class, User::getId, BaseClass::getTeacherId)
+                .leftJoin(BaseStudentFamily.class, BaseStudentFamily::getUserId, User::getId)
+                .leftJoin(DictionaryDetail.class, DictionaryDetail::getCode, BaseStudentSchoolRoll::getStduyStatus);
+        IPage<StudentStatisticsPageVo> voIPage = xjrUserService.selectJoinListPage(ConventPage.getPage(dto), StudentStatisticsPageVo.class, queryUser);
+
+        if(dto.getDate() != null && !"".equals(dto.getDate())){
+            DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE;
+            LocalDate queryDate = LocalDate.parse(dto.getDate(), formatter);
+            LocalDateTime startTime, endTime;
+
+            if(dto.getTimePeriod() != null && dto.getTimePeriod() == 1){
+                startTime = queryDate.atTime(5, 0, 0);
+                endTime = queryDate.atTime(12, 0, 0);
+            }else if(dto.getTimePeriod() != null && dto.getTimePeriod() == 2){
+                startTime = queryDate.atTime(12, 0, 0);
+                endTime = queryDate.atTime(18, 0, 0);
+            }else if(dto.getTimePeriod() != null && dto.getTimePeriod() == 3){
+                startTime = queryDate.atTime(18, 0, 0);
+                endTime = queryDate.atTime(23, 59, 59);
+            }else{
+                startTime = queryDate.atTime(0, 0, 0);
+                endTime = queryDate.atTime(23, 59, 59);
+            }
+            //查询当前时间段存在请假的学生
+            Map<Long, StudentLeave> leaveList = studentLeaveService.getLeaveList(startTime, endTime);
+            //查询进入记录
+            List<StudentOutInRecord> outInRecords = studentOutInRecordService.list(
+                    new QueryWrapper<StudentOutInRecord>().lambda()
+                            .between(StudentOutInRecord::getRecordTime, startTime, endTime)
+                            .eq(StudentOutInRecord::getStatus, 1)
+            );
+            Map<Long, StudentOutInRecord> outInMap = new HashMap<>();
+            for (StudentOutInRecord inRecord : outInRecords) {
+                outInMap.put(inRecord.getUserId(), inRecord);
+            }
+            for (StudentStatisticsPageVo record : voIPage.getRecords()) {
+                StudentLeave studentLeave = leaveList.get(record.getUserId());
+                if(studentLeave != null){
+                    record.setStatus(studentLeave.getLeaveType());
+                }else{
+                    StudentOutInRecord outInRecord = outInMap.get(record.getUserId());
+                    if(outInRecord != null){
+                        record.setRecordTime(outInRecord.getRecordTime());
+                        record.setStatus(outInRecord.getAttendanceStatus());
+                    }else{
+                        record.setStatus("缺勤");
+                    }
+                }
+            }
+        }
+        PageOutput<StudentStatisticsPageVo> pageOutput = ConventPage.getPageOutput(voIPage, StudentStatisticsPageVo.class);
+        return RT.ok(pageOutput);
+    }
+
+
+    @GetMapping(value = "/class-history")
+    @ApiOperation(value="历史考勤")
+    @SaCheckPermission("statistics:detail")
+    public RT<PageOutput<ClassStatisticsVo>> classHistory(@Valid AttendanceStatisticDto dto){
+        Page<ClassStatisticsVo> attendancePage = classService.getAttendancePage(new Page<>(dto.getLimit(), dto.getSize()), dto);
+        List<Long> classIds = new ArrayList<>();
+        for (ClassStatisticsVo record : attendancePage.getRecords()) {
+            classIds.add(record.getId());
+        }
+        if(dto.getStartTime() != null && !"".equals(dto.getStartTime()) && dto.getEndTime() != null && !"".equals(dto.getEndTime())){
+            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);
+
+            //查询每个班的走读生实到人数
+            Map<Long, List<StudentOutInRecordVo>> notStayMap = studentOutInRecordService.getNotStayList(startTime, endTime, classIds);
+            //查询住校生的实到情况
+            Map<Long, List<StudentOutInRecordVo>> stayMap = studentOutInRecordService.getStayList(startTime, endTime, classIds);
+
+            //查询各班的请假人数
+            Map<Long, Integer> classLeaveCount = studentLeaveService.getClassLeaveCount(startTime, endTime);
+
+            //计算2个时间相差的天数
+            long days = ChronoUnit.DAYS.between(startTime.toLocalDate(), endTime.toLocalDate());
+            List<String> dayOfWeeks = new ArrayList<>();
+            for (int i = 0; i <= days; i ++){
+                dayOfWeeks.add(startTime.plusDays(i).getDayOfWeek().name());
+            }
+
+            for (ClassStatisticsVo record: attendancePage.getRecords()) {
+                record.setLeaveCount(classLeaveCount.get(record.getId()) == null ? 0:classLeaveCount.get(record.getId()));
+                record.setActualCount(notStayMap.get(record.getId()).size() + stayMap.get(record.getId()).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 ++;
+                        }
+                    }
+                }
+
+                record.setLateCount(lateCount);
+
+                //最后通过总人数-实到人数-请假人数计算出缺勤人数
+                record.setAbsenteeismCount(record.getStudentCount() - record.getLeaveCount() - record.getActualCount());
+
+                //计算出勤率
+                BigDecimal divide = BigDecimal.ZERO;
+                if(record.getStudentCount() != null && record.getStudentCount() != 0){
+                    divide = BigDecimal.valueOf(record.getActualCount()).divide(BigDecimal.valueOf(record.getStudentCount()), 4, RoundingMode.HALF_UP);
+                }
+                record.setAttendanceRate(divide.doubleValue());
+            }
+        }
+        PageOutput<ClassStatisticsVo> pageOutput = ConventPage.getPageOutput(attendancePage, ClassStatisticsVo.class);
+        return RT.ok(pageOutput);
+    }
+
+    @GetMapping(value = "/leaving-school")
+    @ApiOperation(value="离校统计")
+    @SaCheckPermission("statistics:detail")
+    public RT<PageOutput<ClassStatisticsVo>> leavingSchool(@Valid AttendanceStatisticDto dto){
+        Page<ClassStatisticsVo> attendancePage = classService.getAttendancePage(new Page<>(dto.getLimit(), dto.getSize()), dto);
+        List<Long> classIds = new ArrayList<>();
+        for (ClassStatisticsVo record : attendancePage.getRecords()) {
+            classIds.add(record.getId());
+        }
+        if(dto.getDate() != null && !"".equals(dto.getDate())){
+            DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE;
+            LocalDate queryDate = LocalDate.parse(dto.getDate(), formatter);
+            LocalDateTime startTime, endTime;
+
+
+            if(dto.getTimePeriod() != null && dto.getTimePeriod() == 1){
+                startTime = queryDate.atTime(5, 0, 0);
+                endTime = queryDate.atTime(12, 0, 0);
+            }else if(dto.getTimePeriod() != null && dto.getTimePeriod() == 2){
+                startTime = queryDate.atTime(12, 0, 0);
+                endTime = queryDate.atTime(18, 0, 0);
+            }else if(dto.getTimePeriod() != null && dto.getTimePeriod() == 3){
+                startTime = queryDate.atTime(18, 0, 0);
+                endTime = queryDate.atTime(23, 59, 59);
+            }else{
+                startTime = queryDate.atTime(0, 0, 0);
+                endTime = queryDate.atTime(23, 59, 59);
+            }
+            LocalDateTime lastSundayStart = startTime.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)).plusDays(-1);
+            LocalDateTime lastSundayEnd = endTime.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)).plusDays(-1);
+
+            //查询每个班的走读生实到人数
+            Map<Long, List<StudentOutInRecordVo>> notStayMap = studentOutInRecordService.getNotStayList(startTime, endTime, classIds);
+            //查询住校生的实到情况
+            Map<Long, List<StudentOutInRecordVo>> stayMap = studentOutInRecordService.getStayList(lastSundayStart, lastSundayEnd, classIds);
+
+            //查询各班的请假人数
+            Map<Long, Integer> classLeaveCount = studentLeaveService.getClassLeaveCount(startTime, endTime);
+
+            for (ClassStatisticsVo record: attendancePage.getRecords()) {
+                record.setLeaveCount(classLeaveCount.get(record.getId()));
+                record.setActualCount(notStayMap.get(record.getId()).size() + stayMap.get(record.getId()).size());
+
+                Integer lateCount = 0;
+                for (StudentOutInRecordVo outInRecord : notStayMap.get(record.getId())) {
+                    if(outInRecord.getStatus() == 1){
+                        continue;
+                    }
+                    if("迟到".equals(outInRecord.getAttendanceStatus())){
+                        lateCount ++;
+                    }
+                }
+                for (StudentOutInRecordVo outInRecord : stayMap.get(record.getId())) {
+                    if(outInRecord.getStatus() == 1){
+                        continue;
+                    }
+                    if("迟到".equals(outInRecord.getAttendanceStatus())){
+                        lateCount ++;
+                    }
+                }
+                record.setLateCount(lateCount);
+
+                //最后通过总人数-实到人数-请假人数计算出缺勤人数
+                record.setAbsenteeismCount(record.getStudentCount() - record.getLeaveCount() - record.getActualCount());
+
+                //计算出勤率
+                BigDecimal divide = BigDecimal.valueOf(record.getActualCount()).divide(BigDecimal.valueOf(record.getStudentCount()), 4, RoundingMode.HALF_UP);
+                record.setAttendanceRate(divide.doubleValue());
+            }
+        }
+        PageOutput<ClassStatisticsVo> pageOutput = ConventPage.getPageOutput(attendancePage, ClassStatisticsVo.class);
+        return RT.ok(pageOutput);
+    }
+
+}

+ 126 - 0
src/main/java/com/xjrsoft/module/attendance/controller/TeacherAttendanceRecordController.java

@@ -0,0 +1,126 @@
+package com.xjrsoft.module.attendance.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.github.yulichang.toolkit.MPJWrappers;
+import com.github.yulichang.wrapper.MPJLambdaWrapper;
+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.attendance.dto.AddTeacherAttendanceRecordDto;
+import com.xjrsoft.module.attendance.dto.UpdateTeacherAttendanceRecordDto;
+import cn.dev33.satoken.annotation.SaCheckPermission;
+
+import com.xjrsoft.module.attendance.dto.TeacherAttendanceRecordPageDto;
+import com.xjrsoft.module.attendance.entity.TeacherAttendanceRecord;
+import com.xjrsoft.module.attendance.service.ITeacherAttendanceRecordService;
+import com.xjrsoft.module.attendance.vo.TeacherAttendanceRecordPageVo;
+
+import com.xjrsoft.module.attendance.vo.TeacherAttendanceRecordVo;
+import com.xjrsoft.module.organization.entity.UserDeptRelation;
+import com.xjrsoft.module.outint.entity.TeacherOutInRecord;
+import com.xjrsoft.module.outint.vo.TeacherOutInRecordPageVo;
+import com.xjrsoft.module.system.entity.DictionaryDetail;
+import com.xjrsoft.module.teacher.entity.XjrUser;
+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.List;
+
+/**
+* @title: 教师考勤记录
+* @Author dzx
+* @Date: 2024-05-15
+* @Version 1.0
+*/
+@RestController
+@RequestMapping("/attendance" + "/teacherAttendanceRecord")
+@Api(value = "/attendance"  + "/teacherAttendanceRecord",tags = "教师考勤记录代码")
+@AllArgsConstructor
+public class TeacherAttendanceRecordController {
+
+
+    private final ITeacherAttendanceRecordService teacherAttendanceRecordService;
+
+    @GetMapping(value = "/page")
+    @ApiOperation(value="教师考勤记录列表(分页)")
+    @SaCheckPermission("teacherattendancerecord:detail")
+    public RT<PageOutput<TeacherAttendanceRecordPageVo>> page(@Valid TeacherAttendanceRecordPageDto dto){
+
+        MPJLambdaWrapper<TeacherAttendanceRecord> queryWrapper =  MPJWrappers.<TeacherAttendanceRecord>lambdaJoin()
+                .orderByDesc(TeacherAttendanceRecord::getId)
+                .like(StrUtil.isNotBlank(dto.getName()), XjrUser::getName,dto.getName())
+                .ge(ObjectUtil.isNotNull(dto.getStartTime()), TeacherAttendanceRecord::getCreateDate,dto.getStartTime()+" 00:00:00")
+                .le(ObjectUtil.isNotNull(dto.getStartTime()),TeacherAttendanceRecord::getCreateDate,dto.getStartTime()+" 23:59:59")
+                .eq(ObjectUtil.isNotNull(dto.getTimeInterval())&&dto.getTimeInterval()!=0, TeacherAttendanceRecord::getTimeInterval, dto.getTimeInterval())
+                .eq(StrUtil.isNotBlank(dto.getAttendanceStatus()), TeacherAttendanceRecord::getAttendanceStatus,dto.getAttendanceStatus())
+                .eq(ObjectUtil.isNotNull(dto.getAttendanceMode())&&dto.getAttendanceMode()!=0, TeacherAttendanceRecord::getAttendanceMode, dto.getAttendanceMode())
+                .like(StrUtil.isNotBlank(dto.getCarNumber()), TeacherAttendanceRecord::getCarNumber,dto.getCarNumber())
+                .select(TeacherAttendanceRecord::getId)
+                .select(TeacherAttendanceRecord.class,x -> VoToColumnUtil.fieldsToColumns(TeacherAttendanceRecordPageVo.class).contains(x.getProperty()))
+                .select(XjrUser::getName,XjrUser::getMobile,XjrUser::getCredentialNumber)
+                .leftJoin(XjrUser.class,XjrUser::getId,TeacherOutInRecord::getUserId)
+                .leftJoin(DictionaryDetail.class,DictionaryDetail::getCode, TeacherAttendanceRecord::getAttendanceStatus, ext->ext.selectAs(DictionaryDetail::getName, TeacherAttendanceRecordPageVo::getAttendanceStatusCn))
+                .leftJoin(DictionaryDetail.class,DictionaryDetail::getCode, XjrUser::getGender, ext->ext.selectAs(DictionaryDetail::getName, TeacherAttendanceRecordPageVo::getGender))
+                ;
+
+        if(ObjectUtil.isNotNull(dto.getDeptId())&&dto.getDeptId()!=0){
+            queryWrapper.leftJoin(UserDeptRelation.class,UserDeptRelation::getUserId,XjrUser::getId)
+                    .eq(UserDeptRelation::getDeptId,dto.getDeptId());
+        }
+        IPage<TeacherAttendanceRecordPageVo> page = teacherAttendanceRecordService.selectJoinListPage(ConventPage.getPage(dto), TeacherAttendanceRecordPageVo.class,queryWrapper);
+        PageOutput<TeacherAttendanceRecordPageVo> pageOutput = ConventPage.getPageOutput(page, TeacherAttendanceRecordPageVo.class);
+        return RT.ok(pageOutput);
+    }
+
+    @GetMapping(value = "/info")
+    @ApiOperation(value="根据id查询教师考勤记录信息")
+    @SaCheckPermission("teacherattendancerecord:detail")
+    public RT<TeacherAttendanceRecordVo> info(@RequestParam Long id){
+        TeacherAttendanceRecord teacherAttendanceRecord = teacherAttendanceRecordService.getById(id);
+        if (teacherAttendanceRecord == null) {
+           return RT.error("找不到此数据!");
+        }
+        return RT.ok(BeanUtil.toBean(teacherAttendanceRecord, TeacherAttendanceRecordVo.class));
+    }
+
+
+    @PostMapping
+    @ApiOperation(value = "新增教师考勤记录")
+    @SaCheckPermission("teacherattendancerecord:add")
+    public RT<Boolean> add(@Valid @RequestBody AddTeacherAttendanceRecordDto dto){
+        TeacherAttendanceRecord teacherAttendanceRecord = BeanUtil.toBean(dto, TeacherAttendanceRecord.class);
+        boolean isSuccess = teacherAttendanceRecordService.save(teacherAttendanceRecord);
+    return RT.ok(isSuccess);
+    }
+
+    @PutMapping
+    @ApiOperation(value = "修改教师考勤记录")
+    @SaCheckPermission("teacherattendancerecord:edit")
+    public RT<Boolean> update(@Valid @RequestBody UpdateTeacherAttendanceRecordDto dto){
+
+        TeacherAttendanceRecord teacherAttendanceRecord = BeanUtil.toBean(dto, TeacherAttendanceRecord.class);
+        return RT.ok(teacherAttendanceRecordService.updateById(teacherAttendanceRecord));
+
+    }
+
+    @DeleteMapping
+    @ApiOperation(value = "删除教师考勤记录")
+    @SaCheckPermission("teacherattendancerecord:delete")
+    public RT<Boolean> delete(@Valid @RequestBody List<Long> ids){
+        return RT.ok(teacherAttendanceRecordService.removeBatchByIds(ids));
+
+    }
+
+}

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

@@ -0,0 +1,124 @@
+package com.xjrsoft.module.attendance.controller;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.github.yulichang.wrapper.MPJLambdaWrapper;
+import com.xjrsoft.common.model.result.RT;
+import com.xjrsoft.common.page.ConventPage;
+import com.xjrsoft.common.page.PageOutput;
+import com.xjrsoft.module.attendance.dto.TeacherDetailsDto;
+import com.xjrsoft.module.attendance.vo.TeacherStatisticsPageVo;
+import com.xjrsoft.module.organization.entity.Department;
+import com.xjrsoft.module.organization.entity.User;
+import com.xjrsoft.module.organization.entity.UserDeptRelation;
+import com.xjrsoft.module.organization.service.IUserService;
+import com.xjrsoft.module.outint.entity.TeacherOutInRecord;
+import com.xjrsoft.module.outint.service.ITeacherOutInRecordService;
+import com.xjrsoft.module.teacher.entity.BaseTeacher;
+import com.xjrsoft.module.teacher.entity.WfTeacherleave;
+import com.xjrsoft.module.teacher.service.IWfTeacherleaveService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.AllArgsConstructor;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.validation.Valid;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+* @title: 教师考勤
+* @Author dzx
+* @Date: 2024-05-29
+* @Version 1.0
+*/
+@RestController
+@RequestMapping("/teacherStatistics")
+@Api(value = "/teacherStatistics" ,tags = "教师考勤统计")
+@AllArgsConstructor
+public class TeacherStatisticsController {
+
+
+    private final IUserService xjrUserService;
+    private final ITeacherOutInRecordService teacherOutInRecordService;
+    private final IWfTeacherleaveService wfTeacherleaveService;
+
+
+    @GetMapping(value = "/teacher-details")
+    @ApiOperation(value="教师考勤")
+    @SaCheckPermission("statistics:detail")
+    public RT<PageOutput<TeacherStatisticsPageVo>> teacherDetails(@Valid TeacherDetailsDto dto){
+        MPJLambdaWrapper<User> queryUser = new MPJLambdaWrapper<>();
+        queryUser.disableSubLogicDel().distinct()
+                .eq(ObjectUtil.isNotNull(dto.getDeptId()), UserDeptRelation::getDeptId, dto.getDeptId())
+                .like(StrUtil.isNotEmpty(dto.getName()), User::getName, dto.getName())
+                .selectAs(User::getName, TeacherStatisticsPageVo::getTeacherName)
+                .selectAs(User::getId, TeacherStatisticsPageVo::getUserId)
+                .selectAs(User::getMobile, TeacherStatisticsPageVo::getMobile)
+                .selectAs(Department::getName, TeacherStatisticsPageVo::getDeptName)
+                .innerJoin(BaseTeacher.class, BaseTeacher::getUserId, User::getId)
+                .innerJoin(UserDeptRelation.class, UserDeptRelation::getUserId, User::getId)
+                .leftJoin(Department.class, Department::getId, UserDeptRelation::getDeptId);
+        IPage<TeacherStatisticsPageVo> voIPage = xjrUserService.selectJoinListPage(ConventPage.getPage(dto), TeacherStatisticsPageVo.class, queryUser);
+
+        if(dto.getDate() != null && !"".equals(dto.getDate())){
+            DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE;
+            LocalDate queryDate = LocalDate.parse(dto.getDate(), formatter);
+            LocalDateTime startTime, endTime;
+
+            if(dto.getTimePeriod() == 1){
+                startTime = queryDate.atTime(5, 0, 0);
+                endTime = queryDate.atTime(12, 0, 0);
+            }else if(dto.getTimePeriod() == 2){
+                startTime = queryDate.atTime(12, 0, 0);
+                endTime = queryDate.atTime(18, 0, 0);
+            }else{
+                startTime = queryDate.atTime(0, 0, 0);
+                endTime = queryDate.atTime(23, 59, 59);
+            }
+
+            //查询当前时间段存在请假的教师
+            Map<Long, WfTeacherleave> leaveList = wfTeacherleaveService.getLeaveList(startTime, endTime);
+            //查询进入记录
+            List<TeacherOutInRecord> outInRecords = teacherOutInRecordService.list(
+                    new QueryWrapper<TeacherOutInRecord>().lambda()
+                            .between(TeacherOutInRecord::getRecordTime, startTime, endTime)
+                            .eq(TeacherOutInRecord::getStatus, 1)
+                            .orderByAsc(TeacherOutInRecord::getRecordTime)
+            );
+            Map<Long, TeacherOutInRecord> outInMap = new HashMap<>();
+            for (TeacherOutInRecord inRecord : outInRecords) {
+                if(outInMap.containsKey(inRecord.getUserId())){
+                    continue;
+                }
+                outInMap.put(inRecord.getUserId(), inRecord);
+            }
+            for (TeacherStatisticsPageVo record : voIPage.getRecords()) {
+                WfTeacherleave studentLeave = leaveList.get(record.getUserId());
+                if(studentLeave != null){
+                    record.setStatus(studentLeave.getLeaveType());
+                }else{
+                    TeacherOutInRecord outInRecord = outInMap.get(record.getUserId());
+                    if(outInRecord != null){
+                        record.setRecordTime(outInRecord.getRecordTime());
+                        record.setStatus(outInRecord.getAttendanceStatus());
+                    }else{
+                        record.setStatus("缺勤");
+                    }
+                }
+            }
+        }
+        PageOutput<TeacherStatisticsPageVo> pageOutput = ConventPage.getPageOutput(voIPage, TeacherStatisticsPageVo.class);
+        return RT.ok(pageOutput);
+    }
+
+}

+ 59 - 0
src/main/java/com/xjrsoft/module/attendance/dto/AddAttendanceMessageSetDto.java

@@ -0,0 +1,59 @@
+package com.xjrsoft.module.attendance.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;
+import com.xjrsoft.module.attendance.entity.AttendanceMessageUserRelation;
+
+
+
+/**
+* @title: 考勤消息设置
+* @Author dzx
+* @Date: 2024-05-21
+* @Version 1.0
+*/
+@Data
+public class AddAttendanceMessageSetDto implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+    * 
+    */
+    @ApiModelProperty("")
+    private Integer sortCode;
+    /**
+    * 人员类别(1:教职工 2:学生)
+    */
+    @ApiModelProperty("人员类别(1:教职工 2:学生)")
+    private Integer roleType;
+    /**
+    * 消息类别(1:迟到消息 2:旷课消息 3:缺勤消息)
+    */
+    @ApiModelProperty("消息类别(1:迟到消息 2:旷课消息 3:缺勤消息)")
+    private Integer messageCategory;
+    /**
+    * 时间段(1:上午 2:下午 3:晚上 4:返校)
+    */
+    @ApiModelProperty("时间段(1:上午 2:下午 3:晚上 4:返校)")
+    private String timePeriod;
+    /**
+    * 指定人员
+    */
+    @ApiModelProperty("指定人员")
+    private String userRelation;
+
+    /**
+    * attendanceMessageUserRelation
+    */
+    @ApiModelProperty("attendanceMessageUserRelation子表")
+    private List<AddAttendanceMessageUserRelationDto> attendanceMessageUserRelationList;
+}

+ 53 - 0
src/main/java/com/xjrsoft/module/attendance/dto/AddAttendanceMessageUserRelationDto.java

@@ -0,0 +1,53 @@
+package com.xjrsoft.module.attendance.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 dzx
+* @Date: 2024-05-21
+* @Version 1.0
+*/
+@Data
+public class AddAttendanceMessageUserRelationDto implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+    * 
+    */
+    @ApiModelProperty("")
+    private Integer sortCode;
+    /**
+    * 所属班级id
+    */
+    @ApiModelProperty("所属班级id")
+    private Long classId;
+    /**
+    * 所属部门id
+    */
+    @ApiModelProperty("所属部门id")
+    private Long deptId;
+    /**
+    * 用户id
+    */
+    @ApiModelProperty("用户id")
+    private Long userId;
+    /**
+    * 考勤消息设置(attendance_message_set)
+    */
+    @ApiModelProperty("考勤消息设置(attendance_message_set)")
+    private Long attendanceMessageSetId;
+
+}

+ 58 - 0
src/main/java/com/xjrsoft/module/attendance/dto/AddStudentAttendanceRecordDto.java

@@ -0,0 +1,58 @@
+package com.xjrsoft.module.attendance.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 dzx
+* @Date: 2024-05-15
+* @Version 1.0
+*/
+@Data
+public class AddStudentAttendanceRecordDto implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+    * 学生userId(xjr_user)
+    */
+    @ApiModelProperty("学生userId(xjr_user)")
+    private Long userId;
+    /**
+    * 班主人id(xjr_user)
+    */
+    @ApiModelProperty("班主人id(xjr_user)")
+    private Long teacherId;
+    /**
+    * 班级id(class)
+    */
+    @ApiModelProperty("班级id(class)")
+    private Long classId;
+    /**
+    * 就读方式(xjr_dictionary_item[stduy_status])
+    */
+    @ApiModelProperty("就读方式(xjr_dictionary_item[stduy_status])")
+    private String stduyStatus;
+    /**
+    * 考勤状态(xjr_dictionary_detail[attendance_status])
+    */
+    @ApiModelProperty("考勤状态(xjr_dictionary_detail[attendance_status])")
+    private String attendanceStatus;
+    /**
+    * 时段(1:上午,2:下午,3:晚上)
+    */
+    @ApiModelProperty("时段(1:上午,2:下午,3:晚上)")
+    private Integer timeInterval;
+
+}

+ 48 - 0
src/main/java/com/xjrsoft/module/attendance/dto/AddTeacherAttendanceRecordDto.java

@@ -0,0 +1,48 @@
+package com.xjrsoft.module.attendance.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 dzx
+* @Date: 2024-05-15
+* @Version 1.0
+*/
+@Data
+public class AddTeacherAttendanceRecordDto implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+    * 教师userId(xjr_user)
+    */
+    @ApiModelProperty("教师userId(xjr_user)")
+    private Long userId;
+    /**
+    * 考勤方式(1:人脸,2:车辆)
+    */
+    @ApiModelProperty("考勤方式(1:人脸,2:车辆)")
+    private Integer attendanceMode;
+    /**
+    * 考勤状态(xjr_dictionary_detail[attendance_status])
+    */
+    @ApiModelProperty("考勤状态(xjr_dictionary_detail[attendance_status])")
+    private String attendanceStatus;
+    /**
+    * 时段(1:上午,2:下午,3:晚上)
+    */
+    @ApiModelProperty("时段(1:上午,2:下午,3:晚上)")
+    private Integer timeInterval;
+
+}

+ 15 - 0
src/main/java/com/xjrsoft/module/attendance/dto/AttendanceMessageSetDto.java

@@ -0,0 +1,15 @@
+package com.xjrsoft.module.attendance.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class AttendanceMessageSetDto {
+    /**
+     * 人员类别(1:教职工 2:学生)
+     */
+    @ApiModelProperty("人员类别(1:教职工 2:学生)")
+    private  Integer roleType;
+}

+ 26 - 0
src/main/java/com/xjrsoft/module/attendance/dto/AttendanceMessageSetPageDto.java

@@ -0,0 +1,26 @@
+package com.xjrsoft.module.attendance.dto;
+
+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 dzx
+* @Date: 2024-05-21
+* @Version 1.0
+*/
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class AttendanceMessageSetPageDto extends PageInput {
+
+
+}

+ 34 - 0
src/main/java/com/xjrsoft/module/attendance/dto/AttendanceStatisticDto.java

@@ -0,0 +1,34 @@
+package com.xjrsoft.module.attendance.dto;
+
+import com.xjrsoft.common.page.PageInput;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.time.LocalDate;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class AttendanceStatisticDto extends PageInput {
+
+    @ApiModelProperty("时间段(1:上午 2:下午)")
+    private Integer timePeriod;
+
+    @ApiModelProperty("查询时间")
+    private String date;
+
+    @ApiModelProperty("查询开始时间")
+    private String startTime;
+
+    @ApiModelProperty("查询结束时间")
+    private String endTime;
+
+    @ApiModelProperty("年级id")
+    private Long gradeId;
+
+    @ApiModelProperty("班级id")
+    private Long classId;
+
+    @ApiModelProperty("部门id")
+    private Long deptId;
+}

+ 37 - 0
src/main/java/com/xjrsoft/module/attendance/dto/StudentAttendanceRecordClassPageDto.java

@@ -0,0 +1,37 @@
+package com.xjrsoft.module.attendance.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.xjrsoft.common.page.PageInput;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.time.LocalDateTime;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class StudentAttendanceRecordClassPageDto extends PageInput {
+
+    /**
+     * 记录开始时间
+     */
+    @ApiModelProperty("记录开始时间")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private LocalDateTime startTime;
+    /**
+     * 记录开始时间
+     */
+    @ApiModelProperty("记录结束时间")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private LocalDateTime endTime;
+    /**
+     * 班级id(class)
+     */
+    @ApiModelProperty("班级id(class)")
+    private Long classId;
+    /**
+     * 时段(1:上午,2:下午,3:晚上)
+     */
+    @ApiModelProperty("时段(1:上午,2:下午,3:晚上)")
+    private Integer timeInterval;
+}

+ 67 - 0
src/main/java/com/xjrsoft/module/attendance/dto/StudentAttendanceRecordPageDto.java

@@ -0,0 +1,67 @@
+package com.xjrsoft.module.attendance.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+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 dzx
+* @Date: 2024-05-15
+* @Version 1.0
+*/
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class StudentAttendanceRecordPageDto extends PageInput {
+    /**
+     * 记录开始时间
+     */
+    @ApiModelProperty("记录开始时间")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private LocalDateTime startTime;
+    /**
+     * 记录开始时间
+     */
+    @ApiModelProperty("记录结束时间")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private LocalDateTime endTime;
+    /**
+     * 班级id(class)
+     */
+    @ApiModelProperty("班级id(class)")
+    private Long classId;
+    /**
+     * 就读方式(xjr_dictionary_item[stduy_status])
+     */
+    @ApiModelProperty("就读方式(xjr_dictionary_item[stduy_status])")
+    private String stduyStatus;
+    /**
+     * 考勤状态(xjr_dictionary_detail[attendance_status])
+     */
+    @ApiModelProperty("考勤状态(xjr_dictionary_detail[attendance_status])")
+    private String attendanceStatus;
+    /**
+     * 时段(1:上午,2:下午,3:晚上)
+     */
+    @ApiModelProperty("时段(1:上午,2:下午,3:晚上)")
+    private Integer timeInterval;
+    /**
+     * 姓名
+     */
+    @ApiModelProperty("姓名")
+    private String name;
+    /**
+     * 身份证号
+     */
+    @ApiModelProperty("身份证号")
+    private String identityCard;
+}

+ 29 - 0
src/main/java/com/xjrsoft/module/attendance/dto/StudentDetailsDto.java

@@ -0,0 +1,29 @@
+package com.xjrsoft.module.attendance.dto;
+
+import com.xjrsoft.common.page.PageInput;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class StudentDetailsDto extends PageInput {
+
+    @ApiModelProperty("时间段(1:上午 2:下午)")
+    private Integer timePeriod;
+
+    @ApiModelProperty("查询时间")
+    private String date;
+
+    @ApiModelProperty("姓名")
+    private String name;
+
+    @ApiModelProperty("证件号码")
+    private String credentialNumber;
+
+    @ApiModelProperty("就读方式")
+    private String stduyStatus;
+
+    @ApiModelProperty("班级id")
+    private Long classId;
+}

+ 69 - 0
src/main/java/com/xjrsoft/module/attendance/dto/TeacherAttendanceRecordPageDto.java

@@ -0,0 +1,69 @@
+package com.xjrsoft.module.attendance.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+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 dzx
+* @Date: 2024-05-15
+* @Version 1.0
+*/
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class TeacherAttendanceRecordPageDto extends PageInput {
+
+    /**
+     * 记录开始时间
+     */
+    @ApiModelProperty("记录开始时间")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private LocalDateTime startTime;
+    /**
+     * 记录开始时间
+     */
+    @ApiModelProperty("记录结束时间")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private LocalDateTime endTime;
+    /**
+     * 考勤方式(1:人脸,2:车辆)
+     */
+    @ApiModelProperty("考勤方式(1:人脸,2:车辆)")
+    private Integer attendanceMode;
+    /**
+     * 考勤状态(xjr_dictionary_detail[attendance_status])
+     */
+    @ApiModelProperty("考勤状态(xjr_dictionary_detail[attendance_status])")
+    private String attendanceStatus;
+    /**
+     * 时段(1:上午,2:下午,3:晚上)
+     */
+    @ApiModelProperty("时段(1:上午,2:下午,3:晚上)")
+    private Integer timeInterval;
+    /**
+     * 车牌号
+     */
+    @ApiModelProperty("车牌号")
+    private String carNumber;
+    /**
+     * 教师姓名
+     */
+    @ApiModelProperty("教师姓名")
+    private String name;
+
+    /**
+     * 部门ID
+     */
+    @ApiModelProperty("部门ID")
+    private Long deptId;
+}

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

@@ -0,0 +1,26 @@
+package com.xjrsoft.module.attendance.dto;
+
+import com.xjrsoft.common.page.PageInput;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class TeacherDetailsDto extends PageInput {
+
+    @ApiModelProperty("时间段(1:上午 2:下午)")
+    private Integer timePeriod;
+
+    @ApiModelProperty("查询时间")
+    private String date;
+
+    @ApiModelProperty("姓名")
+    private String name;
+
+    @ApiModelProperty("证件号码")
+    private String credentialNumber;
+
+    @ApiModelProperty("部门id")
+    private Long deptId;
+}

+ 44 - 0
src/main/java/com/xjrsoft/module/attendance/dto/UpdateAttendanceMessageSetDto.java

@@ -0,0 +1,44 @@
+package com.xjrsoft.module.attendance.dto;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+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;
+import com.xjrsoft.module.attendance.entity.AttendanceMessageUserRelation;
+
+
+
+/**
+* @title: 考勤消息设置
+* @Author dzx
+* @Date: 2024-05-21
+* @Version 1.0
+*/
+@Data
+public class UpdateAttendanceMessageSetDto extends AddAttendanceMessageSetDto {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     *
+     */
+    @ApiModelProperty("")
+    @TableField(fill = FieldFill.INSERT)
+    @TableLogic
+    private Integer deleteMark;
+
+    /**
+    * 
+    */
+    @ApiModelProperty("")
+    private Long id;
+}

+ 32 - 0
src/main/java/com/xjrsoft/module/attendance/dto/UpdateStudentAttendanceRecordDto.java

@@ -0,0 +1,32 @@
+package com.xjrsoft.module.attendance.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 dzx
+* @Date: 2024-05-15
+* @Version 1.0
+*/
+@Data
+public class UpdateStudentAttendanceRecordDto extends AddStudentAttendanceRecordDto {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+    * 主键
+    */
+    @ApiModelProperty("主键")
+    private Long id;
+}

+ 32 - 0
src/main/java/com/xjrsoft/module/attendance/dto/UpdateTeacherAttendanceRecordDto.java

@@ -0,0 +1,32 @@
+package com.xjrsoft.module.attendance.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 dzx
+* @Date: 2024-05-15
+* @Version 1.0
+*/
+@Data
+public class UpdateTeacherAttendanceRecordDto extends AddTeacherAttendanceRecordDto {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+    * 主键
+    */
+    @ApiModelProperty("主键")
+    private Long id;
+}

+ 110 - 0
src/main/java/com/xjrsoft/module/attendance/entity/AttendanceMessageSet.java

@@ -0,0 +1,110 @@
+package com.xjrsoft.module.attendance.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 dzx
+* @Date: 2024-05-21
+* @Version 1.0
+*/
+@Data
+@TableName("attendance_message_set")
+@ApiModel(value = "attendance_message_set", description = "考勤消息设置")
+public class AttendanceMessageSet implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+    * 
+    */
+    @ApiModelProperty("")
+    @TableId
+    private Long id;
+    /**
+    * 
+    */
+    @ApiModelProperty("")
+    @TableField(fill = FieldFill.INSERT)
+    private Long createUserId;
+    /**
+    * 
+    */
+    @ApiModelProperty("")
+    @TableField(fill = FieldFill.INSERT)
+    private Date createDate;
+    /**
+    * 
+    */
+    @ApiModelProperty("")
+    @TableField(fill = FieldFill.UPDATE)
+    private Long modifyUserId;
+    /**
+    * 
+    */
+    @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;
+    /**
+    * 
+    */
+    @ApiModelProperty("")
+    private Integer sortCode;
+    /**
+    * 人员类别(1:教职工 2:学生)
+    */
+    @ApiModelProperty("人员类别(1:教职工 2:学生)")
+    private Integer roleType;
+    /**
+    * 消息类别(1:迟到消息 2:旷课消息 3:缺勤消息)
+    */
+    @ApiModelProperty("消息类别(1:迟到消息 2:旷课消息 3:缺勤消息)")
+    private Integer messageCategory;
+    /**
+    * 时间段(1:上午 2:下午 3:晚上 4:返校)
+    */
+    @ApiModelProperty("时间段(1:上午 2:下午 3:晚上 4:返校)")
+    private String timePeriod;
+    /**
+    * 指定人员
+    */
+    @ApiModelProperty("指定人员")
+    private String userRelation;
+
+    /**
+    * attendanceMessageUserRelation
+    */
+    @ApiModelProperty("attendanceMessageUserRelation子表")
+    @TableField(exist = false)
+    @EntityMapping(thisField = "id", joinField = "attendanceMessageSetId")
+    private List<AttendanceMessageUserRelation> attendanceMessageUserRelationList;
+
+}

+ 109 - 0
src/main/java/com/xjrsoft/module/attendance/entity/AttendanceMessageSet.java.1716253865126.bak

@@ -0,0 +1,109 @@
+package com.xjrsoft.module.attendance.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 dzx
+* @Date: 2024-05-20
+* @Version 1.0
+*/
+@Data
+@TableName("attendance_message_set")
+@ApiModel(value = "attendance_message_set", description = "考勤消息设置")
+public class AttendanceMessageSet implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+    * 
+    */
+    @ApiModelProperty("")
+    @TableId
+    private Long id;
+    /**
+    * 
+    */
+    @ApiModelProperty("")
+    @TableField(fill = FieldFill.INSERT)
+    private Long createUserId;
+    /**
+    * 
+    */
+    @ApiModelProperty("")
+    @TableField(fill = FieldFill.INSERT)
+    private Date createDate;
+    /**
+    * 
+    */
+    @ApiModelProperty("")
+    @TableField(fill = FieldFill.UPDATE)
+    private Long modifyUserId;
+    /**
+    * 
+    */
+    @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;
+    /**
+    * 
+    */
+    @ApiModelProperty("")
+    private Integer sortCode;
+    /**
+    * 消息类别(1:迟到消息 2:旷课消息 3:缺勤消息)
+    */
+    @ApiModelProperty("消息类别(1:迟到消息 2:旷课消息 3:缺勤消息)")
+    private Integer messageCategory;
+    /**
+    * 时间段(1:上午 2:下午 3:晚上 4:返校)
+    */
+    @ApiModelProperty("时间段(1:上午 2:下午 3:晚上 4:返校)")
+    private Integer timePeriod;
+    /**
+    * 指定人员
+    */
+    @ApiModelProperty("指定人员")
+    private String userRelation;
+    /**
+     * 人员类别(1:教职工 2:学生)
+     */
+    @ApiModelProperty("人员类别(1:教职工 2:学生)")
+    private  Integer roleType;
+    /**
+    * attendanceMessageUserRelation
+    */
+    @ApiModelProperty("attendanceMessageUserRelation子表")
+    @TableField(exist = false)
+    @EntityMapping(thisField = "id", joinField = "attendanceMessageSetId")
+    private List<AttendanceMessageUserRelation> attendanceMessageUserRelationList;
+
+}

+ 103 - 0
src/main/java/com/xjrsoft/module/attendance/entity/AttendanceMessageUserRelation.java

@@ -0,0 +1,103 @@
+package com.xjrsoft.module.attendance.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 dzx
+* @Date: 2024-05-21
+* @Version 1.0
+*/
+@Data
+@TableName("attendance_message_user_relation")
+@ApiModel(value = "attendance_message_user_relation", description = "考勤消息提醒人员")
+public class AttendanceMessageUserRelation implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+    * 
+    */
+    @ApiModelProperty("")
+    @TableId
+    private Long id;
+    /**
+    * 
+    */
+    @ApiModelProperty("")
+    @TableField(fill = FieldFill.INSERT)
+    private Long createUserId;
+    /**
+    * 
+    */
+    @ApiModelProperty("")
+    @TableField(fill = FieldFill.INSERT)
+    private Date createDate;
+    /**
+    * 
+    */
+    @ApiModelProperty("")
+    @TableField(fill = FieldFill.UPDATE)
+    private Long modifyUserId;
+    /**
+    * 
+    */
+    @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;
+    /**
+    * 
+    */
+    @ApiModelProperty("")
+    private Integer sortCode;
+    /**
+    * 所属班级id
+    */
+    @ApiModelProperty("所属班级id")
+    private Long classId;
+    /**
+    * 所属部门id
+    */
+    @ApiModelProperty("所属部门id")
+    private Long deptId;
+    /**
+    * 用户id
+    */
+    @ApiModelProperty("用户id")
+    private Long userId;
+    /**
+    * 考勤消息设置(attendance_message_set)
+    */
+    @ApiModelProperty("考勤消息设置(attendance_message_set)")
+    private Long attendanceMessageSetId;
+
+
+}

+ 103 - 0
src/main/java/com/xjrsoft/module/attendance/entity/AttendanceMessageUserRelation.java.1716253865128.bak

@@ -0,0 +1,103 @@
+package com.xjrsoft.module.attendance.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 dzx
+* @Date: 2024-05-20
+* @Version 1.0
+*/
+@Data
+@TableName("attendance_message_user_relation")
+@ApiModel(value = "attendance_message_user_relation", description = "考勤消息提醒人员")
+public class AttendanceMessageUserRelation implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+    * 
+    */
+    @ApiModelProperty("")
+    @TableId
+    private Long id;
+    /**
+    * 
+    */
+    @ApiModelProperty("")
+    @TableField(fill = FieldFill.INSERT)
+    private Long createUserId;
+    /**
+    * 
+    */
+    @ApiModelProperty("")
+    @TableField(fill = FieldFill.INSERT)
+    private Date createDate;
+    /**
+    * 
+    */
+    @ApiModelProperty("")
+    @TableField(fill = FieldFill.UPDATE)
+    private Long modifyUserId;
+    /**
+    * 
+    */
+    @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;
+    /**
+    * 
+    */
+    @ApiModelProperty("")
+    private Integer sortCode;
+    /**
+    * 所属班级id
+    */
+    @ApiModelProperty("所属班级id")
+    private Integer classId;
+    /**
+    * 所属部门id
+    */
+    @ApiModelProperty("所属部门id")
+    private Integer deptId;
+    /**
+    * 用户id
+    */
+    @ApiModelProperty("用户id")
+    private String userId;
+    /**
+    * 考勤消息设置(attendance_message_set)
+    */
+    @ApiModelProperty("考勤消息设置(attendance_message_set)")
+    private Long attendanceMessageSetId;
+
+
+}

+ 3 - 0
src/main/java/com/xjrsoft/module/attendance/entity/AttendanceRuleDetails.java

@@ -228,4 +228,7 @@ public class AttendanceRuleDetails implements Serializable {
 
     @ApiModelProperty("节假日迟到旷课时间")
     private Integer holidaysLateMinutes;
+
+    @ApiModelProperty("为节假日前一天时放学时间")
+    private LocalTime holidaysEndTime;
 }

+ 108 - 0
src/main/java/com/xjrsoft/module/attendance/entity/StudentAttendanceRecord.java

@@ -0,0 +1,108 @@
+package com.xjrsoft.module.attendance.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 dzx
+* @Date: 2024-05-15
+* @Version 1.0
+*/
+@Data
+@TableName("student_attendance_record")
+@ApiModel(value = "student_attendance_record", description = "学生考勤记录")
+public class StudentAttendanceRecord implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+    * 主键
+    */
+    @ApiModelProperty("主键")
+    @TableId
+    private Long id;
+    /**
+    * 创建人
+    */
+    @ApiModelProperty("创建人")
+    @TableField(fill = FieldFill.INSERT)
+    private Long createUserId;
+    /**
+    * 创建时间
+    */
+    @ApiModelProperty("创建时间")
+    @TableField(fill = FieldFill.INSERT)
+    private Date createDate;
+    /**
+    * 修改人id
+    */
+    @ApiModelProperty("修改人id")
+    @TableField(fill = FieldFill.UPDATE)
+    private Long modifyUserId;
+    /**
+    * 修改日期
+    */
+    @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;
+    /**
+    * 学生userId(xjr_user)
+    */
+    @ApiModelProperty("学生userId(xjr_user)")
+    private Long userId;
+    /**
+    * 班主人id(xjr_user)
+    */
+    @ApiModelProperty("班主人id(xjr_user)")
+    private Long teacherId;
+    /**
+    * 班级id(class)
+    */
+    @ApiModelProperty("班级id(class)")
+    private Long classId;
+    /**
+    * 就读方式(xjr_dictionary_item[stduy_status])
+    */
+    @ApiModelProperty("就读方式(xjr_dictionary_item[stduy_status])")
+    private String stduyStatus;
+    /**
+    * 考勤状态(xjr_dictionary_detail[attendance_status])
+    */
+    @ApiModelProperty("考勤状态(xjr_dictionary_detail[attendance_status])")
+    private String attendanceStatus;
+    /**
+    * 时段(1:上午,2:下午,3:晚上)
+    */
+    @ApiModelProperty("时段(1:上午,2:下午,3:晚上)")
+    private Integer timeInterval;
+
+
+}

+ 102 - 0
src/main/java/com/xjrsoft/module/attendance/entity/TeacherAttendanceRecord.java

@@ -0,0 +1,102 @@
+package com.xjrsoft.module.attendance.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 dzx
+* @Date: 2024-05-15
+* @Version 1.0
+*/
+@Data
+@TableName("teacher_attendance_record")
+@ApiModel(value = "teacher_attendance_record", description = "教师考勤记录")
+public class TeacherAttendanceRecord implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+    * 主键
+    */
+    @ApiModelProperty("主键")
+    @TableId
+    private Long id;
+    /**
+    * 创建人
+    */
+    @ApiModelProperty("创建人")
+    @TableField(fill = FieldFill.INSERT)
+    private Long createUserId;
+    /**
+    * 创建时间
+    */
+    @ApiModelProperty("创建时间")
+    @TableField(fill = FieldFill.INSERT)
+    private Date createDate;
+    /**
+    * 修改人id
+    */
+    @ApiModelProperty("修改人id")
+    @TableField(fill = FieldFill.UPDATE)
+    private Long modifyUserId;
+    /**
+    * 修改日期
+    */
+    @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;
+    /**
+    * 教师userId(xjr_user)
+    */
+    @ApiModelProperty("教师userId(xjr_user)")
+    private Long userId;
+    /**
+    * 考勤方式(1:人脸,2:车辆)
+    */
+    @ApiModelProperty("考勤方式(1:人脸,2:车辆)")
+    private Integer attendanceMode;
+    /**
+    * 考勤状态(xjr_dictionary_detail[attendance_status])
+    */
+    @ApiModelProperty("考勤状态(xjr_dictionary_detail[attendance_status])")
+    private String attendanceStatus;
+    /**
+    * 时段(1:上午,2:下午,3:晚上)
+    */
+    @ApiModelProperty("时段(1:上午,2:下午,3:晚上)")
+    private Integer timeInterval;
+    /**
+     * 车牌号
+     */
+    @ApiModelProperty("车牌号")
+    private String carNumber;
+
+}

+ 17 - 0
src/main/java/com/xjrsoft/module/attendance/mapper/AttendanceMessageSetMapper.java

@@ -0,0 +1,17 @@
+package com.xjrsoft.module.attendance.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.github.yulichang.base.MPJBaseMapper;
+import com.xjrsoft.module.attendance.entity.AttendanceMessageSet;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+* @title: 考勤消息设置
+* @Author dzx
+* @Date: 2024-05-21
+* @Version 1.0
+*/
+@Mapper
+public interface AttendanceMessageSetMapper extends MPJBaseMapper<AttendanceMessageSet> {
+
+}

+ 17 - 0
src/main/java/com/xjrsoft/module/attendance/mapper/AttendanceMessageUserRelationMapper.java

@@ -0,0 +1,17 @@
+package com.xjrsoft.module.attendance.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.github.yulichang.base.MPJBaseMapper;
+import com.xjrsoft.module.attendance.entity.AttendanceMessageUserRelation;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+* @title: 考勤消息提醒人员
+* @Author dzx
+* @Date: 2024-05-21
+* @Version 1.0
+*/
+@Mapper
+public interface AttendanceMessageUserRelationMapper extends MPJBaseMapper<AttendanceMessageUserRelation> {
+
+}

+ 9 - 0
src/main/java/com/xjrsoft/module/attendance/mapper/AttendanceRuleDetailsMapper.java

@@ -2,7 +2,11 @@ package com.xjrsoft.module.attendance.mapper;
 
 import com.github.yulichang.base.MPJBaseMapper;
 import com.xjrsoft.module.attendance.entity.AttendanceRuleDetails;
+import com.xjrsoft.module.attendance.vo.AttendanceRuleDetailsUserVo;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
 
 /**
 * @title: 考勤规则细则
@@ -12,5 +16,10 @@ import org.apache.ibatis.annotations.Mapper;
 */
 @Mapper
 public interface AttendanceRuleDetailsMapper extends MPJBaseMapper<AttendanceRuleDetails> {
+    List<AttendanceRuleDetails> getTodayRules(@Param("dayOfWeek") String dayOfWeek);
+
+    List<AttendanceRuleDetailsUserVo> getAllTeacherTodyRule(@Param("dayOfWeek") String dayOfWeek);
+
+    List<AttendanceRuleDetailsUserVo> getAllStudentTodyRule(@Param("dayOfWeek") String dayOfWeek);
 
 }

+ 17 - 0
src/main/java/com/xjrsoft/module/attendance/mapper/StudentAttendanceRecordMapper.java

@@ -0,0 +1,17 @@
+package com.xjrsoft.module.attendance.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.github.yulichang.base.MPJBaseMapper;
+import com.xjrsoft.module.attendance.entity.StudentAttendanceRecord;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+* @title: 学生考勤记录
+* @Author dzx
+* @Date: 2024-05-15
+* @Version 1.0
+*/
+@Mapper
+public interface StudentAttendanceRecordMapper extends MPJBaseMapper<StudentAttendanceRecord> {
+
+}

+ 17 - 0
src/main/java/com/xjrsoft/module/attendance/mapper/TeacherAttendanceRecordMapper.java

@@ -0,0 +1,17 @@
+package com.xjrsoft.module.attendance.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.github.yulichang.base.MPJBaseMapper;
+import com.xjrsoft.module.attendance.entity.TeacherAttendanceRecord;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+* @title: 教师考勤记录
+* @Author dzx
+* @Date: 2024-05-15
+* @Version 1.0
+*/
+@Mapper
+public interface TeacherAttendanceRecordMapper extends MPJBaseMapper<TeacherAttendanceRecord> {
+
+}

+ 49 - 0
src/main/java/com/xjrsoft/module/attendance/service/IAttendanceMessageSetService.java

@@ -0,0 +1,49 @@
+package com.xjrsoft.module.attendance.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.github.yulichang.base.MPJBaseService;
+import com.xjrsoft.module.attendance.dto.UpdateAttendanceMessageSetDto;
+import com.xjrsoft.module.attendance.entity.AttendanceMessageSet;
+import lombok.Data;
+import java.util.List;
+
+/**
+* @title: 考勤消息设置
+* @Author dzx
+* @Date: 2024-05-21
+* @Version 1.0
+*/
+
+public interface IAttendanceMessageSetService extends MPJBaseService<AttendanceMessageSet> {
+    /**
+    * 新增
+    *
+    * @param attendanceMessageSet
+    * @return
+    */
+    Boolean add(AttendanceMessageSet attendanceMessageSet);
+
+    /**
+    * 更新
+    *
+    * @param attendanceMessageSet
+    * @return
+    */
+    Boolean update(AttendanceMessageSet attendanceMessageSet);
+
+    /**
+     * 更新
+     *
+     * @param attendanceMessageSetDtos
+     * @return
+     */
+    Boolean edit(List<UpdateAttendanceMessageSetDto>  attendanceMessageSetDtos);
+
+    /**
+    * 删除
+    *
+    * @param ids
+    * @return
+    */
+    Boolean delete(List<Long> ids);
+}

+ 17 - 0
src/main/java/com/xjrsoft/module/attendance/service/IAttendanceRuleCategoryService.java

@@ -4,8 +4,11 @@ import com.github.yulichang.base.MPJBaseService;
 import com.xjrsoft.module.attendance.dto.AddAttendanceRuleCategoryDto;
 import com.xjrsoft.module.attendance.dto.UpdateAttendanceRuleCategoryDto;
 import com.xjrsoft.module.attendance.entity.AttendanceRuleCategory;
+import com.xjrsoft.module.attendance.entity.AttendanceRuleDetails;
+import com.xjrsoft.module.attendance.vo.AttendanceRuleDetailsUserVo;
 
 import java.util.List;
+import java.util.Map;
 
 /**
 * @title: 考勤规则
@@ -38,4 +41,18 @@ public interface IAttendanceRuleCategoryService extends MPJBaseService<Attendanc
     * @return
     */
     Boolean delete(List<Long> ids);
+
+    List<AttendanceRuleDetails> getTodayRules();
+
+    AttendanceRuleDetails getTodayRulesByParam(String dayOfWeek);
+
+    Map<Long, AttendanceRuleDetailsUserVo> getAllTeacherTodyRule(String dayOfWeek);
+
+    Map<Long, AttendanceRuleDetailsUserVo> getAllStudentTodyRule(String dayOfWeek);
+
+
+    Map<String, Map<Long, AttendanceRuleDetailsUserVo>> getAllTeacherTodyRule(List<String> dayOfWeek);
+
+    Map<String, Map<Long, AttendanceRuleDetailsUserVo>> getAllStudentTodyRule(List<String> dayOfWeek);
+
 }

+ 17 - 0
src/main/java/com/xjrsoft/module/attendance/service/IStudentAttendanceRecordService.java

@@ -0,0 +1,17 @@
+package com.xjrsoft.module.attendance.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.github.yulichang.base.MPJBaseService;
+import com.xjrsoft.module.attendance.entity.StudentAttendanceRecord;
+import lombok.Data;
+import java.util.List;
+
+/**
+* @title: 学生考勤记录
+* @Author dzx
+* @Date: 2024-05-15
+* @Version 1.0
+*/
+
+public interface IStudentAttendanceRecordService extends MPJBaseService<StudentAttendanceRecord> {
+}

+ 17 - 0
src/main/java/com/xjrsoft/module/attendance/service/ITeacherAttendanceRecordService.java

@@ -0,0 +1,17 @@
+package com.xjrsoft.module.attendance.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.github.yulichang.base.MPJBaseService;
+import com.xjrsoft.module.attendance.entity.TeacherAttendanceRecord;
+import lombok.Data;
+import java.util.List;
+
+/**
+* @title: 教师考勤记录
+* @Author dzx
+* @Date: 2024-05-15
+* @Version 1.0
+*/
+
+public interface ITeacherAttendanceRecordService extends MPJBaseService<TeacherAttendanceRecord> {
+}

+ 113 - 0
src/main/java/com/xjrsoft/module/attendance/service/impl/AttendanceMessageSetServiceImpl.java

@@ -0,0 +1,113 @@
+package com.xjrsoft.module.attendance.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.github.yulichang.base.MPJBaseServiceImpl;
+import com.xjrsoft.module.attendance.dto.UpdateAttendanceMessageSetDto;
+import com.xjrsoft.module.attendance.entity.AttendanceMessageUserRelation;
+import com.xjrsoft.module.attendance.mapper.AttendanceMessageUserRelationMapper;
+import com.xjrsoft.module.attendance.entity.AttendanceMessageSet;
+import com.xjrsoft.module.attendance.mapper.AttendanceMessageSetMapper;
+import com.xjrsoft.module.attendance.service.IAttendanceMessageSetService;
+import lombok.AllArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+
+/**
+* @title: 考勤消息设置
+* @Author dzx
+* @Date: 2024-05-21
+* @Version 1.0
+*/
+@Service
+@AllArgsConstructor
+public class AttendanceMessageSetServiceImpl extends MPJBaseServiceImpl<AttendanceMessageSetMapper, AttendanceMessageSet> implements IAttendanceMessageSetService {
+    private final AttendanceMessageSetMapper attendanceMessageSetAttendanceMessageSetMapper;
+
+    private final AttendanceMessageUserRelationMapper attendanceMessageSetAttendanceMessageUserRelationMapper;
+
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean add(AttendanceMessageSet attendanceMessageSet) {
+        attendanceMessageSetAttendanceMessageSetMapper.insert(attendanceMessageSet);
+        for (AttendanceMessageUserRelation attendanceMessageUserRelation : attendanceMessageSet.getAttendanceMessageUserRelationList()) {
+            attendanceMessageUserRelation.setAttendanceMessageSetId(attendanceMessageSet.getId());
+            attendanceMessageSetAttendanceMessageUserRelationMapper.insert(attendanceMessageUserRelation);
+        }
+
+        return true;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean update(AttendanceMessageSet attendanceMessageSet) {
+        attendanceMessageSetAttendanceMessageSetMapper.updateById(attendanceMessageSet);
+        //********************************* AttendanceMessageUserRelation  增删改  开始 *******************************************/
+        {
+            // 查出所有子级的id
+            List<AttendanceMessageUserRelation> attendanceMessageUserRelationList = attendanceMessageSetAttendanceMessageUserRelationMapper.selectList(Wrappers.lambdaQuery(AttendanceMessageUserRelation.class).eq(AttendanceMessageUserRelation::getAttendanceMessageSetId, attendanceMessageSet.getId()).select(AttendanceMessageUserRelation::getId));
+            List<Long> attendanceMessageUserRelationIds = attendanceMessageUserRelationList.stream().map(AttendanceMessageUserRelation::getId).collect(Collectors.toList());
+            //原有子表单 没有被删除的主键
+            List<Long> attendanceMessageUserRelationOldIds = attendanceMessageSet.getAttendanceMessageUserRelationList().stream().map(AttendanceMessageUserRelation::getId).filter(Objects::nonNull).collect(Collectors.toList());
+            //找到需要删除的id
+            List<Long> attendanceMessageUserRelationRemoveIds = attendanceMessageUserRelationIds.stream().filter(item -> !attendanceMessageUserRelationOldIds.contains(item)).collect(Collectors.toList());
+
+            for (AttendanceMessageUserRelation attendanceMessageUserRelation : attendanceMessageSet.getAttendanceMessageUserRelationList()) {
+                //如果不等于空则修改
+                if (attendanceMessageUserRelation.getId() != null) {
+                    attendanceMessageSetAttendanceMessageUserRelationMapper.updateById(attendanceMessageUserRelation);
+                }
+                //如果等于空 则新增
+                else {
+                    //已经不存在的id 删除
+                    attendanceMessageUserRelation.setAttendanceMessageSetId(attendanceMessageSet.getId());
+                    attendanceMessageSetAttendanceMessageUserRelationMapper.insert(attendanceMessageUserRelation);
+                }
+            }
+            //已经不存在的id 删除
+            if(attendanceMessageUserRelationRemoveIds.size() > 0){
+                attendanceMessageSetAttendanceMessageUserRelationMapper.deleteBatchIds(attendanceMessageUserRelationRemoveIds);
+            }
+        }
+        //********************************* AttendanceMessageUserRelation  增删改  结束 *******************************************/
+
+        return true;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean edit(List<UpdateAttendanceMessageSetDto>  attendanceMessageSetDtos) {
+        for (UpdateAttendanceMessageSetDto attendanceMessageSetDto : attendanceMessageSetDtos) {
+            // 先删除 再添加
+            AttendanceMessageSet attendanceMessageSetDel = attendanceMessageSetAttendanceMessageSetMapper.selectOne(Wrappers.lambdaQuery(AttendanceMessageSet.class)
+                    .eq(AttendanceMessageSet::getRoleType, attendanceMessageSetDto.getRoleType())
+                    .eq(AttendanceMessageSet::getMessageCategory, attendanceMessageSetDto.getMessageCategory()));
+            if (attendanceMessageSetDel != null) {
+                attendanceMessageSetAttendanceMessageSetMapper.deleteById(attendanceMessageSetDel.getId());
+                attendanceMessageSetAttendanceMessageUserRelationMapper.delete(Wrappers.lambdaQuery(AttendanceMessageUserRelation.class).eq(AttendanceMessageUserRelation::getAttendanceMessageSetId, attendanceMessageSetDel.getId()));
+            }
+
+            if (attendanceMessageSetDto.getDeleteMark() != 1) {
+                AttendanceMessageSet attendanceMessageSet = BeanUtil.toBean(attendanceMessageSetDto, AttendanceMessageSet.class);
+                add(attendanceMessageSet);
+            }
+
+        }
+        return true;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean delete(List<Long> ids) {
+        attendanceMessageSetAttendanceMessageSetMapper.deleteBatchIds(ids);
+        attendanceMessageSetAttendanceMessageUserRelationMapper.delete(Wrappers.lambdaQuery(AttendanceMessageUserRelation.class).in(AttendanceMessageUserRelation::getAttendanceMessageSetId, ids));
+
+        return true;
+    }
+}

+ 75 - 0
src/main/java/com/xjrsoft/module/attendance/service/impl/AttendanceRuleCategoryServiceImpl.java

@@ -19,6 +19,7 @@ import com.xjrsoft.module.attendance.mapper.AttendanceRuleCategoryMapper;
 import com.xjrsoft.module.attendance.mapper.AttendanceRuleDetailsMapper;
 import com.xjrsoft.module.attendance.mapper.AttendanceUserRelationMapper;
 import com.xjrsoft.module.attendance.service.IAttendanceRuleCategoryService;
+import com.xjrsoft.module.attendance.vo.AttendanceRuleDetailsUserVo;
 import com.xjrsoft.module.concat.service.IXjrUserService;
 import com.xjrsoft.module.organization.entity.UserDeptRelation;
 import com.xjrsoft.module.student.entity.BaseStudent;
@@ -30,9 +31,13 @@ import lombok.AllArgsConstructor;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.time.DayOfWeek;
+import java.time.LocalDateTime;
 import java.util.ArrayList;
 import java.util.Date;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 import java.util.stream.Collectors;
 
@@ -255,6 +260,7 @@ public class AttendanceRuleCategoryServiceImpl extends MPJBaseServiceImpl<Attend
             if(attendanceRuleCategory.getAttendanceRange() == 1){
                 List<XjrUser> userList = xjrUserService.list(
                     new MPJLambdaWrapper<XjrUser>()
+                    .select(XjrUser::getId)
                     .select(XjrUser.class, x -> VoToColumnUtil.fieldsToColumns(XjrUser.class).contains(x.getProperty()))
                     .leftJoin(BaseTeacher.class, BaseTeacher::getUserId, XjrUser::getId)
                     .eq(BaseTeacher::getDeleteMark, DeleteMark.NODELETE.getCode())
@@ -277,6 +283,7 @@ public class AttendanceRuleCategoryServiceImpl extends MPJBaseServiceImpl<Attend
 
                 List<XjrUser> userList = xjrUserService.list(
                     new MPJLambdaWrapper<XjrUser>()
+                    .select(XjrUser::getId)
                     .select(XjrUser.class, x -> VoToColumnUtil.fieldsToColumns(XjrUser.class).contains(x.getProperty()))
                     .leftJoin(BaseTeacher.class, BaseTeacher::getUserId, XjrUser::getId)
                     .leftJoin(UserDeptRelation.class, UserDeptRelation::getUserId, XjrUser::getId)
@@ -289,6 +296,7 @@ public class AttendanceRuleCategoryServiceImpl extends MPJBaseServiceImpl<Attend
                 List<Long> relationUserIds = userList.stream().map(XjrUser::getId).collect(Collectors.toList());
                 List<XjrUser> relations = xjrUserService.list(
                     new MPJLambdaWrapper<XjrUser>()
+                    .select(XjrUser::getId)
                     .select(XjrUser.class, x -> VoToColumnUtil.fieldsToColumns(XjrUser.class).contains(x.getProperty()))
                     .leftJoin(AttendanceUserRelation.class, AttendanceUserRelation::getUserId, XjrUser::getId)
                     .eq(AttendanceUserRelation::getDeleteMark, DeleteMark.NODELETE.getCode())
@@ -344,6 +352,7 @@ public class AttendanceRuleCategoryServiceImpl extends MPJBaseServiceImpl<Attend
 
                 List<XjrUser> userList = xjrUserService.list(
                     new MPJLambdaWrapper<XjrUser>()
+                    .select(XjrUser::getId)
                     .select(XjrUser.class, x -> VoToColumnUtil.fieldsToColumns(XjrUser.class).contains(x.getProperty()))
                     .leftJoin(BaseStudentSchoolRoll.class, BaseStudentSchoolRoll::getUserId, XjrUser::getId)
                     .eq(BaseStudentSchoolRoll::getDeleteMark, DeleteMark.NODELETE.getCode())
@@ -355,6 +364,7 @@ public class AttendanceRuleCategoryServiceImpl extends MPJBaseServiceImpl<Attend
                 List<Long> relationUserIds = userList.stream().map(XjrUser::getId).collect(Collectors.toList());
                 List<XjrUser> relations = xjrUserService.list(
                     new MPJLambdaWrapper<XjrUser>()
+                    .select(XjrUser::getId)
                     .select(XjrUser.class, x -> VoToColumnUtil.fieldsToColumns(XjrUser.class).contains(x.getProperty()))
                     .leftJoin(AttendanceUserRelation.class, AttendanceUserRelation::getUserId, XjrUser::getId)
                     .eq(AttendanceUserRelation::getDeleteMark, DeleteMark.NODELETE.getCode())
@@ -401,4 +411,69 @@ public class AttendanceRuleCategoryServiceImpl extends MPJBaseServiceImpl<Attend
 
         return true;
     }
+
+    @Override
+    public List<AttendanceRuleDetails> getTodayRules() {
+        LocalDateTime now = LocalDateTime.now();
+        DayOfWeek dayOfWeek = now.getDayOfWeek();
+        return detailsMapper.getTodayRules(dayOfWeek.name());
+    }
+
+    @Override
+    public AttendanceRuleDetails getTodayRulesByParam(String dayOfWeek) {
+        return null;
+    }
+
+    @Override
+    public Map<Long, AttendanceRuleDetailsUserVo> getAllTeacherTodyRule(String dayOfWeek) {
+        List<AttendanceRuleDetailsUserVo> teacherTodyRule = detailsMapper.getAllTeacherTodyRule(dayOfWeek);
+        Map<Long, AttendanceRuleDetailsUserVo> result = new HashMap<>();
+        for (AttendanceRuleDetailsUserVo userVo : teacherTodyRule) {
+            result.put(userVo.getUserId(), userVo);
+        }
+
+        return result;
+    }
+
+    @Override
+    public Map<Long, AttendanceRuleDetailsUserVo> getAllStudentTodyRule(String dayOfWeek) {
+        List<AttendanceRuleDetailsUserVo> teacherTodyRule = detailsMapper.getAllStudentTodyRule(dayOfWeek);
+        Map<Long, AttendanceRuleDetailsUserVo> result = new HashMap<>();
+        for (AttendanceRuleDetailsUserVo userVo : teacherTodyRule) {
+            result.put(userVo.getUserId(), userVo);
+        }
+
+        return result;
+    }
+
+    @Override
+    public Map<String, Map<Long, AttendanceRuleDetailsUserVo>> getAllTeacherTodyRule(List<String> dayOfWeek) {
+
+        Map<String, Map<Long, AttendanceRuleDetailsUserVo>> result = new HashMap<>();
+        for (String s : dayOfWeek) {
+            List<AttendanceRuleDetailsUserVo> teacherTodyRule = detailsMapper.getAllTeacherTodyRule(s);
+            Map<Long, AttendanceRuleDetailsUserVo> dataMap = new HashMap<>();
+            for (AttendanceRuleDetailsUserVo userVo : teacherTodyRule) {
+                dataMap.put(userVo.getUserId(), userVo);
+            }
+            result.put(s, dataMap);
+        }
+
+        return result;
+    }
+
+    @Override
+    public Map<String, Map<Long, AttendanceRuleDetailsUserVo>> getAllStudentTodyRule(List<String> dayOfWeek) {
+        Map<String, Map<Long, AttendanceRuleDetailsUserVo>> result = new HashMap<>();
+        for (String s : dayOfWeek) {
+            List<AttendanceRuleDetailsUserVo> teacherTodyRule = detailsMapper.getAllStudentTodyRule(s);
+            Map<Long, AttendanceRuleDetailsUserVo> dataMap = new HashMap<>();
+            for (AttendanceRuleDetailsUserVo userVo : teacherTodyRule) {
+                dataMap.put(userVo.getUserId(), userVo);
+            }
+            result.put(s, dataMap);
+        }
+
+        return result;
+    }
 }

+ 25 - 0
src/main/java/com/xjrsoft/module/attendance/service/impl/StudentAttendanceRecordServiceImpl.java

@@ -0,0 +1,25 @@
+package com.xjrsoft.module.attendance.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.github.yulichang.base.MPJBaseServiceImpl;
+import com.xjrsoft.module.attendance.entity.StudentAttendanceRecord;
+import com.xjrsoft.module.attendance.mapper.StudentAttendanceRecordMapper;
+import com.xjrsoft.module.attendance.service.IStudentAttendanceRecordService;
+import lombok.AllArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+
+/**
+* @title: 学生考勤记录
+* @Author dzx
+* @Date: 2024-05-15
+* @Version 1.0
+*/
+@Service
+@AllArgsConstructor
+public class StudentAttendanceRecordServiceImpl extends MPJBaseServiceImpl<StudentAttendanceRecordMapper, StudentAttendanceRecord> implements IStudentAttendanceRecordService {
+}

+ 25 - 0
src/main/java/com/xjrsoft/module/attendance/service/impl/TeacherAttendanceRecordServiceImpl.java

@@ -0,0 +1,25 @@
+package com.xjrsoft.module.attendance.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.github.yulichang.base.MPJBaseServiceImpl;
+import com.xjrsoft.module.attendance.entity.TeacherAttendanceRecord;
+import com.xjrsoft.module.attendance.mapper.TeacherAttendanceRecordMapper;
+import com.xjrsoft.module.attendance.service.ITeacherAttendanceRecordService;
+import lombok.AllArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+
+/**
+* @title: 教师考勤记录
+* @Author dzx
+* @Date: 2024-05-15
+* @Version 1.0
+*/
+@Service
+@AllArgsConstructor
+public class TeacherAttendanceRecordServiceImpl extends MPJBaseServiceImpl<TeacherAttendanceRecordMapper, TeacherAttendanceRecord> implements ITeacherAttendanceRecordService {
+}

+ 84 - 0
src/main/java/com/xjrsoft/module/attendance/vo/AttendanceMessageSetPageVo.java

@@ -0,0 +1,84 @@
+package com.xjrsoft.module.attendance.vo;
+
+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 dzx
+* @Date: 2024-05-21
+* @Version 1.0
+*/
+@Data
+public class AttendanceMessageSetPageVo {
+
+    /**
+    * 
+    */
+    @ApiModelProperty("")
+    private String id;
+    /**
+    * 
+    */
+    @ApiModelProperty("")
+    private Long createUserId;
+    /**
+    * 
+    */
+    @ApiModelProperty("")
+    private Date createDate;
+    /**
+    * 
+    */
+    @ApiModelProperty("")
+    private Long modifyUserId;
+    /**
+    * 
+    */
+    @ApiModelProperty("")
+    private Date modifyDate;
+    /**
+    * 
+    */
+    @ApiModelProperty("")
+    private Integer deleteMark;
+    /**
+    * 
+    */
+    @ApiModelProperty("")
+    private Integer enabledMark;
+    /**
+    * 
+    */
+    @ApiModelProperty("")
+    private Integer sortCode;
+    /**
+    * 人员类别(1:教职工 2:学生)
+    */
+    @ApiModelProperty("人员类别(1:教职工 2:学生)")
+    private Integer roleType;
+    /**
+    * 消息类别(1:迟到消息 2:旷课消息 3:缺勤消息)
+    */
+    @ApiModelProperty("消息类别(1:迟到消息 2:旷课消息 3:缺勤消息)")
+    private Integer messageCategory;
+    /**
+    * 时间段(1:上午 2:下午 3:晚上 4:返校)
+    */
+    @ApiModelProperty("时间段(1:上午 2:下午 3:晚上 4:返校)")
+    private String timePeriod;
+    /**
+    * 指定人员
+    */
+    @ApiModelProperty("指定人员")
+    private String userRelation;
+
+}

+ 60 - 0
src/main/java/com/xjrsoft/module/attendance/vo/AttendanceMessageSetVo.java

@@ -0,0 +1,60 @@
+package com.xjrsoft.module.attendance.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;
+import com.xjrsoft.module.attendance.entity.AttendanceMessageUserRelation;
+
+/**
+* @title: 考勤消息设置表单出参
+* @Author dzx
+* @Date: 2024-05-21
+* @Version 1.0
+*/
+@Data
+public class AttendanceMessageSetVo {
+
+    /**
+    * 
+    */
+    @ApiModelProperty("")
+    private Long id;
+    /**
+    * 
+    */
+    @ApiModelProperty("")
+    private Integer sortCode;
+    /**
+    * 人员类别(1:教职工 2:学生)
+    */
+    @ApiModelProperty("人员类别(1:教职工 2:学生)")
+    private Integer roleType;
+    /**
+    * 消息类别(1:迟到消息 2:旷课消息 3:缺勤消息)
+    */
+    @ApiModelProperty("消息类别(1:迟到消息 2:旷课消息 3:缺勤消息)")
+    private Integer messageCategory;
+    /**
+    * 时间段(1:上午 2:下午 3:晚上 4:返校)
+    */
+    @ApiModelProperty("时间段(1:上午 2:下午 3:晚上 4:返校)")
+    private String timePeriod;
+    /**
+    * 指定人员
+    */
+    @ApiModelProperty("指定人员")
+    private String userRelation;
+
+
+    /**
+    * attendanceMessageUserRelation
+    */
+    @ApiModelProperty("attendanceMessageUserRelation子表")
+    private List<AttendanceMessageUserRelationVo> attendanceMessageUserRelationList;
+
+}

+ 58 - 0
src/main/java/com/xjrsoft/module/attendance/vo/AttendanceMessageUserRelationVo.java

@@ -0,0 +1,58 @@
+package com.xjrsoft.module.attendance.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 dzx
+* @Date: 2024-05-21
+* @Version 1.0
+*/
+@Data
+public class AttendanceMessageUserRelationVo {
+
+    /**
+    * 
+    */
+    @ApiModelProperty("")
+    private Long id;
+    /**
+    * 
+    */
+    @ApiModelProperty("")
+    private Integer sortCode;
+    /**
+    * 所属班级id
+    */
+    @ApiModelProperty("所属班级id")
+    private Long classId;
+    /**
+    * 所属部门id
+    */
+    @ApiModelProperty("所属部门id")
+    private Long deptId;
+    /**
+    * 用户id
+    */
+    @ApiModelProperty("用户id")
+    private Long userId;
+    /**
+    * 考勤消息设置(attendance_message_set)
+    */
+    @ApiModelProperty("考勤消息设置(attendance_message_set)")
+    private Long attendanceMessageSetId;
+
+    /**
+     * 名称
+     */
+    @ApiModelProperty("名称")
+    private String name;
+
+}

+ 3 - 0
src/main/java/com/xjrsoft/module/attendance/vo/AttendanceRuleCategoryPageVo.java

@@ -90,4 +90,7 @@ public class AttendanceRuleCategoryPageVo {
     @ApiModelProperty("状态(1:启用 0:禁用)")
     private Integer status;
 
+    @ApiModelProperty("非考勤周期是否允许进出(1:是 0:否)")
+    private Integer notCycleIsInOut;
+
 }

+ 172 - 0
src/main/java/com/xjrsoft/module/attendance/vo/AttendanceRuleDetailsUserVo.java

@@ -0,0 +1,172 @@
+package com.xjrsoft.module.attendance.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.time.LocalTime;
+
+/**
+* @title: 考勤规则细则表单出参
+* @Author dzx
+* @Date: 2024-05-08
+* @Version 1.0
+*/
+@Data
+public class AttendanceRuleDetailsUserVo {
+
+    /**
+    * 
+    */
+    @ApiModelProperty("")
+    private Long id;
+    /**
+    * 
+    */
+    /**
+    * 周几(星期一~日或节假日)
+    */
+    @ApiModelProperty("周几(星期一~日或节假日)")
+    private String dateType;
+    /**
+    * 是否允许进出校
+    */
+    @ApiModelProperty("是否允许进出校")
+    private Integer isAllowInOutSchool;
+    /**
+    * 是否考勤
+    */
+    @ApiModelProperty("是否考勤")
+    private Integer isAttendance;
+    /**
+    * 上学时间前多少分钟进行提醒
+    */
+    @ApiModelProperty("上学时间前多少分钟进行提醒")
+    private Integer agoMinutes;
+    /**
+    * 超过上学时间多少分钟未打卡进行提醒
+    */
+    @ApiModelProperty("超过上学时间多少分钟未打卡进行提醒")
+    private Integer overMinutes;
+    /**
+    * 上学时间内是否允许进出
+    */
+    @ApiModelProperty("上学时间内是否允许进出")
+    private Integer isAllowInOutSchoolTime;
+    /**
+    * 上午是否启用(1:是 0:否)
+    */
+    @ApiModelProperty("上午是否启用(1:是 0:否)")
+    private Integer amStatus;
+    /**
+    * 上午上学时间
+    */
+    @ApiModelProperty("上午上学时间")
+    private LocalTime amStartTime;
+    /**
+    * 上午放学时间
+    */
+    @ApiModelProperty("上午放学时间")
+    private LocalTime amEndTime;
+    /**
+    * 上午迟到旷课分钟数
+    */
+    @ApiModelProperty("上午迟到旷课分钟数")
+    private Integer amLateMinutes;
+    /**
+    * 上午是否为节假日(1:是 0:否)
+    */
+    @ApiModelProperty("上午是否为节假日(1:是 0:否)")
+    private Integer amIsHolidays;
+    /**
+    * 上午为节假日前一天时上学时间
+    */
+    @ApiModelProperty("上午为节假日前一天时上学时间")
+    private LocalTime amHolidaysStartTime;
+    /**
+    * 上午为节假日前一天时放学时间
+    */
+    @ApiModelProperty("上午为节假日前一天时放学时间")
+    private LocalTime amHolidaysEndTime;
+    /**
+    * 下午是否启用(1:是 0:否)
+    */
+    @ApiModelProperty("下午是否启用(1:是 0:否)")
+    private Integer pmStatus;
+    /**
+    * 下午上学时间
+    */
+    @ApiModelProperty("下午上学时间")
+    private LocalTime pmStartTime;
+    /**
+    * 下午放学时间
+    */
+    @ApiModelProperty("下午放学时间")
+    private LocalTime pmEndTime;
+    /**
+    * 下午迟到旷课分钟数
+    */
+    @ApiModelProperty("下午迟到旷课分钟数")
+    private Integer pmLateMinutes;
+    /**
+    * 下午是否为节假日(1:是 0:否)
+    */
+    @ApiModelProperty("下午是否为节假日(1:是 0:否)")
+    private Integer pmIsHolidays;
+    /**
+    * 下午为节假日前一天时上学时间
+    */
+    @ApiModelProperty("下午为节假日前一天时上学时间")
+    private LocalTime pmHolidaysStartTime;
+    /**
+    * 下午为节假日前一天时放学时间
+    */
+    @ApiModelProperty("下午为节假日前一天时放学时间")
+    private LocalTime pmHolidaysEndTime;
+    /**
+    * 晚上是否启用(1:是 0:否)
+    */
+    @ApiModelProperty("晚上是否启用(1:是 0:否)")
+    private Integer eveningStatus;
+    /**
+    * 晚上上学时间
+    */
+    @ApiModelProperty("晚上上学时间")
+    private LocalTime eveningStartTime;
+    /**
+    * 晚上放学时间
+    */
+    @ApiModelProperty("晚上放学时间")
+    private LocalTime eveningEndTime;
+    /**
+    * 晚上迟到旷课分钟数
+    */
+    @ApiModelProperty("晚上迟到旷课分钟数")
+    private Integer eveningLateMinutes;
+    /**
+    * 晚上是否为节假日(1:是 0:否)
+    */
+    @ApiModelProperty("晚上是否为节假日(1:是 0:否)")
+    private Integer eveningIsHolidays;
+    /**
+    * 晚上为节假日前一天时上学时间
+    */
+    @ApiModelProperty("晚上为节假日前一天时上学时间")
+    private LocalTime eveningHolidaysStartTime;
+    /**
+    * 晚上为节假日前一天时放学时间
+    */
+    @ApiModelProperty("晚上为节假日前一天时放学时间")
+    private LocalTime eveningHolidaysEndTime;
+    /**
+    * 考勤规则(attendance_rule_category)
+    */
+    @ApiModelProperty("考勤规则(attendance_rule_category)")
+    private Long attendanceRuleCategoryId;
+
+    @ApiModelProperty("为节假日前一天时放学时间")
+    private LocalTime holidaysEndTime;
+
+    @ApiModelProperty("用户id")
+    private Long userId;
+
+}

+ 2 - 1
src/main/java/com/xjrsoft/module/attendance/vo/AttendanceRuleDetailsVo.java

@@ -165,6 +165,7 @@ public class AttendanceRuleDetailsVo {
     @ApiModelProperty("考勤规则(attendance_rule_category)")
     private Long attendanceRuleCategoryId;
 
-
+    @ApiModelProperty("为节假日前一天时放学时间")
+    private LocalTime holidaysEndTime;
 
 }

+ 60 - 0
src/main/java/com/xjrsoft/module/attendance/vo/ClassStatisticsVo.java

@@ -0,0 +1,60 @@
+package com.xjrsoft.module.attendance.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+* @title: 教职工统计
+* @Author dzx
+* @Date: 2024年5月24日
+* @Version 1.0
+*/
+@Data
+public class ClassStatisticsVo {
+
+    @ApiModelProperty("班级id")
+    private Long id;
+
+    @ApiModelProperty("班级名称")
+    private String name;
+
+    @ApiModelProperty("班主任姓名")
+    private String teacherName;
+
+    @ApiModelProperty("学生总人数")
+    private Integer studentCount;
+
+    @ApiModelProperty("住校人数")
+    private Integer stayCount;
+
+    @ApiModelProperty("走读人数")
+    private Integer notStayCount;
+
+    @ApiModelProperty("请假人数")
+    private Integer leaveCount;
+
+    @ApiModelProperty("迟到人数")
+    private Integer lateCount;
+
+    @ApiModelProperty("旷课人数")
+    private Integer playTruantCount;
+
+    @ApiModelProperty("实到人数")
+    private Integer actualCount;
+
+    @ApiModelProperty("缺勤人数")
+    private Integer absenteeismCount;
+
+    @ApiModelProperty("出勤率")
+    private Double attendanceRate;
+
+    @ApiModelProperty("应该离校人数")
+    private Integer ygLeaveSchoolCount;
+
+    @ApiModelProperty("已经离校人数")
+    private Integer yjLeaveSchoolCount;
+
+    @ApiModelProperty("未离校人数")
+    private Integer wLeaveSchoolCount;
+
+}

+ 83 - 0
src/main/java/com/xjrsoft/module/attendance/vo/StudentAttendanceRecordClassPageVo.java

@@ -0,0 +1,83 @@
+package com.xjrsoft.module.attendance.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+public class StudentAttendanceRecordClassPageVo {
+    /**
+     * 主键
+     */
+    @ApiModelProperty("主键")
+    private String id;
+    /**
+     * 时段(1:上午,2:下午,3:晚上)
+     */
+    @ApiModelProperty("时段(1:上午,2:下午,3:晚上)")
+    private Integer timeInterval;
+    /**
+     * 班级ID
+     */
+    @ApiModelProperty("班级ID")
+    private Long classId;
+    /**
+     * 班级
+     */
+    @ApiModelProperty("班级")
+    private String classCn;
+    /**
+     * 班主人
+     */
+    @ApiModelProperty("班主人")
+    private Long teacherCn;
+    /**
+     * 总人数
+     */
+    @ApiModelProperty("总人数")
+    private  Integer totalCount;
+    /**
+     * 住读人数
+     */
+    @ApiModelProperty("住读人数")
+    private  Integer stayCount;
+    /**
+     * 走读人数
+     */
+    @ApiModelProperty("走读人数")
+    private  Integer notStayCount;
+    /**
+     * 实到人数
+     */
+    @ApiModelProperty("实到人数")
+    private  Integer actualCount;
+    /**
+     * 请假人数
+     */
+    @ApiModelProperty("请假人数")
+    private  Integer leaveCount;
+    /**
+     * 迟到人数
+     */
+    @ApiModelProperty("迟到人数")
+    private  Integer lateCount;
+    /**
+     * 旷课人数
+     */
+    @ApiModelProperty("旷课人数")
+    private  Integer absenteeismCount;
+    /**
+     * 缺勤人数
+     */
+    @ApiModelProperty("缺勤人数")
+    private  Integer truantCount;
+    /**
+     * 缺勤率
+     */
+    @ApiModelProperty("缺勤率")
+    private  Float attendanceRate;
+    /**
+     * 考勤状态
+     */
+    @ApiModelProperty("考勤状态")
+    private String attendanceStatusCn;
+}

+ 123 - 0
src/main/java/com/xjrsoft/module/attendance/vo/StudentAttendanceRecordPageVo.java

@@ -0,0 +1,123 @@
+package com.xjrsoft.module.attendance.vo;
+
+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 dzx
+* @Date: 2024-05-15
+* @Version 1.0
+*/
+@Data
+public class StudentAttendanceRecordPageVo {
+
+    /**
+    * 主键
+    */
+    @ApiModelProperty("主键")
+    private String id;
+    /**
+    * 创建人
+    */
+    @ApiModelProperty("创建人")
+    private Long createUserId;
+    /**
+    * 创建时间
+    */
+    @ApiModelProperty("创建时间")
+    private Date createDate;
+    /**
+    * 修改人id
+    */
+    @ApiModelProperty("修改人id")
+    private Long modifyUserId;
+    /**
+    * 修改日期
+    */
+    @ApiModelProperty("修改日期")
+    private Date modifyDate;
+    /**
+    * 删除标记
+    */
+    @ApiModelProperty("删除标记")
+    private Integer deleteMark;
+    /**
+    * 有效标记
+    */
+    @ApiModelProperty("有效标记")
+    private Integer enabledMark;
+    /**
+    * 学生userId(xjr_user)
+    */
+    @ApiModelProperty("学生userId(xjr_user)")
+    private Long userId;
+    /**
+    * 班主人id(xjr_user)
+    */
+    @ApiModelProperty("班主人id(xjr_user)")
+    private Long teacherId;
+    /**
+    * 班级id(class)
+    */
+    @ApiModelProperty("班级id(class)")
+    private Long classId;
+    /**
+    * 就读方式(xjr_dictionary_item[stduy_status])
+    */
+    @ApiModelProperty("就读方式(xjr_dictionary_item[stduy_status])")
+    private String stduyStatus;
+    /**
+    * 考勤状态(xjr_dictionary_detail[attendance_status])
+    */
+    @ApiModelProperty("考勤状态(xjr_dictionary_detail[attendance_status])")
+    private String attendanceStatus;
+    /**
+    * 时段(1:上午,2:下午,3:晚上)
+    */
+    @ApiModelProperty("时段(1:上午,2:下午,3:晚上)")
+    private Integer timeInterval;
+    /**
+     * 班级
+     */
+    @ApiModelProperty("班级")
+    private String classCn;
+    /**
+     * 班主人
+     */
+    @ApiModelProperty("班主人")
+    private Long teacherCn;
+    /**
+     * 身份证号
+     */
+    @ApiModelProperty("身份证号")
+    private String identityCard;
+    /**
+     * 姓名
+     */
+    @ApiModelProperty("姓名")
+    private String name;
+    /**
+     * 就读方式
+     */
+    @ApiModelProperty("就读方式")
+    private String stduyStatusCn;
+    /**
+     * 考勤状态
+     */
+    @ApiModelProperty("考勤状态")
+    private String attendanceStatusCn;
+    /**
+     * 性别
+     */
+    @ApiModelProperty("性别")
+    private String gender;
+}

+ 59 - 0
src/main/java/com/xjrsoft/module/attendance/vo/StudentAttendanceRecordVo.java

@@ -0,0 +1,59 @@
+package com.xjrsoft.module.attendance.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 dzx
+* @Date: 2024-05-15
+* @Version 1.0
+*/
+@Data
+public class StudentAttendanceRecordVo {
+
+    /**
+    * 主键
+    */
+    @ApiModelProperty("主键")
+    private Long id;
+    /**
+    * 学生userId(xjr_user)
+    */
+    @ApiModelProperty("学生userId(xjr_user)")
+    private Long userId;
+    /**
+    * 班主人id(xjr_user)
+    */
+    @ApiModelProperty("班主人id(xjr_user)")
+    private Long teacherId;
+    /**
+    * 班级id(class)
+    */
+    @ApiModelProperty("班级id(class)")
+    private Long classId;
+    /**
+    * 就读方式(xjr_dictionary_item[stduy_status])
+    */
+    @ApiModelProperty("就读方式(xjr_dictionary_item[stduy_status])")
+    private String stduyStatus;
+    /**
+    * 考勤状态(xjr_dictionary_detail[attendance_status])
+    */
+    @ApiModelProperty("考勤状态(xjr_dictionary_detail[attendance_status])")
+    private String attendanceStatus;
+    /**
+    * 时段(1:上午,2:下午,3:晚上)
+    */
+    @ApiModelProperty("时段(1:上午,2:下午,3:晚上)")
+    private Integer timeInterval;
+
+
+
+}

+ 46 - 0
src/main/java/com/xjrsoft/module/attendance/vo/StudentStatisticsPageVo.java

@@ -0,0 +1,46 @@
+package com.xjrsoft.module.attendance.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+* @title: 学生考勤统计列表
+* @Author dzx
+* @Date: 2024年5月24日
+* @Version 1.0
+*/
+@Data
+public class StudentStatisticsPageVo {
+
+    @ApiModelProperty("班级名称")
+    private String className;
+
+    @ApiModelProperty("班主任名称")
+    private String teacherName;
+
+    @ApiModelProperty("学生名称")
+    private String studentName;
+
+    @ApiModelProperty("身份证号")
+    private String credentialNumber;
+
+    @ApiModelProperty("就读方式")
+    private String stduyStatusCn;
+
+    @ApiModelProperty("考勤状态")
+    private String status;
+
+    @ApiModelProperty("学生userId")
+    private Long userId;
+
+    @ApiModelProperty("考勤时间")
+    private LocalDateTime recordTime;
+
+    @ApiModelProperty("手机号")
+    private String mobile;
+
+    @ApiModelProperty("监护人电话")
+    private String guardianPhone;
+}

+ 41 - 0
src/main/java/com/xjrsoft/module/attendance/vo/StudentStatisticsVo.java

@@ -0,0 +1,41 @@
+package com.xjrsoft.module.attendance.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+* @title: 教职工统计
+* @Author dzx
+* @Date: 2024年5月24日
+* @Version 1.0
+*/
+@Data
+public class StudentStatisticsVo {
+
+    @ApiModelProperty("总人数")
+    private Long allCount;
+    /**
+    * 实到人数
+    */
+    @ApiModelProperty("实到人数")
+    private Long actualCount;
+    /**
+    * 请假人数
+    */
+    @ApiModelProperty("请假人数")
+    private Long leaveCount;
+    /**
+    * 迟到人数
+    */
+    @ApiModelProperty("迟到人数")
+    private Long lateCount;
+    /**
+    * 上学时间前多少分钟进行提醒
+    */
+    @ApiModelProperty("缺勤人数")
+    private Long absenteeismCount;
+
+    @ApiModelProperty("出勤率")
+    private Double attendanceRate;
+
+}

+ 108 - 0
src/main/java/com/xjrsoft/module/attendance/vo/TeacherAttendanceRecordPageVo.java

@@ -0,0 +1,108 @@
+package com.xjrsoft.module.attendance.vo;
+
+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 dzx
+* @Date: 2024-05-15
+* @Version 1.0
+*/
+@Data
+public class TeacherAttendanceRecordPageVo {
+
+    /**
+    * 主键
+    */
+    @ApiModelProperty("主键")
+    private String id;
+    /**
+    * 创建人
+    */
+    @ApiModelProperty("创建人")
+    private Long createUserId;
+    /**
+    * 创建时间
+    */
+    @ApiModelProperty("创建时间")
+    private Date createDate;
+    /**
+    * 修改人id
+    */
+    @ApiModelProperty("修改人id")
+    private Long modifyUserId;
+    /**
+    * 修改日期
+    */
+    @ApiModelProperty("修改日期")
+    private Date modifyDate;
+    /**
+    * 删除标记
+    */
+    @ApiModelProperty("删除标记")
+    private Integer deleteMark;
+    /**
+    * 有效标记
+    */
+    @ApiModelProperty("有效标记")
+    private Integer enabledMark;
+    /**
+    * 教师userId(xjr_user)
+    */
+    @ApiModelProperty("教师userId(xjr_user)")
+    private Long userId;
+    /**
+    * 考勤方式(1:人脸,2:车辆)
+    */
+    @ApiModelProperty("考勤方式(1:人脸,2:车辆)")
+    private Integer attendanceMode;
+    /**
+    * 考勤状态(xjr_dictionary_detail[attendance_status])
+    */
+    @ApiModelProperty("考勤状态(xjr_dictionary_detail[attendance_status])")
+    private String attendanceStatus;
+    /**
+    * 时段(1:上午,2:下午,3:晚上)
+    */
+    @ApiModelProperty("时段(1:上午,2:下午,3:晚上)")
+    private Integer timeInterval;
+    /**
+     * 车牌号
+     */
+    @ApiModelProperty("车牌号")
+    private String carNumber;
+    /**
+     * 姓名
+     */
+    @ApiModelProperty("姓名")
+    private String name;
+    /**
+     * 身份证号
+     */
+    @ApiModelProperty("身份证号")
+    private String identityCard;
+    /**
+     * 手机号码
+     */
+    @ApiModelProperty("手机号码")
+    private Long phone;
+    /**
+     * 性别
+     */
+    @ApiModelProperty("性别")
+    private String gender;
+    /**
+     * 考勤状态(xjr_dictionary_detail[attendance_status])
+     */
+    @ApiModelProperty("考勤状态(xjr_dictionary_detail[attendance_status])")
+    private String attendanceStatusCn;
+}

+ 49 - 0
src/main/java/com/xjrsoft/module/attendance/vo/TeacherAttendanceRecordVo.java

@@ -0,0 +1,49 @@
+package com.xjrsoft.module.attendance.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 dzx
+* @Date: 2024-05-15
+* @Version 1.0
+*/
+@Data
+public class TeacherAttendanceRecordVo {
+
+    /**
+    * 主键
+    */
+    @ApiModelProperty("主键")
+    private Long id;
+    /**
+    * 教师userId(xjr_user)
+    */
+    @ApiModelProperty("教师userId(xjr_user)")
+    private Long userId;
+    /**
+    * 考勤方式(1:人脸,2:车辆)
+    */
+    @ApiModelProperty("考勤方式(1:人脸,2:车辆)")
+    private Integer attendanceMode;
+    /**
+    * 考勤状态(xjr_dictionary_detail[attendance_status])
+    */
+    @ApiModelProperty("考勤状态(xjr_dictionary_detail[attendance_status])")
+    private String attendanceStatus;
+    /**
+    * 时段(1:上午,2:下午,3:晚上)
+    */
+    @ApiModelProperty("时段(1:上午,2:下午,3:晚上)")
+    private Integer timeInterval;
+
+
+
+}

+ 34 - 0
src/main/java/com/xjrsoft/module/attendance/vo/TeacherStatisticsPageVo.java

@@ -0,0 +1,34 @@
+package com.xjrsoft.module.attendance.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+* @title: 教师考勤统计列表
+* @Author dzx
+* @Date: 2024年5月29日
+* @Version 1.0
+*/
+@Data
+public class TeacherStatisticsPageVo {
+
+    @ApiModelProperty("教职工姓名")
+    private String teacherName;
+
+    @ApiModelProperty("手机号")
+    private String mobile;
+
+    @ApiModelProperty("考勤状态")
+    private String status;
+
+    @ApiModelProperty("教师userId")
+    private Long userId;
+
+    @ApiModelProperty("部门名称")
+    private String deptName;
+
+    @ApiModelProperty("考勤时间")
+    private LocalDateTime recordTime;
+}

+ 45 - 0
src/main/java/com/xjrsoft/module/attendance/vo/TeacherStatisticsVo.java

@@ -0,0 +1,45 @@
+package com.xjrsoft.module.attendance.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.time.LocalTime;
+
+/**
+* @title: 教职工统计
+* @Author dzx
+* @Date: 2024年5月24日
+* @Version 1.0
+*/
+@Data
+public class TeacherStatisticsVo {
+
+    @ApiModelProperty("总人数")
+    private Long allCount;
+    /**
+    * 实到人数
+    */
+    @ApiModelProperty("实到人数")
+    private Long actualCount;
+    /**
+    * 请假人数
+    */
+    @ApiModelProperty("请假人数")
+    private Long leaveCount;
+    /**
+    * 迟到人数
+    */
+    @ApiModelProperty("迟到人数")
+    private Long lateCount;
+    /**
+    * 上学时间前多少分钟进行提醒
+    */
+    @ApiModelProperty("缺勤人数")
+    private Long absenteeismCount;
+
+    @ApiModelProperty("出勤率")
+    private Double attendanceRate;
+
+    @ApiModelProperty("旷课人数")
+    private Integer playTruantCount;
+}

+ 44 - 0
src/main/java/com/xjrsoft/module/attendance/vo/VisitorInfoVo.java

@@ -0,0 +1,44 @@
+package com.xjrsoft.module.attendance.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+* @title: 访客信息
+* @Author dzx
+* @Date: 2024年5月27日
+* @Version 1.0
+*/
+@Data
+public class VisitorInfoVo {
+
+    @ApiModelProperty("访客姓名")
+    private String name;
+
+    @ApiModelProperty("访客身份证")
+    private String identityCard;
+
+    @ApiModelProperty("电话")
+    private String phone;
+
+    @ApiModelProperty("被访人")
+    private String respondentUserName;
+
+    @ApiModelProperty("被访部门")
+    private String deptName;
+
+    @ApiModelProperty("到访结束时间")
+    private LocalDateTime endTime;
+
+    @ApiModelProperty("到访开始时间")
+    private LocalDateTime startTime;
+
+    @ApiModelProperty("申请时间")
+    private LocalDateTime createDate;
+
+    @ApiModelProperty("进校事由")
+    private String reason;
+
+}

+ 10 - 0
src/main/java/com/xjrsoft/module/base/mapper/BaseClassMapper.java

@@ -2,11 +2,16 @@ package com.xjrsoft.module.base.mapper;
 
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.github.yulichang.base.MPJBaseMapper;
+import com.xjrsoft.module.attendance.dto.AttendanceStatisticDto;
+import com.xjrsoft.module.attendance.vo.ClassStatisticsVo;
 import com.xjrsoft.module.base.dto.BaseClassPageDto;
 import com.xjrsoft.module.base.entity.BaseClass;
 import com.xjrsoft.module.base.vo.BaseClassPageVo;
+import com.xjrsoft.module.base.vo.StudentClassVo;
 import org.apache.ibatis.annotations.Mapper;
 
+import java.util.List;
+
 /**
  * <p>
  * 班级表 Mapper 接口
@@ -19,4 +24,9 @@ import org.apache.ibatis.annotations.Mapper;
 public interface BaseClassMapper extends MPJBaseMapper<BaseClass> {
 
     Page<BaseClassPageVo> getPage(Page<BaseClassPageVo> page, BaseClassPageDto dto);
+
+    List<StudentClassVo> getStudentClass();
+
+
+    Page<ClassStatisticsVo> getAttendanceClass(Page<ClassStatisticsVo> page, AttendanceStatisticDto dto);
 }

+ 7 - 0
src/main/java/com/xjrsoft/module/base/service/IBaseClassService.java

@@ -2,9 +2,12 @@ package com.xjrsoft.module.base.service;
 
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.github.yulichang.base.MPJBaseService;
+import com.xjrsoft.module.attendance.dto.AttendanceStatisticDto;
+import com.xjrsoft.module.attendance.vo.ClassStatisticsVo;
 import com.xjrsoft.module.base.dto.BaseClassPageDto;
 import com.xjrsoft.module.base.entity.BaseClass;
 import com.xjrsoft.module.base.vo.BaseClassPageVo;
+import com.xjrsoft.module.base.vo.StudentClassVo;
 import com.xjrsoft.module.organization.vo.UserStudentVo;
 
 import java.util.List;
@@ -14,4 +17,8 @@ public interface IBaseClassService extends MPJBaseService<BaseClass> {
     UserStudentVo getClassInfo(long id);
 
     Page<BaseClassPageVo> getPage(Page<BaseClassPageVo> page, BaseClassPageDto dto);
+
+    List<StudentClassVo> getStudentClass();
+
+    Page<ClassStatisticsVo> getAttendancePage(Page<ClassStatisticsVo> page, AttendanceStatisticDto dto);
 }

+ 13 - 0
src/main/java/com/xjrsoft/module/base/service/impl/BaseClassServiceImpl.java

@@ -4,11 +4,14 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.github.yulichang.base.MPJBaseServiceImpl;
 import com.github.yulichang.wrapper.MPJLambdaWrapper;
+import com.xjrsoft.module.attendance.dto.AttendanceStatisticDto;
+import com.xjrsoft.module.attendance.vo.ClassStatisticsVo;
 import com.xjrsoft.module.base.dto.BaseClassPageDto;
 import com.xjrsoft.module.base.entity.BaseClass;
 import com.xjrsoft.module.base.mapper.BaseClassMapper;
 import com.xjrsoft.module.base.service.IBaseClassService;
 import com.xjrsoft.module.base.vo.BaseClassPageVo;
+import com.xjrsoft.module.base.vo.StudentClassVo;
 import com.xjrsoft.module.organization.entity.UserStudent;
 import com.xjrsoft.module.organization.service.IUserStudentService;
 import com.xjrsoft.module.organization.vo.UserStudentVo;
@@ -81,4 +84,14 @@ public class BaseClassServiceImpl extends MPJBaseServiceImpl<BaseClassMapper, Ba
     public Page<BaseClassPageVo> getPage(Page<BaseClassPageVo> page, BaseClassPageDto dto) {
         return baseClassMapper.getPage(page, dto);
     }
+
+    @Override
+    public List<StudentClassVo> getStudentClass() {
+        return baseClassMapper.getStudentClass();
+    }
+
+    @Override
+    public Page<ClassStatisticsVo> getAttendancePage(Page<ClassStatisticsVo> page, AttendanceStatisticDto dto){
+        return baseClassMapper.getAttendanceClass(page, dto);
+    };
 }

+ 31 - 0
src/main/java/com/xjrsoft/module/base/vo/StudentClassVo.java

@@ -0,0 +1,31 @@
+package com.xjrsoft.module.base.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+
+/**
+* @title: 学生班级信息
+* @Author dzx
+* @Date: 2024年5月22日
+* @Version 1.0
+*/
+@Data
+public class StudentClassVo {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty("学生user_id")
+    private Long userId;
+
+    @ApiModelProperty("班级id")
+    private Long id;
+
+    @ApiModelProperty("班级表中的teacher_id")
+    private Long teacherId;
+
+
+    @ApiModelProperty("班级名称")
+    private String name;
+
+}

+ 55 - 0
src/main/java/com/xjrsoft/module/hikvision/entity/HikvisionData.java

@@ -0,0 +1,55 @@
+package com.xjrsoft.module.hikvision.entity;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+
+/**
+* @title: 简约系统对照表
+* @Author dzx
+* @Date: 2024-01-23
+* @Version 1.0
+*/
+@Data
+@TableName("hikvision_data")
+@ApiModel(value = "海康威视系统对照表", description = "海康威视系统对照表")
+public class HikvisionData implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+    * 创建时间
+    */
+    @ApiModelProperty("首次推送时间")
+    @TableField(fill = FieldFill.INSERT)
+    private Date createDate;
+    /**
+    * 修改时间
+    */
+    @ApiModelProperty("修改时间")
+    @TableField(fill = FieldFill.UPDATE)
+    private Date modifyDate;
+    /**
+    * 表名
+    */
+    @ApiModelProperty("表名")
+    private String tableName;
+    /**
+    * 英文姓名
+    */
+    @ApiModelProperty("数据id")
+    private String sourceId;
+    /**
+    * 姓名拼音
+    */
+    @ApiModelProperty("对应的海康威视系统的id")
+    private String hikvisionId;
+
+}

+ 30 - 0
src/main/java/com/xjrsoft/module/hikvision/mapper/HikvisionDataMapper.java

@@ -0,0 +1,30 @@
+package com.xjrsoft.module.hikvision.mapper;
+
+import com.github.yulichang.base.MPJBaseMapper;
+import com.xjrsoft.module.hikvision.entity.HikvisionData;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+* @title: 寝室床位
+* @Author dzx
+* @Date: 2023-12-27
+* @Version 1.0
+*/
+@Mapper
+public interface HikvisionDataMapper extends MPJBaseMapper<HikvisionData> {
+
+    /**
+     * 查询教师在海康中的id
+     * @param sourceId
+     * @return
+     */
+    String getTeacherHikvisionId(Long sourceId);
+
+
+    /**
+     * 查询学生在海康中的id
+     * @param sourceId
+     * @return
+     */
+    String getStudentHikvisionId(Long sourceId);
+}

+ 24 - 9
src/main/java/com/xjrsoft/module/hikvision/util/ApiUtil.java

@@ -1,8 +1,8 @@
 package com.xjrsoft.module.hikvision.util;
 
-import com.google.gson.JsonObject;
 import com.hikvision.artemis.sdk.ArtemisHttpUtil;
 import com.hikvision.artemis.sdk.config.ArtemisConfig;
+import org.apache.http.HttpResponse;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -19,11 +19,12 @@ public class ApiUtil {
     /**
      * 调用海康接口(该方法内部实现了登入认证逻辑)
      * @param apiPath 接口地址
-     * @param paramJson body参数
+     * @param body body参数
      * @param querys 查询参数
+     * @param header header参数
      * @return 接口调用结果
      */
-    public String doPost(String apiPath, JsonObject paramJson, Map<String, String> querys){
+    public String doPost(String apiPath, String body, Map<String, String> querys, Map<String, String> header){
         /**
          * STEP1:设置平台参数,根据实际情况,设置host appkey appsecret 三个参数.
          */
@@ -51,11 +52,25 @@ public class ApiUtil {
          */
         String contentType = "application/json";
 
-        /**
-         * STEP5:组装请求参数
-         */
-        String body = paramJson.toString();
+        return ArtemisHttpUtil.doPostStringArtemis(path, body, querys, null, contentType , header);// post请求application/json类型参数
+    }
+
+    /**
+     * 调用海康接口(该方法内部实现了登入认证逻辑)
+     * @param apiPath 接口地址
+     * @param body body参数
+     * @param querys 查询参数
+     * @return 接口调用结果
+     */
+    public String doPost(String apiPath, String body, Map<String, String> querys){
+        return doPost(apiPath, body, querys, null);
+    }
 
-        return ArtemisHttpUtil.doPostStringArtemis(path, body, querys, null, contentType , null);// post请求application/json类型参数
+    public static String GetRedirectURL(String uri){
+        if (!uri.isEmpty())
+            return "https://" + ApiUtil.host + "/" + uri;
+        else
+            return "";
     }
-}
+
+}

+ 536 - 34
src/main/java/com/xjrsoft/module/hikvision/util/DataUtil.java

@@ -1,61 +1,563 @@
 package com.xjrsoft.module.hikvision.util;
 
 import cn.hutool.db.Db;
+import com.alibaba.druid.sql.visitor.functions.Trim;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
 import com.google.gson.JsonObject;
 import com.google.gson.JsonParser;
 import com.xjrsoft.module.base.entity.BaseClass;
-import com.xjrsoft.module.schedule.util.ScheduleUtil;
+import com.xjrsoft.module.base.entity.BaseGrade;
+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;
+import org.apache.velocity.runtime.directive.Foreach;
+import org.springframework.beans.factory.annotation.Autowired;
 
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.sql.SQLException;
+import java.text.SimpleDateFormat;
+import java.util.*;
 
 /**
  * @author dzx
  * @date 2024/5/10
  */
+@Slf4j
 public class DataUtil {
+    /**
+     * 同步组织数据
+     * 只有批量添加接口,需要一个层级一个层级的添加
+     */
+    public Map<String, String> insertDepartment(Db db, String tableName, Map<String, String> tableData) throws Exception {
+        String sql = "SELECT DISTINCT LENGTH(hierarchy) FROM " + tableName + " WHERE delete_mark = 0";
+        List<Integer[]> list = db.query(sql, Integer[].class);
+        Set<Integer> levelSet = new HashSet<>();
+        for (Integer[] strings : list) {
+            levelSet.add(strings[0]);
+        }
 
-    public Map<Long, String> insertDepartment(Db db, String tableName, Map<Long, String> gradeMap,
-                                         Map<Long, String> teacherMap, String semesterSerialNo, Map<Long, String> ids, Map<Long, String> classroomMap) throws Exception {
-        String sql = "SELECT * FROM " + tableName + " WHERE delete_mark = 0 and is_graduate = 1";
-        List<BaseClass> dataList = db.query(sql, BaseClass.class);
+        sql = "SELECT * FROM " + tableName + " WHERE delete_mark = 0 ORDER BY LENGTH(hierarchy)";
+        List<Department> dataList = db.query(sql, Department.class);
+        String apiPath = "/api/resource/v1/org/batch/add";
+        Map<String, String> idMap = new HashMap<>();
+        JsonParser jsonParser = new JsonParser();
+        ApiUtil apiUtil = new ApiUtil();
 
-        Map<Long, String> idMap = new HashMap<>();
+        Map<String, String> idCodeMap = new HashMap<>();
+        for (Integer level : levelSet) {
+            JsonArray dataArray = new JsonArray();
+            for (Department department : dataList) {
+                if(tableData != null && tableData.containsKey(department.getId().toString())){
+                    continue;
+                }
+                if(department.getHierarchy().length() == level){
+                    JsonObject paramJson = new JsonObject();
+                    paramJson.addProperty("clientId", department.getCode());
+                    paramJson.addProperty("orgIndexCode", department.getId().toString());
+                    paramJson.addProperty("orgName", department.getName());
+                    paramJson.addProperty("parentIndexCode", department.getParentId().toString());
+                    if(department.getParentId() == 0){
+                        paramJson.addProperty("parentIndexCode", "root000000");
+                    }
+                    paramJson.addProperty("orgCode", department.getCode());
+                    dataArray.add(paramJson);
+                    idCodeMap.put(department.getCode(), department.getId().toString());
+                }
+            }
+            String result = apiUtil.doPost(apiPath, dataArray.toString(), null, null);
+            JsonElement parse = jsonParser.parse(result);
+
+            JsonObject resultJson = parse.getAsJsonObject();
+            if("0".equals(resultJson.get("code").getAsString()) && "success".equals(resultJson.get("msg").getAsString())){
+                JsonArray array = resultJson.get("data").getAsJsonObject().get("successes").getAsJsonArray();
+                for (JsonElement jsonElement : array) {
+                    JsonObject jsonObject = jsonElement.getAsJsonObject();
+                    idMap.put(idCodeMap.get(jsonObject.get("clientId").getAsString()), jsonObject.get("orgIndexCode").getAsString());
+                }
+            }
+        }
+        //插入记录表
+        insertRecord(db, tableName, idMap);
+        return idMap;
+    }
+
+    /**
+     * 推送学生班级信息
+     */
+    public Map<String, String> insertClass(Db db, String tableName, Map<String, String> tableData) throws SQLException {
+        Map<String, String> idMap = new HashMap<>();
+        //1、查询字典,将走读住读、班级类型先推送过去
+        String sql = "SELECT * FROM xjr_dictionary_detail WHERE delete_mark = 0 AND item_id = 2023000000000000030";
+        List<DictionaryDetail> detailList = db.query(sql, DictionaryDetail.class);
+
+        String apiPath = "/api/resource/v1/org/batch/add";
         JsonParser jsonParser = new JsonParser();
-        for (BaseClass baseClass : dataList) {
-            String url  = ScheduleUtil.apiUrl + "class/create";
+        ApiUtil apiUtil = new ApiUtil();
+        int clientId = 1;
+        Map<Integer, String> idCodeMap = new HashMap<>();
+        JsonArray dataArray = new JsonArray();
+
+        Set<String> stduyStatus = new HashSet<>();
+
+        for (DictionaryDetail dict : detailList) {
+            if(tableData != null && tableData.containsKey(dict.getId().toString())){
+                stduyStatus.add(dict.getId().toString());
+                continue;
+            }
             JsonObject paramJson = new JsonObject();
-            paramJson.addProperty("teacherSerialNo", teacherMap.get(baseClass.getTeacherId()));
-            paramJson.addProperty("name", baseClass.getName());
-
-            paramJson.addProperty("semesterSerialNo", semesterSerialNo);
-            paramJson.addProperty("eduYearSerialNo", gradeMap.get(baseClass.getGradeId()));
-            paramJson.addProperty("extendId", baseClass.getId());
-            paramJson.addProperty("classRoomSerialNo", classroomMap.get(baseClass.getClassroomId()));
-            if(ids != null && ids.get(baseClass.getId()) != null){
-                url  = ScheduleUtil.apiUrl + "class/update";
-                paramJson.addProperty("serialNo", ids.get(baseClass.getId()));
-                long timestamp = System.currentTimeMillis();
-                //生成签名
-                String sign = ScheduleUtil.createSign(timestamp);
-                String result = ScheduleUtil.doPost(url, paramJson.toString(), sign, timestamp);
+            paramJson.addProperty("clientId", clientId);
+            paramJson.addProperty("orgIndexCode", dict.getCode());
+            paramJson.addProperty("orgName", dict.getName() + "学生");
+            paramJson.addProperty("parentIndexCode", "root000000");
+            paramJson.addProperty("orgCode", dict.getCode());
+            dataArray.add(paramJson);
+            idCodeMap.put(clientId, dict.getCode());
+            clientId ++;
+        }
+        String result = apiUtil.doPost(apiPath, dataArray.toString(), null, null);
+        JsonElement parse = jsonParser.parse(result);
+
+        JsonObject resultJson = parse.getAsJsonObject();
+        if("0".equals(resultJson.get("code").getAsString()) && "success".equals(resultJson.get("msg").getAsString())){
+            JsonArray array = resultJson.get("data").getAsJsonObject().get("successes").getAsJsonArray();
+            for (JsonElement jsonElement : array) {
+                JsonObject jsonObject = jsonElement.getAsJsonObject();
+                idMap.put(idCodeMap.get(jsonObject.get("clientId").getAsInt()), jsonObject.get("orgIndexCode").getAsString());
+                stduyStatus.add(jsonObject.get("orgIndexCode").getAsString());
+            }
+        }
+        //推送班级类型
+        sql = "SELECT * FROM xjr_dictionary_detail WHERE delete_mark = 0 AND item_id = 2023000000000000039";
+        detailList = db.query(sql, DictionaryDetail.class);
+        dataArray = new JsonArray();
+        Set<String> classTypeSet = new HashSet<>();
+        for (String status : stduyStatus) {
+            for (DictionaryDetail dict : detailList) {
+                if(tableData != null && tableData.containsKey(dict.getCode())){
+                    classTypeSet.add(dict.getCode());
+                    continue;
+                }
+                JsonObject paramJson = new JsonObject();
+                paramJson.addProperty("clientId", clientId);
+                paramJson.addProperty("orgIndexCode", dict.getCode() + "-" + status);
+                paramJson.addProperty("orgName", dict.getName());
+                paramJson.addProperty("parentIndexCode", status);
+                paramJson.addProperty("orgCode", dict.getCode());
+                dataArray.add(paramJson);
+                idCodeMap.put(clientId, dict.getCode() + "-" + status);
+                clientId ++;
+            }
+        }
+
+        result = apiUtil.doPost(apiPath, dataArray.toString(), null, null);
+        parse = jsonParser.parse(result);
+        resultJson = parse.getAsJsonObject();
+        if("0".equals(resultJson.get("code").getAsString()) && "success".equals(resultJson.get("msg").getAsString())){
+            JsonArray array = resultJson.get("data").getAsJsonObject().get("successes").getAsJsonArray();
+            for (JsonElement jsonElement : array) {
+                JsonObject jsonObject = jsonElement.getAsJsonObject();
+                idMap.put(idCodeMap.get(jsonObject.get("clientId").getAsInt()), jsonObject.get("orgIndexCode").getAsString());
+                classTypeSet.add(jsonObject.get("orgIndexCode").getAsString());
+            }
+        }
+
+        //推送年级
+        sql = "SELECT * FROM base_grade WHERE delete_mark = 0 AND STATUS = 1";
+        List<BaseGrade> gradeList = db.query(sql, BaseGrade.class);
+        Map<Long, String> gradeNameMap = new HashMap<>();
+        dataArray = new JsonArray();
+        for (String classType : classTypeSet) {
+            for (BaseGrade baseGrade : gradeList) {
+                gradeNameMap.put(baseGrade.getId(), baseGrade.getName().replaceAll("级", ""));
+                if(tableData != null && tableData.containsKey(baseGrade.getId().toString())){
+                    continue;
+                }
+                JsonObject paramJson = new JsonObject();
+                paramJson.addProperty("clientId", clientId);
+                paramJson.addProperty("orgIndexCode", baseGrade.getName().replaceAll("级", "") + "-" + classType);
+                paramJson.addProperty("orgName", baseGrade.getName());
+                paramJson.addProperty("parentIndexCode", classType);
+                paramJson.addProperty("orgCode", clientId);
+                dataArray.add(paramJson);
+                idCodeMap.put(clientId, baseGrade.getName().replaceAll("级", "") + "-" + classType);
+                clientId ++;
+            }
+        }
+
+        result = apiUtil.doPost(apiPath, dataArray.toString(), null, null);
+        parse = jsonParser.parse(result);
+        Set<String> gradeSet = new HashSet<>();
+        resultJson = parse.getAsJsonObject();
+        if("0".equals(resultJson.get("code").getAsString()) && "success".equals(resultJson.get("msg").getAsString())){
+            JsonArray array = resultJson.get("data").getAsJsonObject().get("successes").getAsJsonArray();
+            for (JsonElement jsonElement : array) {
+                JsonObject jsonObject = jsonElement.getAsJsonObject();
+                idMap.put(idCodeMap.get(jsonObject.get("clientId").getAsInt()), jsonObject.get("orgIndexCode").getAsString());
+                gradeSet.add(jsonObject.get("orgIndexCode").getAsString());
+            }
+        }
+
+        //推送班级
+        sql = "SELECT * FROM base_class WHERE delete_mark = 0 AND is_graduate = 1 AND class_type IS NOT NULL";
+        List<BaseClass> classList = db.query(sql, BaseClass.class);
+
+        dataArray = new JsonArray();
+        for (String grade : gradeSet) {
+            String[] gradeGroup = grade.split("-");
+            for (BaseClass baseClass : classList) {
+                if(tableData != null && tableData.containsKey(baseClass.getId().toString())){
+                    continue;
+                }
+                String gradeName = gradeNameMap.get(baseClass.getGradeId());
+                if(!gradeGroup[0].equals(gradeName)){
+                    continue;
+                }
+
+                if(!gradeGroup[1].equals(baseClass.getClassType())){
+                    continue;
+                }
+                JsonObject paramJson = new JsonObject();
+                paramJson.addProperty("clientId", clientId);
+                paramJson.addProperty("orgIndexCode", baseClass.getId() + "-" + grade);
+                paramJson.addProperty("orgName", baseClass.getName());
+                paramJson.addProperty("parentIndexCode", grade);
+                paramJson.addProperty("orgCode", clientId);
+                dataArray.add(paramJson);
+                idCodeMap.put(clientId, baseClass.getId() + "-" + grade);
+                clientId ++;
+            }
+        }
+
+        result = apiUtil.doPost(apiPath, dataArray.toString(), null, null);
+        parse = jsonParser.parse(result);
+        resultJson = parse.getAsJsonObject();
+        if("0".equals(resultJson.get("code").getAsString()) && "success".equals(resultJson.get("msg").getAsString())){
+            JsonArray array = resultJson.get("data").getAsJsonObject().get("successes").getAsJsonArray();
+            for (JsonElement jsonElement : array) {
+                JsonObject jsonObject = jsonElement.getAsJsonObject();
+                idMap.put(idCodeMap.get(jsonObject.get("clientId").getAsInt()), jsonObject.get("orgIndexCode").getAsString());
+            }
+        }
+
+        //插入记录表
+        insertRecord(db, tableName, idMap);
+
+        return idMap;
+    }
+
+    public Map<String, String> insertStudentOne(Db db, String tableName, Map<String, String> tableData) throws Exception {
+        String sql = "SELECT t1.id,t1.name,CONCAT(t3.id,'-',replace(t4.name,'级',''),'-',t3.class_type,'-',t2.stduy_status)," +
+                " t1.user_name,t1.gender,DATE_FORMAT(t1.birth_date, '%Y-%m-%d'),t1.mobile,t1.email,t1.credential_type,t1.credential_number FROM xjr_user t1" +
+                " INNER JOIN base_student_school_roll t2 ON t1.id = t2.user_id" +
+                " INNER JOIN base_class t3 ON t2.class_id = t3.id" +
+                " INNER JOIN base_grade t4 ON t3.grade_id = t4.id" +
+                " WHERE t1.delete_mark = 0 AND t2.delete_mark = 0 AND t3.class_type IS NOT NULL";
+        List<String[]> list = db.query(sql, String[].class);
+        Map<Integer, String> clientMap = new HashMap<>();
+
+        String apiPath = "/api/resource/v2/person/single/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_student");
+
+        for(int i = 1; i < list.size(); i ++){
+            String[] el = list.get(i);
+            if(tableData != null && tableData.containsKey(el[0])){
                 continue;
             }
+            JsonObject paramJson = new JsonObject();
+            paramJson.addProperty("clientId", i);
+            paramJson.addProperty("personId", el[0]);
+            paramJson.addProperty("personName", el[1]);
+            paramJson.addProperty("orgIndexCode", el[2]);
+            paramJson.addProperty("phoneNo", el[6]);
+            paramJson.addProperty("jobNo", el[3]);
+            paramJson.addProperty("birthday", el[5]);
+            paramJson.addProperty("personType", 2);
 
-            //获取时间戳
-            long timestamp = System.currentTimeMillis();
-            //生成签名
-            String sign = ScheduleUtil.createSign(timestamp);
-            String result = ScheduleUtil.doPost(url, paramJson.toString(), sign, timestamp);
-            if(result == null){
+            int gender;
+            switch (el[4]) {
+                case "SB10001":
+                    gender = 1;
+                    break;
+                case "SB10002":
+                    gender = 2;
+                    break;
+                default:
+                    gender = 0;
+                    break;
+            }
+            paramJson.addProperty("gender", gender);
+
+            clientMap.put(i, el[0]);
+            System.out.println("入参:" + paramJson.toString());
+            String result = apiUtil.doPost(apiPath, paramJson.toString(), null, header);
+            JsonElement parse = jsonParser.parse(result);
+            JsonObject resultJson = parse.getAsJsonObject();
+            if("0".equals(resultJson.get("code").getAsString()) && "success".equals(resultJson.get("msg").getAsString())){
+                JsonObject array = resultJson.get("data").getAsJsonObject();
+                idMap.put(el[0], array.get("personId").getAsString());
+            }
+        }
+
+        //插入记录表
+        insertRecord(db, tableName, idMap);
+        return idMap;
+    }
+
+    public Map<String, String> insertStudent(Db db, String tableName, Map<String, String> tableData) throws Exception {
+        String sql = "SELECT t1.id,t1.name,CONCAT(t3.id,'-',t4.name,'-',t3.class_type,'-',t2.stduy_status)," +
+                " t1.user_name,t1.gender,t1.birth_date,t1.mobile,t1.email,t1.credential_type,t1.credential_number FROM xjr_user t1" +
+                " INNER JOIN base_student_school_roll t2 ON t1.id = t2.user_id" +
+                " INNER JOIN base_class t3 ON t2.class_id = t3.id" +
+                " INNER JOIN base_grade t4 ON t3.grade_id = t4.id" +
+                " WHERE t1.delete_mark = 0 AND t2.delete_mark = 0 AND t3.class_type IS NOT NULL ";
+        List<String[]> list = db.query(sql, String[].class);
+        Map<Integer, String> clientMap = new HashMap<>();
+
+        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_student");
+
+        int maxCount = 100;
+
+        int frequency = list.size() / maxCount;
+        for(int index = 0; index < frequency; index ++){
+            JsonArray paramArray = new JsonArray();
+
+            for(int i = (index * maxCount); i < ((index + 1) * maxCount); i ++){
+                if(i >= list.size()){
+                    continue;
+                }
+                String[] el = list.get(i);
+                if(tableData != null && tableData.containsKey(el[0])){
+                    continue;
+                }
+                JsonObject paramJson = new JsonObject();
+                paramJson.addProperty("clientId", i);
+                paramJson.addProperty("personId", el[0]);
+                paramJson.addProperty("personName", el[1]);
+                paramJson.addProperty("orgIndexCode", el[2]);
+                paramJson.addProperty("phoneNo", el[6]);
+                paramJson.addProperty("jobNo", el[3]);
+                paramJson.addProperty("birthday", el[5]);
+                paramJson.addProperty("personType", 2);
+
+                int gender;
+                switch (el[4]) {
+                    case "SB10001":
+                        gender = 1;
+                        break;
+                    case "SB10002":
+                        gender = 2;
+                        break;
+                    default:
+                        gender = 0;
+                        break;
+                }
+                paramJson.addProperty("gender", gender);
+                paramArray.add(paramJson);
+
+                clientMap.put(i, el[0]);
+            }
+
+            String result = apiUtil.doPost(apiPath, paramArray.toString(), null, header);
+            JsonElement parse = jsonParser.parse(result);
+            JsonObject resultJson = parse.getAsJsonObject();
+            if("0".equals(resultJson.get("code").getAsString()) && "success".equals(resultJson.get("msg").getAsString())){
+                JsonArray array = resultJson.get("data").getAsJsonObject().get("successes").getAsJsonArray();
+                for (JsonElement jsonElement : array) {
+                    JsonObject jsonObject = jsonElement.getAsJsonObject();
+                    idMap.put(clientMap.get(jsonObject.get("clientId").getAsInt()), jsonObject.get("personId").getAsString());
+                }
+            }
+        }
+
+        //插入记录表
+        insertRecord(db, tableName, idMap);
+        return idMap;
+    }
+
+    public Map<String, String> insertTeacher(Db db, String tableName, Map<String, String> tableData, Map<String, String> deptMap) throws Exception {
+        String sql = "SELECT t1.id,t1.name,t1.gender,t3.dept_id,t1.birth_date,t1.mobile,t1.email,t1.credential_type,t1.credential_number,t1.user_name FROM xjr_user t1" +
+                " INNER JOIN " + tableName + " t2 ON t1.id = t2.user_id" +
+                " INNER JOIN xjr_user_dept_relation t3 ON t1.id = t3.user_id" +
+                " INNER JOIN xjr_department t4 ON t3.dept_id = t4.id " +
+                " WHERE t1.delete_mark = 0 AND t2.delete_mark = 0 AND t4.delete_mark = 0";
+        List<String[]> list = db.query(sql, String[].class);
+        JsonArray paramArray = new JsonArray();
+        Map<Integer, String> clientMap = new HashMap<>();
+        for(int i = 0; i < list.size(); i ++){
+            String[] el = list.get(i);
+            if(tableData != null && tableData.containsKey(el[0])){
                 continue;
             }
-            JsonObject resultJson = jsonParser.parse(result).getAsJsonObject();
-            idMap.put(baseClass.getId(), resultJson.get("data").getAsString());
+            JsonObject paramJson = new JsonObject();
+            paramJson.addProperty("clientId", i);
+            paramJson.addProperty("personId", el[0]);
+            paramJson.addProperty("personName", el[1]);
+            paramJson.addProperty("orgIndexCode", deptMap.get(el[3]));
+            paramJson.addProperty("phoneNo", el[5]);
+            paramJson.addProperty("jobNo", el[9]);
+            paramJson.addProperty("birthday", el[4]);
+            paramJson.addProperty("personType", 1);
+
+            int gender;
+            switch (el[2]) {
+                case "SB10001":
+                    gender = 1;
+                    break;
+                case "SB10002":
+                    gender = 2;
+                    break;
+                default:
+                    gender = 0;
+                    break;
+            }
+            paramJson.addProperty("gender", gender);
+            paramArray.add(paramJson);
+
+            clientMap.put(i, el[0]);
+        }
+
+        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");
+
+        String result = apiUtil.doPost(apiPath, paramArray.toString(), null, header);
+        JsonElement parse = jsonParser.parse(result);
+        JsonObject resultJson = parse.getAsJsonObject();
+        if("0".equals(resultJson.get("code").getAsString()) && "success".equals(resultJson.get("msg").getAsString())){
+            JsonArray array = resultJson.get("data").getAsJsonObject().get("successes").getAsJsonArray();
+            for (JsonElement jsonElement : array) {
+                JsonObject jsonObject = jsonElement.getAsJsonObject();
+                idMap.put(clientMap.get(jsonObject.get("clientId").getAsInt()), jsonObject.get("personId").getAsString());
+            }
+        }else{
+
         }
         //插入记录表
-//        insertRecord(db, tableName, idMap);
+        insertRecord(db, tableName, idMap);
         return idMap;
     }
+
+    /*同步车辆数据*/
+    public Map<Long, String> insertCar(Db db, String tableName, Map<String, String> tableData, FaceImportMapper faceImportMapper) throws Exception {
+        String sql = "SELECT * FROM " + tableName + " WHERE delete_mark = 0 and status = 1";
+        List<CarMessageApply> dataList = db.query(sql, CarMessageApply.class);
+        String apiPath = "/api/resource/v1/vehicle/batch/add";
+        String apiPathTime = "/api/pms/v1/car/charge";
+        Map<Long, String> idMap = new HashMap<>();
+        JsonParser jsonParser = new JsonParser();
+        ApiUtil apiUtil = new ApiUtil();
+
+        Map<Integer, Long> clientMap = new HashMap<>();
+        Map<String, String> tagMap = new HashMap<>();
+        tagMap.put("tagId", "frs");
+
+        String existingPlatesSql = "SELECT source_id FROM hikvision_data";
+        List<String> existingPlates = db.query(existingPlatesSql, String.class);
+
+        JsonArray dataArray = new JsonArray();
+        String result = null;
+        int clientId = 1;
+        for (CarMessageApply carMessageApply : dataList) {
+            if(existingPlates.contains(carMessageApply.getId() + "")){
+                continue;
+            }
+
+            JsonObject paramJson = new JsonObject();
+            paramJson.addProperty("clientId", clientId);
+            paramJson.addProperty("plateNo", carMessageApply.getCarNumber().trim());
+            paramJson.addProperty("personId", faceImportMapper.GetHikvisonPersonId(carMessageApply.getId().toString()));
+
+            int vehicleTypeNum;
+            switch (carMessageApply.getVehicleType()) {
+                case "小型车":
+                    vehicleTypeNum = 1;
+                    break;
+                case "大型车":
+                    vehicleTypeNum = 2;
+                    break;
+                case "摩托车":
+                    vehicleTypeNum = 3;
+                    break;
+                default:
+                    vehicleTypeNum = 0;
+                    break;
+            }
+            paramJson.addProperty("vehicleType", vehicleTypeNum);
+            clientMap.put(clientId, carMessageApply.getId());
+            dataArray.add(paramJson);
+            clientId++;
+        }
+        result = apiUtil.doPost(apiPath, dataArray.toString(), tagMap, null);
+
+        for (CarMessageApply carMessageApply : dataList) {
+            JsonObject paramJsonTime = new JsonObject();
+            paramJsonTime.addProperty("parkSyscode", "c69f2a7c48a74216bcab7d65f24d4a09");
+            paramJsonTime.addProperty("plateNo", carMessageApply.getCarNumber().trim());
+            paramJsonTime.addProperty("startTime", String.valueOf(carMessageApply.getStartTime()));
+            paramJsonTime.addProperty("endTime", String.valueOf(carMessageApply.getEndTime()));
+            apiUtil.doPost(apiPathTime, String.valueOf(paramJsonTime), tagMap, null);
+        }
+
+        JsonElement parse = jsonParser.parse(result);
+        JsonObject resultJson = parse.getAsJsonObject();
+        if ("0".equals(resultJson.get("code").getAsString()) && "success".equals(resultJson.get("msg").getAsString())) {
+            JsonArray array = resultJson.get("data").getAsJsonObject().get("successes").getAsJsonArray();
+            for (JsonElement jsonElement : array) {
+                JsonObject jsonObject = jsonElement.getAsJsonObject();
+                int responseClientId = jsonObject.get("clientId").getAsInt();
+                Long sourceId = clientMap.get(responseClientId);
+                if (sourceId != null) {
+                    idMap.put(sourceId, jsonObject.get("vehicleId").getAsString());
+                } else {
+                    System.err.println("No matching clientId found in clientMap for: " + responseClientId);
+                }
+            }
+            insertRecord(db, tableName, idMap);
+        } else {
+            System.err.println("API call failed: " + resultJson.get("msg").getAsString());
+        }
+        return idMap;
+    }
+
+    void insertRecord(Db db, String tableName, Map<?, String> idsMap) throws SQLException {
+        if (idsMap.isEmpty()) {
+            return;
+        }
+        var sqls = new ArrayList<String>();
+        for (var entry : idsMap.entrySet()) {
+            var sourceId = entry.getKey();
+            var sql = "INSERT INTO hikvision_data(create_date, table_name, source_id, hikvision_id) " +
+                    "VALUES(now(), '" + tableName + "', '" + sourceId + "', '" + entry.getValue() + "')";
+            sqls.add(sql);
+        }
+        db.executeBatch(sqls);
+    }
+
+//    void insertRecord(Db db, String tableName, Map<Long, String> idsMap) throws SQLException {
+//        if(idsMap.isEmpty()){
+//            return;
+//        }
+//        List<String> sqls = new ArrayList<>();
+//        for (Long sourceId : idsMap.keySet()) {
+//            String sql = "INSERT INTO hikvision_data(create_date,table_name,source_id,hikvision_id) value(now(),'"
+//                    + tableName + "'," + sourceId + ",'" + idsMap.get(sourceId) + "')";
+//            sqls.add(sql);
+//        }
+//        db.executeBatch(sqls);
+//    };
 }

+ 123 - 0
src/main/java/com/xjrsoft/module/hikvision/util/EventController.java

@@ -0,0 +1,123 @@
+package com.xjrsoft.module.hikvision.util;
+
+import cn.hutool.db.Db;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import com.xjrsoft.common.constant.GlobalConstant;
+import com.xjrsoft.common.model.result.RT;
+import com.xjrsoft.common.utils.DatasourceUtil;
+import com.xjrsoft.config.HikvisionConfig;
+import com.xjrsoft.module.teacher.mapper.FaceImportMapper;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.sql.DataSource;
+import java.sql.SQLException;
+import java.text.ParseException;
+
+@RestController
+@RequestMapping("/event")
+@Api(value = "/event", tags = "订阅事件接收")
+@AllArgsConstructor
+@Slf4j
+public class EventController {
+    private final Out_In_RecordUtil outInRecordUtil = new Out_In_RecordUtil();
+
+    DataSource datasource = DatasourceUtil.getDataSource(GlobalConstant.DEFAULT_DATASOURCE_KEY);
+    private final Db use = Db.use(datasource);
+    private final FaceImportMapper faceImportMapper;
+    private final HikvisionConfig hikvisionConfig;
+
+    @PostMapping("/receiveCar")
+    @ApiOperation(value = "接收车辆事件")
+    public ResponseEntity<Void> receiveCarEvent(@RequestBody(required = false) String eventData) {
+        log.info("Received event data: {}", eventData);
+        new Thread(() -> {
+            try {
+                outInRecordUtil.GetVehicleRecordTest(use, faceImportMapper, eventData);
+            } catch (SQLException | ParseException e) {
+                log.error("Error processing event data", e);
+            }
+        }).start();
+
+        // 立即返回HTTP 200 OK响应
+        return ResponseEntity.ok().build();
+    }
+
+    @PostMapping("/receivePeople")
+    @ApiOperation(value = "接收人员事件")
+    public ResponseEntity<Void> receivePeopleEvent(@RequestBody(required = false) String eventData) {
+        log.info("Received event data: {}", eventData);
+        new Thread(() -> {
+            try {
+                outInRecordUtil.GetTeacherAndStudentRecordsTest(use, faceImportMapper, eventData);
+            } catch (SQLException | ParseException e) {
+                log.error("Error processing event data", e);
+            }
+        }).start();
+
+        return ResponseEntity.ok().build();
+    }
+
+    @PostMapping("/subscribe")
+    @ApiOperation(value = "订阅事件")
+    public RT<Boolean> subscribeEvent() {
+        ApiUtil apiUtil = new ApiUtil();
+        JsonArray eventList = new JsonArray();
+        String apiPath = "/api/eventService/v1/eventSubscriptionByEventTypes";
+        JsonObject paramJson = new JsonObject();
+//*******手动更改****************************************************
+//        eventList.add(196893); //人脸匹配成功
+        eventList.add(771760131); //入场放行事件
+        eventList.add(771760134); //出场放行事件
+        paramJson.addProperty("eventDest", hikvisionConfig.getCarUrl()); //要修改第二个参数
+//******************************************************************
+        paramJson.add("eventTypes", eventList);
+
+        String response = apiUtil.doPost(apiPath, paramJson.toString(), null);
+        log.info("Subscribe response: {}", response);
+        return RT.ok(true);
+    }
+
+    @PostMapping("/query")
+    @ApiOperation(value = "查询已订阅事件")
+    public String queryEvent() {
+        ApiUtil apiUtil = new ApiUtil();
+        String apiPath = "/api/eventService/v1/eventSubscriptionView";
+        String response = apiUtil.doPost(apiPath, null, null);
+        System.out.println("output: " + response);
+//        Gson gson = new GsonBuilder().setPrettyPrinting().create();
+//
+//        JsonElement jsonElement = JsonParser.parseString(response);
+//
+//        String prettyJson = gson.toJson(jsonElement);
+
+        return response;
+    }
+
+    @PostMapping("/cancel")
+    @ApiOperation(value = "取消已订阅事件")
+    public String cancelEvent() {
+        ApiUtil apiUtil = new ApiUtil();
+        JsonArray eventList = new JsonArray();
+//*******手动更改****************************************************
+        eventList.add(196893);
+        eventList.add(771760131); //正常过车
+        eventList.add(771760134);
+//******************************************************************
+        JsonObject paramJson = new JsonObject();
+        paramJson.add("eventTypes", eventList);
+        String apiPath = "/api/eventService/v1/eventUnSubscriptionByEventTypes";
+        String response = apiUtil.doPost(apiPath, paramJson.toString(), null);
+        System.out.println("output: " + response);
+
+        return response;
+    }
+}

+ 69 - 0
src/main/java/com/xjrsoft/module/hikvision/util/FaceImportUtil.java

@@ -0,0 +1,69 @@
+package com.xjrsoft.module.hikvision.util;
+
+import com.google.gson.JsonObject;
+import com.xjrsoft.module.personnel.entity.TeacherFaceProcess;
+import com.xjrsoft.module.teacher.mapper.FaceImportMapper;
+
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Base64;
+import java.util.HashMap;
+import java.util.Map;
+
+
+
+public class FaceImportUtil {
+
+    private static ApiUtil apiUtil = new ApiUtil();
+
+    public static String ImportTeacherFace(String personId, String fileUrl) {
+        JsonObject paramJson = new JsonObject();
+        paramJson.addProperty("personId", personId);
+        paramJson.addProperty("faceData", ImageToBase64(fileUrl));
+
+        Map<String, String> querys = new HashMap<>();
+        querys.put("tagId", "frs");
+
+        String apiPath = "/api/resource/v1/face/single/add";
+        String response = apiUtil.doPost(apiPath, String.valueOf(paramJson), querys);
+
+        return response;
+    }
+
+    public static String ImportStudentFace(String personId, String fileUrl) {
+        JsonObject paramJson = new JsonObject();
+        paramJson.addProperty("personId", personId);
+        paramJson.addProperty("faceData", ImageToBase64(fileUrl));
+
+        Map<String, String> querys = new HashMap<>();
+        querys.put("tagId", "frs");
+
+        String apiPath = "/api/resource/v1/face/single/add";
+        String response = apiUtil.doPost(apiPath, String.valueOf(paramJson), querys);
+
+        return response;
+    }
+
+    public static String ImageToBase64(String imageUrl) {
+        String base64String = "";
+        try {
+            URL url = new URL(imageUrl);
+            InputStream inputStream = url.openStream();
+            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+            byte[] buffer = new byte[4096];
+            int bytesRead;
+            while ((bytesRead = inputStream.read(buffer)) != -1) {
+                outputStream.write(buffer, 0, bytesRead);
+            }
+            byte[] imageBytes = outputStream.toByteArray();
+            base64String = Base64.getEncoder().encodeToString(imageBytes);
+            inputStream.close();
+            outputStream.close();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        int commaIndex = base64String.indexOf(',') + 1;
+        return base64String.substring(commaIndex);
+    }
+}

+ 587 - 0
src/main/java/com/xjrsoft/module/hikvision/util/Out_In_RecordUtil.java

@@ -0,0 +1,587 @@
+package com.xjrsoft.module.hikvision.util;
+
+import cn.hutool.db.Db;
+import com.google.gson.Gson;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.xjrsoft.module.attendance.entity.AttendanceRuleDetails;
+import com.xjrsoft.module.teacher.mapper.FaceImportMapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.sql.SQLException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Date;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicInteger;
+
+
+public class Out_In_RecordUtil {
+    private static final Logger log = LoggerFactory.getLogger(Out_In_RecordUtil.class);
+
+    private void teacherInsertRecord(Db db, Long userId, String recordTime, String facePhoto, int status, String eventId, String attendanceStatus) throws SQLException {
+
+        String sql = "INSERT INTO teacher_out_in_record(create_date, user_id, record_time, face_photo, eventId, status,delete_mark,enabled_mark, attendance_status) " +
+                "VALUES(now(), '"  + userId + "', '" + recordTime + "', '" +
+                facePhoto + "', '" + eventId + "', '" +status + "',0,1,'" + attendanceStatus + "')";
+        db.execute(sql);
+    }
+
+    private void studentInsertRecord(Db db, Long userId, Long teacherId, Long classId, String facePhoto, String recordTime, int status, String eventId, String attendanceStatus) throws SQLException {
+        String sql = "INSERT INTO student_out_in_record(create_date, user_id, teacher_id, class_id, face_photo, record_time , eventId,status,delete_mark,enabled_mark, attendance_status) " +
+                "VALUES(now(), '" + userId + "', '" + teacherId + "', '" +
+                classId + "', '" + facePhoto + "', '" + recordTime + "', '" + eventId + "', '" + status + "',0,1,'" + attendanceStatus + "')";
+        db.execute(sql);
+    }
+
+
+    public void visitInsertRecord(Db db, Long reservation_school_people_id, String recordTime,String facePhoto, int status) throws SQLException {
+        String sql = "INSERT INTO visitor_out_in_record(create_date, reservation_school_people_id, record_time, face_photo, status,delete_mark,enabled_mark) " +
+                "VALUES(now(), '"  + reservation_school_people_id + "', '" +
+                 recordTime + "', '" + facePhoto + "', '" + status +  "',0,1)";
+        db.execute(sql);
+    }
+
+    private void vehicleInsertRecord(Db db, Long carMessageApplyId, String recordTime, int releaseReason, int category, String facePhoto, int status, String planNo, String crossRecordSyscode,
+                                     int releaseResult, int releaseWay, int vehicleType, String phone, String name) throws SQLException {
+        String sql = "INSERT INTO car_out_in_record(create_date, car_message_apply_id, record_time, face_photo, status,release_reason, plan_no, " +
+                "cross_record_syscode, release_result, release_way, vehicle_type, phone, name, category,delete_mark,enabled_mark) " +
+                "VALUES(now(), '"  + carMessageApplyId + "', '" +
+                recordTime + "', '" + facePhoto + "', '" + status + "', '" + releaseReason + "', '" + planNo + "', '" +
+                crossRecordSyscode + "', '" + releaseResult + "', '" + releaseWay + "', '" + vehicleType + "', '" + phone + "', '" + name + "', '" + category  +  "',0,1)";
+        db.execute(sql);
+    }
+
+    public void GetTeacherAndStudentRecords(Db use, FaceImportMapper faceImportMapper) throws SQLException, ParseException {
+        JsonArray responseBuilder = new JsonArray();
+
+        AtomicInteger pageNo = new AtomicInteger(1);
+        int pageSize = 100;
+        boolean hasMorePages = true;
+
+        while (hasMorePages) {
+            String response = GetDoorEvent(pageNo, pageSize);
+
+            JsonElement responseElement = new Gson().fromJson(response, JsonElement.class);
+            JsonArray dataList = responseElement.getAsJsonObject().getAsJsonObject("data").getAsJsonArray("list");
+
+            for (JsonElement item : dataList) {
+                responseBuilder.add(item);
+            }
+
+            JsonObject responseJson = new Gson().fromJson(response, JsonObject.class);
+            int totalCount = responseJson.getAsJsonObject("data").get("totalPage").getAsInt();
+            hasMorePages = pageNo.getAndIncrement() * pageSize < totalCount;
+        }
+        // Process the records
+        InsertTeacherStudentRecords(use, responseBuilder, faceImportMapper);
+    }
+
+    private void InsertTeacherStudentRecords(Db use, JsonArray doorEventsResponse, FaceImportMapper faceImportMapper) throws SQLException, ParseException {
+        List<String> teacherEventIdList = faceImportMapper.GetTeacherUrlList();
+        List<String> studentEventIdList = faceImportMapper.GetStudentUrlList();
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+        for (JsonElement element : doorEventsResponse) {
+            JsonObject item = element.getAsJsonObject();
+
+            Long personId;
+            try {
+                personId = item.get("personId").isJsonNull() ? null : item.get("personId").getAsLong();
+            }catch (Exception e){
+                continue;
+            }
+            if (personId == null) continue;
+
+            int status = item.get("inAndOutType").getAsInt();
+            String uri = item.get("picUri").isJsonNull() ? null : item.get("picUri").getAsString();
+            String recordTime = item.get("eventTime").isJsonNull() ? null : item.get("eventTime").getAsString();
+            String eventId = item.get("eventId").isJsonNull() ? null : item.get("eventId").getAsString();
+            String recordTimeStr = ChangeTime(recordTime);
+            if (!Objects.equals(faceImportMapper.IsStudentTypeByPersonId(personId), "学生")) {
+                // 老师记录
+                if (teacherEventIdList.contains(eventId)) {
+                    continue;
+                }
+                LocalDateTime recordTimeDate = LocalDateTime.parse(recordTimeStr, formatter);
+                String attendanceStatus = discernTeacherStatus(use, recordTimeDate, status, personId);
+                teacherInsertRecord(use, personId, recordTimeStr, ApiUtil.GetRedirectURL(uri),status,eventId, attendanceStatus);
+            } else {
+                // 学生记录
+                if (studentEventIdList.contains(eventId)){
+                    continue;
+                }
+                LocalDateTime recordTimeDate = LocalDateTime.parse(recordTimeStr, formatter);
+                String attendanceStatus = discernStudentStatus(use, recordTimeDate, status, personId);
+                studentInsertRecord(use, personId, faceImportMapper.GetTeacherIdByPersonId(personId),
+                        faceImportMapper.GetClassIdByPersonId(personId), ApiUtil.GetRedirectURL(uri), recordTimeStr, status,eventId, attendanceStatus);
+            }
+        }
+    }
+
+    String discernTeacherStatus(Db use, LocalDateTime recordTime, int status, Long userId) throws SQLException {
+        String attendanceStatus = "";
+        String dayOfWeek = recordTime.getDayOfWeek().name();
+        String sql = "SELECT t2.* FROM attendance_rule_category t1" +
+                " INNER JOIN attendance_rule_details t2 ON t1.id = t2.attendance_rule_category_id" +
+                " INNER JOIN attendance_user_relation t3 ON t1.id = t3.attendance_rule_category_id" +
+                " WHERE t1.delete_mark = 0 AND t2.delete_mark = 0 AND NOW() BETWEEN start_date AND end_date" +
+                " AND t2.date_type = '" + dayOfWeek + "' and t3.user_id = " + userId;
+        List<AttendanceRuleDetails> ruleDetailsList = use.query(sql, AttendanceRuleDetails.class);
+        if(!ruleDetailsList.isEmpty()){
+            AttendanceRuleDetails ruleDetails = ruleDetailsList.get(0);
+            if (ruleDetails != null) {
+                if (ruleDetails.getIsAttendance() != null && ruleDetails.getIsAttendance() == 0) {
+                    attendanceStatus = "不考勤";
+                } else {
+                    LocalDateTime amStartTime = null, amEndTime = null, pmStartTime = null, pmEndTime = null, eveningStartTime = null, eveningEndTime = null;
+                    if (ruleDetails.getAmStatus() != null && ruleDetails.getAmStatus() == 1) {
+                        amStartTime = recordTime.withHour(ruleDetails.getAmStartTime().getHour())
+                                .withMinute(ruleDetails.getAmStartTime().getMinute())
+                                .withSecond(ruleDetails.getAmStartTime().getSecond());
+                        amEndTime = recordTime.withHour(ruleDetails.getAmEndTime().getHour())
+                                .withMinute(ruleDetails.getAmEndTime().getMinute())
+                                .withSecond(ruleDetails.getAmEndTime().getSecond());
+                    }
+                    if (ruleDetails.getPmStatus() != null && ruleDetails.getPmStatus() == 1) {
+                        pmStartTime = recordTime.withHour(ruleDetails.getPmStartTime().getHour())
+                                .withMinute(ruleDetails.getPmStartTime().getMinute())
+                                .withSecond(ruleDetails.getPmStartTime().getSecond());
+                        pmEndTime = recordTime.withHour(ruleDetails.getPmEndTime().getHour())
+                                .withMinute(ruleDetails.getPmEndTime().getMinute())
+                                .withSecond(ruleDetails.getPmEndTime().getSecond());
+                    }
+                    if (status == 0) {//出
+                        if (recordTime.isBefore(amEndTime) && recordTime.isAfter(amStartTime)) {
+                            attendanceStatus = "早退";
+                        } else if (recordTime.isBefore(pmEndTime) && recordTime.isAfter(pmStartTime)) {
+                            attendanceStatus = "早退";
+                        } else {
+                            attendanceStatus = "离校";
+                        }
+                    } else {//进
+                        if (recordTime.isBefore(amEndTime) && recordTime.isAfter(amStartTime)) {
+                            attendanceStatus = "迟到";
+                        } else if (recordTime.isBefore(pmEndTime) && recordTime.isAfter(pmStartTime)) {
+                            attendanceStatus = "迟到";
+                        } else {
+                            attendanceStatus = "到校";
+                        }
+                    }
+                }
+            }
+        }
+        return attendanceStatus;
+    }
+
+
+    String discernStudentStatus(Db use, LocalDateTime recordTime, int status, Long studentUserId) throws SQLException {
+        String attendanceStatus = "";
+        String dayOfWeek = recordTime.getDayOfWeek().name();
+        String sql = "SELECT t2.* FROM attendance_rule_category t1" +
+                " INNER JOIN attendance_rule_details t2 ON t1.id = t2.attendance_rule_category_id" +
+                " INNER JOIN attendance_user_relation t3 ON t1.id = t3.attendance_rule_category_id" +
+                " WHERE t1.delete_mark = 0 AND t2.delete_mark = 0 AND NOW() BETWEEN start_date AND end_date" +
+                " AND t2.date_type = '" + dayOfWeek + "' and t3.user_id = " + studentUserId;
+        List<AttendanceRuleDetails> ruleDetailsList = use.query(sql, AttendanceRuleDetails.class);
+        if(!ruleDetailsList.isEmpty()){
+            AttendanceRuleDetails ruleDetails = ruleDetailsList.get(0);
+            if(ruleDetails.getIsAllowInOutSchool() != null && ruleDetails.getIsAllowInOutSchool() == 0){
+                attendanceStatus = "不考勤";
+            }else{
+                LocalDateTime amStartTime = null, amEndTime = null, pmStartTime = null, pmEndTime = null, eveningStartTime = null, eveningEndTime = null;
+                if(ruleDetails.getAmStatus() != null && ruleDetails.getAmStatus() == 1){
+                    amStartTime = recordTime.withHour(ruleDetails.getAmStartTime().getHour())
+                            .withMinute(ruleDetails.getAmStartTime().getMinute())
+                            .withSecond(ruleDetails.getAmStartTime().getSecond());
+                    amEndTime = recordTime.withHour(ruleDetails.getAmEndTime().getHour())
+                            .withMinute(ruleDetails.getAmEndTime().getMinute())
+                            .withSecond(ruleDetails.getAmEndTime().getSecond());
+                }
+                if(ruleDetails.getPmStatus() != null && ruleDetails.getPmStatus() == 1){
+                    pmStartTime = recordTime.withHour(ruleDetails.getPmStartTime().getHour())
+                            .withMinute(ruleDetails.getPmStartTime().getMinute())
+                            .withSecond(ruleDetails.getPmStartTime().getSecond());
+                    pmEndTime = recordTime.withHour(ruleDetails.getPmEndTime().getHour())
+                            .withMinute(ruleDetails.getPmEndTime().getMinute())
+                            .withSecond(ruleDetails.getPmEndTime().getSecond());
+                }
+                if(ruleDetails.getEveningStatus() != null && ruleDetails.getEveningStatus() == 1){
+                    eveningStartTime = recordTime.withHour(ruleDetails.getEveningStartTime().getHour())
+                            .withMinute(ruleDetails.getEveningStartTime().getMinute())
+                            .withSecond(ruleDetails.getEveningStartTime().getSecond());
+                    eveningEndTime = recordTime.withHour(ruleDetails.getEveningEndTime().getHour())
+                            .withMinute(ruleDetails.getEveningEndTime().getMinute())
+                            .withSecond(ruleDetails.getEveningEndTime().getSecond());
+                }
+                if(status == 0){//出
+                    if(recordTime.isBefore(amEndTime) && recordTime.isAfter(amStartTime)){
+                        attendanceStatus = "早退";
+                    }else if(recordTime.isBefore(pmEndTime) && recordTime.isAfter(pmStartTime)){
+                        attendanceStatus = "早退";
+                    }else if(recordTime.isBefore(eveningEndTime) && recordTime.isAfter(eveningStartTime)){
+                        attendanceStatus = "早退";
+                    }else{
+                        attendanceStatus = "离校";
+                    }
+                }else{//进
+                    if(recordTime.isBefore(amEndTime) && recordTime.isAfter(amStartTime)){
+                        attendanceStatus = "迟到";
+                        if(recordTime.isAfter(amStartTime.plusMinutes(40))){
+                            attendanceStatus = "旷课";
+                        }
+                    }else if(recordTime.isBefore(pmEndTime) && recordTime.isAfter(pmStartTime)){
+                        attendanceStatus = "迟到";
+                        if(recordTime.isAfter(pmStartTime.plusMinutes(40))){
+                            attendanceStatus = "旷课";
+                        }
+                    }else if(recordTime.isBefore(eveningEndTime) && recordTime.isAfter(eveningStartTime)){
+                        attendanceStatus = "迟到";
+                        if(recordTime.isAfter(eveningStartTime.plusMinutes(40))){
+                            attendanceStatus = "旷课";
+                        }
+                    }else{
+                        attendanceStatus = "到校";
+                    }
+                }
+            }
+        }
+        return attendanceStatus;
+    }
+
+    public void GetVisitRecord(Db use, FaceImportMapper faceImportMapper) throws SQLException, ParseException {
+        ApiUtil apiUtil = new ApiUtil();
+
+        AtomicInteger pageNo = new AtomicInteger(1);
+        int pageSize = 100;
+        boolean hasMorePages = true;
+        JsonArray responseBuilder = new JsonArray();
+        JsonArray responseDoorBuilder = new JsonArray();
+
+        String apiPath = "/api/visitor/v1/event/turnover/search";
+
+        while (hasMorePages) {
+            JsonObject paramJson = new JsonObject();
+            paramJson.addProperty("pageNo", pageNo.get());
+            paramJson.addProperty("pageSize", pageSize);
+
+            String response = apiUtil.doPost(apiPath, String.valueOf(paramJson), null);
+            String responseDoor = GetDoorEvent(pageNo,pageSize);
+
+            JsonElement responseElement = new Gson().fromJson(response, JsonElement.class);
+            JsonElement responseDoorElement = new Gson().fromJson(responseDoor, JsonElement.class);
+
+            JsonArray dataList = responseElement.getAsJsonObject().getAsJsonObject("data").getAsJsonArray("rows");
+            JsonArray dataDoorList = responseDoorElement.getAsJsonObject().getAsJsonObject("data").getAsJsonArray("list");
+
+            for (JsonElement item : dataList) {
+                responseBuilder.add(item);
+            }
+
+            for (JsonElement item : dataDoorList) {
+                responseDoorBuilder.add(item);
+            }
+
+            JsonObject responseJson = new Gson().fromJson(response, JsonObject.class);
+            int totalCount = responseJson.getAsJsonObject("data").get("total").getAsInt();
+            hasMorePages = pageNo.getAndIncrement() * pageSize < totalCount;
+        }
+
+        InsertVisitRecords(use, responseBuilder,responseDoorBuilder,faceImportMapper);
+    }
+
+    private void InsertVisitRecords(Db use, JsonArray eventsResponse, JsonArray doorEventsResponse,FaceImportMapper faceImportMapper) throws SQLException, ParseException {
+        List<Long> visit_id_list = faceImportMapper.GetReservationSchoolIdList();
+
+        for (JsonElement element : eventsResponse) {
+            JsonObject item = element.getAsJsonObject();
+
+            String picUri = item.get("visitorPhotoUri").isJsonNull() ? null : ApiUtil.GetRedirectURL(item.get("visitorPhotoUri").getAsString());
+            String orderId = item.get("orderId").isJsonNull() ? null : item.get("orderId").getAsString();
+            String eventTime = item.get("eventTime").isJsonNull() ? null : ChangeTime(item.get("eventTime").getAsString());
+            //todo: reservationSchoolId
+//            Long reservationSchoolId = faceImportMapper.GetReservationSchoolId(orderId) == null ? 1 : faceImportMapper.GetReservationSchoolId(orderId);
+
+            int status = -1;
+            for (JsonElement e : doorEventsResponse){
+                JsonObject ele = e.getAsJsonObject();
+                if (ele.get("eventId") == item.get("eventId")){
+                    status = ele.get("inAndOutType").getAsInt();
+                    break;
+                }
+            }
+
+            if (visit_id_list.contains(1)) continue;
+            visitInsertRecord(use, Long.parseLong("123"), eventTime, picUri, status);
+        }
+
+    }
+
+    public void GetVehicleRecord(Db use, FaceImportMapper faceImportMapper) throws SQLException, ParseException {
+        ApiUtil apiUtil = new ApiUtil();
+
+        AtomicInteger pageNo = new AtomicInteger(1);
+        int pageSize = 1000;
+        boolean hasMorePages = true;
+        JsonArray responseBuilder = new JsonArray();
+
+        String apiPath = "/api/pms/v1/crossRecords/page";
+
+        while (hasMorePages) {
+            JsonObject paramJson = new JsonObject();
+            paramJson.addProperty("pageNo", pageNo.getAndIncrement());
+            paramJson.addProperty("pageSize", pageSize);
+
+            String response = apiUtil.doPost(apiPath, String.valueOf(paramJson), null);
+            JsonElement responseElement = new Gson().fromJson(response, JsonElement.class);
+            JsonArray dataList = responseElement.getAsJsonObject().getAsJsonObject("data").getAsJsonArray("list");
+
+            for (JsonElement item : dataList) {
+                responseBuilder.add(item);
+            }
+
+            JsonObject responseJson = new Gson().fromJson(response, JsonObject.class);
+            int totalCount = responseJson.getAsJsonObject("data").get("total").getAsInt();
+            hasMorePages = pageNo.getAndIncrement() * pageSize < totalCount;
+        }
+
+        InsertVehicleRecords(use, responseBuilder,faceImportMapper);
+    }
+
+    private void InsertVehicleRecords(Db use, JsonArray doorEventsResponse, FaceImportMapper faceImportMapper) throws SQLException, ParseException {
+        List<String> vehicle_id_list = faceImportMapper.GetVehicleIdList();
+
+        for (JsonElement element : doorEventsResponse) {
+            JsonObject item = element.getAsJsonObject();
+
+            String carMessageApplyIdStr = faceImportMapper.GetCarMessageApplyIdByCarNumber(item.get("plateNo").getAsString().trim());
+            Long carId = (carMessageApplyIdStr == null || carMessageApplyIdStr.isEmpty()) ? 0 : Long.parseLong(carMessageApplyIdStr);
+            String category = null;
+            int categoryInt = 0;
+            if (item.has("carCategory")){
+                category = item.get("carCategory").isJsonNull() ? null : item.get("carCategory").getAsString();
+                switch (category){
+                    case "10":
+                        categoryInt = 0;
+                        break;
+                    case "11":
+                        categoryInt = 1;
+                        break;
+                }
+            }
+
+            int releaseResultInt = 0;
+            if (item.has("releaseResult")){
+                releaseResultInt = item.get("releaseResult").isJsonNull() ? null : item.get("releaseResult").getAsInt();
+            }
+
+            int releaseWayInt = 0;
+            if (item.has("releaseWay")){
+                releaseWayInt = item.get("releaseWay").isJsonNull() ? null : item.get("releaseWay").getAsInt();
+            }
+
+            int releaseReasonInt = 0;
+            if (item.has("releaseReason")){
+                releaseReasonInt = item.get("releaseReason").isJsonNull() ? null : item.get("releaseReason").getAsInt();
+            }
+
+            int vehicleType = item.get("vehicleType").isJsonNull() ? null : item.get("vehicleType").getAsInt();
+            String crossRecordSyscode = item.get("crossRecordSyscode").isJsonNull() ? null : item.get("crossRecordSyscode").getAsString();
+            String plateNo = item.get("plateNo").isJsonNull() ? null : item.get("plateNo").getAsString();
+            String eventTime = item.get("crossTime").isJsonNull() ? null : ChangeTime(item.get("crossTime").getAsString());
+
+            int status = item.get("vehicleOut").isJsonNull() ? null : item.get("vehicleOut").getAsInt();
+            int statusInt = 0;
+            switch (status){
+                case 0:
+                    statusInt = 1;
+                    break;
+                case 1:
+                    statusInt = 0;
+                    break;
+            }
+
+            JsonElement facePicUriElement = item.get("plateNoPicUri");
+            String facePicUri;
+            if (facePicUriElement == null || facePicUriElement.isJsonNull()) {
+                facePicUri = "null";
+            } else {
+                facePicUri = ApiUtil.GetRedirectURL(facePicUriElement.getAsString());
+            }
+            System.out.println(facePicUri + "haha");
+
+            String phone = faceImportMapper.GetPhoneNumberByPlanNum(plateNo);
+            if (phone == null){
+                phone = faceImportMapper.GetPhoneNumberByPlanNumView(plateNo);
+                if (phone == null) phone = "";
+            }
+
+            String name = faceImportMapper.GetNameByPlanNum(plateNo);
+            if (name == null){
+                name = faceImportMapper.GetNameByPlanNumView(plateNo);
+                if (name == null) name = "";
+            }
+
+            if(vehicle_id_list.contains(crossRecordSyscode)) continue;
+
+            vehicleInsertRecord(use, carId, eventTime, releaseReasonInt, categoryInt, facePicUri, statusInt, plateNo,
+                    crossRecordSyscode, releaseResultInt, releaseWayInt, vehicleType, phone, name);
+        }
+    }
+
+    private String GetDoorEvent(AtomicInteger pageNo, int pageSize){
+        ApiUtil apiUtil = new ApiUtil();
+        String apiPath = "/api/acs/v2/door/events";
+        JsonObject paramJson = new JsonObject();
+        paramJson.addProperty("pageNo", pageNo.get());
+        paramJson.addProperty("pageSize", pageSize);
+
+        return apiUtil.doPost(apiPath, String.valueOf(paramJson), null);
+    }
+
+    private String ChangeTime(String recordTime) throws ParseException {
+        SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
+        SimpleDateFormat mysqlFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        Date date = isoFormat.parse(recordTime);
+        return mysqlFormat.format(date);
+    }
+
+    public void GetTeacherAndStudentRecordsTest(Db use, FaceImportMapper faceImportMapper, String data) throws SQLException, ParseException {
+        try {
+            List<String> teacherEventIdList = faceImportMapper.GetTeacherUrlList();
+            List<String> studentEventIdList = faceImportMapper.GetStudentUrlList();
+            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+
+            JsonObject jsonObject = new Gson().fromJson(data, JsonObject.class);
+            JsonObject paramsObject = jsonObject.getAsJsonObject("params");
+            JsonArray eventsArray = paramsObject.getAsJsonArray("events");
+
+            for (JsonElement eventElement : eventsArray) {
+                JsonObject eventObject = eventElement.getAsJsonObject();
+                JsonObject dataObject = eventObject.getAsJsonObject("data");
+
+                String idNum = null;
+                if (dataObject.has("ExtEventPersonNo")) {
+                    idNum = dataObject.get("ExtEventPersonNo").getAsString();
+                }
+                String happenTime = eventObject.get("happenTime").getAsString();
+                String extEventPictureURL = dataObject.get("ExtEventPictureURL").getAsString();
+                int status = eventObject.get("status").getAsInt();
+                String eventId = eventObject.get("eventId").getAsString();
+                String recordTimeStr = ChangeTime(happenTime);
+
+                if (idNum == null) continue;
+
+                if (!Objects.equals(faceImportMapper.IsStudentTypeByPersonId(Long.valueOf(idNum)), "学生")) {
+                    // 老师记录
+                    if (teacherEventIdList.contains(eventId)) {
+                        continue;
+                    }
+                    LocalDateTime recordTimeDate = LocalDateTime.parse(recordTimeStr, formatter);
+                    String attendanceStatus = discernTeacherStatus(use, recordTimeDate, status, Long.valueOf(idNum));
+                    teacherInsertRecord(use, Long.valueOf(idNum), recordTimeStr, ApiUtil.GetRedirectURL(extEventPictureURL), status, eventId, attendanceStatus);
+                } else {
+                    // 学生记录
+                    if (studentEventIdList.contains(eventId)){
+                        continue;
+                    }
+                    LocalDateTime recordTimeDate = LocalDateTime.parse(recordTimeStr, formatter);
+                    String attendanceStatus = discernStudentStatus(use, recordTimeDate, status, Long.valueOf(idNum));
+                    studentInsertRecord(use, Long.valueOf(idNum), faceImportMapper.GetTeacherIdByPersonId(Long.valueOf(idNum)),
+                            faceImportMapper.GetClassIdByPersonId(Long.valueOf(idNum)), ApiUtil.GetRedirectURL(extEventPictureURL), recordTimeStr, status,eventId, attendanceStatus);
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+
+    public void GetVehicleRecordTest(Db use, FaceImportMapper faceImportMapper, String data) throws SQLException, ParseException {
+        if (data != null) {
+            List<String> vehicle_id_list = faceImportMapper.GetVehicleIdList();
+            try {
+                JsonObject jsonObject = new Gson().fromJson(data, JsonObject.class);
+                JsonObject paramsObject = jsonObject.getAsJsonObject("params");
+                JsonArray eventsArray = paramsObject.getAsJsonArray("events");
+
+                for (JsonElement eventElement : eventsArray) {
+                    JsonObject eventObject = eventElement.getAsJsonObject();
+                    JsonObject dataObject = eventObject.getAsJsonObject("data");
+
+                    String carNum = dataObject.get("plateNo").getAsString().trim();
+                    String eventIndex = dataObject.get("eventIndex").getAsString().trim();
+                    String carMessageApplyIdStr = faceImportMapper.GetCarMessageApplyIdByCarNumber(carNum);
+                    Long carId = (carMessageApplyIdStr == null || carMessageApplyIdStr.isEmpty()) ? 0 : Long.parseLong(carMessageApplyIdStr);
+                    String eventTime = ChangeTime(dataObject.get("time").getAsString());
+
+                    int releaseWayInt = 0;
+                    int releaseReasonInt = 0;
+                    int releaseResultInt = 0;
+                    JsonObject inResultObject = dataObject.getAsJsonObject("inResult");
+                    if (inResultObject != null) {
+                        JsonObject rlsResultObject = inResultObject.getAsJsonObject("rlsResult");
+                        if (rlsResultObject != null && rlsResultObject.has("releaseWay") && rlsResultObject.has("releaseReason") && rlsResultObject.has("releaseResult")) {
+                            releaseWayInt = rlsResultObject.get("releaseWay").getAsInt();
+                            releaseReasonInt = rlsResultObject.get("releaseReason").getAsInt();
+                            releaseResultInt = rlsResultObject.get("releaseResult").getAsInt();
+                        }
+                    }
+
+                    String carAttributeName = dataObject.get("carAttributeName").getAsString().trim();
+                    int vehicleType = dataObject.get("vehicleType").getAsInt();
+                    int category = -1;
+                    switch (carAttributeName){
+                        case "临时车":
+                            category = 1;
+                            break;
+                        case "固定车":
+                            category = 0;
+                            break;
+                    }
+
+                    String facePicUri = "";
+                    JsonObject picUrlObject = dataObject.getAsJsonObject("picUrl");
+                    if (picUrlObject != null && picUrlObject.has("vehiclePicUrl")) {
+                        facePicUri = picUrlObject.get("vehiclePicUrl").getAsString();
+                    }
+
+                    int status = eventObject.get("status").getAsInt();
+                    int statusInt = 0;
+                    switch (status){
+                        case 0:
+                            statusInt = 1;
+                            break;
+                        case 1:
+                            statusInt = 0;
+                            break;
+                    }
+
+                    String phone = faceImportMapper.GetPhoneNumberByPlanNum(carNum);
+                    if (phone == null){
+                        phone = faceImportMapper.GetPhoneNumberByPlanNumView(carNum);
+                        if (phone == null) phone = "";
+                    }
+
+                    String name = faceImportMapper.GetNameByPlanNum(carNum);
+                    if (name == null){
+                        name = faceImportMapper.GetNameByPlanNumView(carNum);
+                        if (name == null) name = "";
+                    }
+
+                    if (vehicle_id_list.contains(eventIndex)) continue;
+
+                    vehicleInsertRecord(use, carId, eventTime, releaseReasonInt, category, ApiUtil.GetRedirectURL(facePicUri), statusInt, carNum, eventIndex, releaseResultInt, releaseWayInt,vehicleType,phone,name);
+                }
+            } catch (Exception e) {
+                log.info(String.valueOf(e));
+            }
+        }
+    }
+
+
+}

+ 137 - 0
src/main/java/com/xjrsoft/module/holiday/controller/HolidayDateController.java

@@ -0,0 +1,137 @@
+package com.xjrsoft.module.holiday.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.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.entity.BaseClass;
+import com.xjrsoft.module.holiday.dto.*;
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import com.alibaba.excel.EasyExcel;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+
+import com.alibaba.excel.support.ExcelTypeEnum;
+import org.springframework.http.ResponseEntity;
+
+import java.io.ByteArrayOutputStream;
+import java.text.ParseException;
+import java.util.ArrayList;
+
+import com.xjrsoft.module.holiday.entity.HolidayDate;
+import com.xjrsoft.module.holiday.service.IHolidayDateService;
+import com.xjrsoft.module.holiday.vo.HolidayDateListVo;
+import com.xjrsoft.module.holiday.vo.HolidayDatePageVo;
+
+import com.xjrsoft.module.holiday.vo.HolidayDateVo;
+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.List;
+
+/**
+ * @title:
+ * @Author fanxp
+ * @Date: 2024-03-26
+ * @Version 1.0
+ */
+@RestController
+@RequestMapping("/holiday" + "/holidayDate")
+@Api(value = "/holiday" + "/holidayDate", tags = "节假日代码")
+@AllArgsConstructor
+public class HolidayDateController {
+
+
+    private final IHolidayDateService holidayDateService;
+
+    @GetMapping(value = "/list")
+    @ApiOperation(value = "列表(不分页)")
+    @SaCheckPermission("holidaydate:detail")
+    public RT<List<HolidayDateListVo>> list(@Valid HolidayDateListDto dto) {
+
+        LambdaQueryWrapper<HolidayDate> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper
+                .eq(HolidayDate::getDeleteStatus,0)
+                .eq(ObjectUtil.isNotNull(dto.getYear()), HolidayDate::getYear, dto.getYear())
+                .eq(ObjectUtil.isNotNull(dto.getMonth()), HolidayDate::getYear, dto.getMonth())
+                .eq(ObjectUtil.isNotNull(dto.getDay()), HolidayDate::getYear, dto.getDay())
+                .orderByAsc(HolidayDate::getDate)
+                .select(HolidayDate.class, x -> VoToColumnUtil.fieldsToColumns(HolidayDateListVo.class).contains(x.getProperty()));
+
+        List<HolidayDate> list = holidayDateService.list(queryWrapper);
+        List<HolidayDateListVo> listVos = BeanUtil.copyToList(list, HolidayDateListVo.class);
+        return RT.ok(listVos);
+    }
+
+    @GetMapping(value = "/page")
+    @ApiOperation(value = "列表(分页)")
+    @SaCheckPermission("holidaydate:detail")
+    public RT<PageOutput<HolidayDatePageVo>> page(@Valid HolidayDatePageDto dto) {
+
+        LambdaQueryWrapper<HolidayDate> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper
+                .eq(HolidayDate::getDeleteStatus,0)
+                .orderByAsc(HolidayDate::getDate)
+                .select(HolidayDate.class, x -> VoToColumnUtil.fieldsToColumns(HolidayDatePageVo.class).contains(x.getProperty()));
+        IPage<HolidayDate> page = holidayDateService.page(ConventPage.getPage(dto), queryWrapper);
+        PageOutput<HolidayDatePageVo> pageOutput = ConventPage.getPageOutput(page, HolidayDatePageVo.class);
+        return RT.ok(pageOutput);
+    }
+
+    @GetMapping(value = "/info")
+    @ApiOperation(value = "根据id查询信息")
+    @SaCheckPermission("holidaydate:detail")
+    public RT<HolidayDateVo> info(@RequestParam Long id) {
+        HolidayDate holidayDate = holidayDateService.getById(id);
+        if (holidayDate == null) {
+            return RT.error("找不到此数据!");
+        }
+        return RT.ok(BeanUtil.toBean(holidayDate, HolidayDateVo.class));
+    }
+
+    @PostMapping(value = "init")
+    @ApiOperation(value = "初始化年节假日数据")
+    @SaCheckPermission("holidaydate:add")
+    public RT<Boolean> initYear(@Valid @RequestBody InitYearDto dto) {
+        boolean isSuccess = holidayDateService.initHoliday(dto.getYear());
+        return RT.ok(isSuccess);
+    }
+
+
+    @PostMapping
+    @ApiOperation(value = "新增")
+    @SaCheckPermission("holidaydate:add")
+    public RT<Boolean> add(@Valid @RequestBody AddHolidayDateDto dto) throws ParseException {
+        boolean isSuccess = holidayDateService.add(dto);
+        return RT.ok(isSuccess);
+    }
+
+    @PutMapping
+    @ApiOperation(value = "修改")
+    @SaCheckPermission("holidaydate:edit")
+    public RT<Boolean> update(@Valid @RequestBody UpdateHolidayDateDto dto) {
+        HolidayDate holidayDate = BeanUtil.toBean(dto, HolidayDate.class);
+        holidayDate.setWay(2);
+        return RT.ok(holidayDateService.updateById(holidayDate));
+    }
+
+    @DeleteMapping
+    @ApiOperation(value = "删除")
+    @SaCheckPermission("holidaydate:delete")
+    public RT<Boolean> delete(@Valid @RequestBody List<Long> ids) {
+        return RT.ok(holidayDateService.delete(ids));
+    }
+}

+ 39 - 0
src/main/java/com/xjrsoft/module/holiday/dto/AddHolidayDateDto.java

@@ -0,0 +1,39 @@
+package com.xjrsoft.module.holiday.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 fanxp
+* @Date: 2024-03-26
+* @Version 1.0
+*/
+@Data
+public class AddHolidayDateDto implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+
+    @ApiModelProperty("开始时间(YYYY-MM-DD)")
+    private String startDate;
+
+    @ApiModelProperty("结束时间(YYYY-MM-DD)")
+    private String endDate;
+
+    /**
+    * 0=普通工作日 1=周末 2=需要补班的工作日 3=法定节假日
+    */
+    @ApiModelProperty("0=普通工作日 1=周末 2=需要补班的工作日 3=法定节假日")
+    private Integer status;
+}

+ 40 - 0
src/main/java/com/xjrsoft/module/holiday/dto/HolidayDateListDto.java

@@ -0,0 +1,40 @@
+package com.xjrsoft.module.holiday.dto;
+
+import com.xjrsoft.common.page.ListInput;
+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 fanxp
+* @Date: 2024-03-26
+* @Version 1.0
+*/
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class HolidayDateListDto extends ListInput {
+
+    /**
+     *
+     */
+    @ApiModelProperty("年")
+    private Integer year;
+    /**
+     *
+     */
+    @ApiModelProperty("月")
+    private Integer month;
+    /**
+     *
+     */
+    @ApiModelProperty("日")
+    private Integer day;
+}

+ 26 - 0
src/main/java/com/xjrsoft/module/holiday/dto/HolidayDatePageDto.java

@@ -0,0 +1,26 @@
+package com.xjrsoft.module.holiday.dto;
+
+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 fanxp
+* @Date: 2024-03-26
+* @Version 1.0
+*/
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class HolidayDatePageDto extends PageInput {
+
+
+}

+ 13 - 0
src/main/java/com/xjrsoft/module/holiday/dto/InitYearDto.java

@@ -0,0 +1,13 @@
+package com.xjrsoft.module.holiday.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class InitYearDto implements Serializable {
+
+    @ApiModelProperty("年")
+    public Integer year;
+}

+ 32 - 0
src/main/java/com/xjrsoft/module/holiday/dto/UpdateHolidayDateDto.java

@@ -0,0 +1,32 @@
+package com.xjrsoft.module.holiday.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 fanxp
+* @Date: 2024-03-26
+* @Version 1.0
+*/
+@Data
+public class UpdateHolidayDateDto extends AddHolidayDateDto {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+    * 主键编号
+    */
+    @ApiModelProperty("主键编号")
+    private Long id;
+}

+ 78 - 0
src/main/java/com/xjrsoft/module/holiday/entity/HolidayDate.java

@@ -0,0 +1,78 @@
+package com.xjrsoft.module.holiday.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.Builder;
+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 fanxp
+* @Date: 2024-03-26
+* @Version 1.0
+*/
+@Data
+@Builder
+@TableName("holiday_date")
+@ApiModel(value = "holiday_date", description = "")
+public class HolidayDate implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+    * 主键编号
+    */
+    @ApiModelProperty("主键编号")
+    @TableId
+    private Long id;
+    /**
+    * 日期yyyy-MM-dd
+    */
+    @ApiModelProperty("日期yyyy-MM-dd")
+    private String date;
+    /**
+    * 
+    */
+    @ApiModelProperty("")
+    private Integer year;
+    /**
+    * 
+    */
+    @ApiModelProperty("")
+    private Integer month;
+    /**
+    * 
+    */
+    @ApiModelProperty("")
+    private Integer day;
+    /**
+    * 0=普通工作日 1=周末 2=需要补班的工作日 3=法定节假日
+    */
+    @ApiModelProperty("0=普通工作日 1=周末 2=需要补班的工作日 3=法定节假日")
+    private Integer status;
+    /**
+    * 方式 1=系统数据 2=用户数据
+    */
+    @ApiModelProperty("方式 1=系统数据 2=用户数据")
+    private Integer way;
+    /**
+    * 删除状态 0=正常 1=删除
+    */
+    @ApiModelProperty("删除状态 0=正常 1=删除")
+    private Integer deleteStatus;
+
+
+}

+ 17 - 0
src/main/java/com/xjrsoft/module/holiday/mapper/HolidayDateMapper.java

@@ -0,0 +1,17 @@
+package com.xjrsoft.module.holiday.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.github.yulichang.base.MPJBaseMapper;
+import com.xjrsoft.module.holiday.entity.HolidayDate;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+* @title: 
+* @Author fanxp
+* @Date: 2024-03-26
+* @Version 1.0
+*/
+@Mapper
+public interface HolidayDateMapper extends MPJBaseMapper<HolidayDate> {
+
+}

+ 28 - 0
src/main/java/com/xjrsoft/module/holiday/service/IHolidayDateService.java

@@ -0,0 +1,28 @@
+package com.xjrsoft.module.holiday.service;
+
+import com.github.yulichang.base.MPJBaseService;
+import com.xjrsoft.module.holiday.dto.AddHolidayDateDto;
+import com.xjrsoft.module.holiday.entity.HolidayDate;
+
+import java.text.ParseException;
+import java.util.List;
+
+/**
+* @title: 
+* @Author fanxp
+* @Date: 2024-03-26
+* @Version 1.0
+*/
+
+public interface IHolidayDateService extends MPJBaseService<HolidayDate> {
+    Boolean initHoliday(int year);
+
+    Boolean delete(List<Long> ids);
+
+    Boolean add(AddHolidayDateDto dto) throws ParseException;
+
+    /**
+     * 当前时间是否休息
+     */
+    Boolean currentIsRest();
+}

+ 179 - 0
src/main/java/com/xjrsoft/module/holiday/service/impl/HolidayDateServiceImpl.java

@@ -0,0 +1,179 @@
+package com.xjrsoft.module.holiday.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.github.yulichang.base.MPJBaseServiceImpl;
+import com.xjrsoft.common.exception.MyException;
+import com.xjrsoft.common.utils.DateUtils;
+import com.xjrsoft.common.utils.HolidayUtil;
+import com.xjrsoft.module.holiday.dto.AddHolidayDateDto;
+import com.xjrsoft.module.holiday.entity.HolidayDate;
+import com.xjrsoft.module.holiday.mapper.HolidayDateMapper;
+import com.xjrsoft.module.holiday.service.IHolidayDateService;
+import com.xjrsoft.module.holiday.vo.AlmanacVo;
+import lombok.AllArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * @title:
+ * @Author fanxp
+ * @Date: 2024-03-26
+ * @Version 1.0
+ */
+@Service
+@AllArgsConstructor
+public class HolidayDateServiceImpl extends MPJBaseServiceImpl<HolidayDateMapper, HolidayDate> implements IHolidayDateService {
+
+    private final HolidayDateMapper holidayDateMapper;
+
+    /**
+     * 当前时间是否休息
+     */
+    public Boolean currentIsRest() {
+        LocalDateTime now = LocalDateTime.now();
+        String day = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+        Long count = holidayDateMapper.selectCount(Wrappers.<HolidayDate>query().lambda()
+                .eq(HolidayDate::getDate, day)
+                .eq(HolidayDate::getStatus,3)
+        );
+        return count > 0;
+    }
+
+    /**
+     * 添加数据
+     *
+     * @param dto
+     * @return
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean add(AddHolidayDateDto dto) throws ParseException {
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+        Date start = sdf.parse(dto.getStartDate());
+        Date end = sdf.parse(dto.getEndDate());
+
+        if (start.compareTo(end) > 0) {
+            throw new MyException("开始时间不能大于结束时间!");
+        }
+
+        while (start.compareTo(end) <= 0) {
+            Calendar calendar = Calendar.getInstance();
+            calendar.setTime(start);
+
+            HolidayDate param = HolidayDate.builder()
+                    .date(sdf.format(start))
+                    .way(2)
+                    .year(calendar.get(Calendar.YEAR))
+                    .month(calendar.get(Calendar.MONTH) + 1)
+                    .day(calendar.get(Calendar.DATE))
+                    .status(dto.getStatus())
+                    .build();
+            holidayDateMapper.insert(param);
+            start = DateUtils.addDateDays(start, 1);
+        }
+        return true;
+    }
+
+    /**
+     * 删除数据
+     *
+     * @param ids
+     * @return
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean delete(List<Long> ids) {
+        List<HolidayDate> holidayDates = holidayDateMapper.selectBatchIds(ids);
+        for (HolidayDate h : holidayDates) {
+            // 用户数据直接删除,系统数据添加标识
+            if (h.getWay() == 1) {
+                h.setDeleteStatus(1);
+                holidayDateMapper.updateById(h);
+            } else {
+                holidayDateMapper.deleteById(h.getId());
+            }
+        }
+        return true;
+    }
+
+    /**
+     * 初始化节假日
+     *
+     * @param year
+     * @return
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public Boolean initHoliday(int year) {
+        List<HolidayDate> allList = new ArrayList<>();
+        for (int month = 1; month < 13; month++) {
+            List<HolidayDate> monthList = getYearMonthHoliday(year, month);
+            allList.addAll(monthList);
+        }
+//        List<HolidayDate> monthList = getYearMonthHoliday(year - 1, 12);
+//        allList.addAll(monthList);
+
+        Map<String, HolidayDate> mData = allList.stream().collect(Collectors.toMap(HolidayDate::getDate, item -> item));
+        // 获取用户数据
+        List<HolidayDate> userDates = holidayDateMapper.selectList(Wrappers.<HolidayDate>query().lambda().eq(HolidayDate::getYear, year).eq(HolidayDate::getWay, 2));
+        for (HolidayDate uh : userDates) {
+            mData.keySet().removeIf(key -> Objects.equals(key, uh.getDate()));
+        }
+        // 清除系统数据
+        holidayDateMapper.delete(Wrappers.<HolidayDate>query().lambda().eq(HolidayDate::getYear, year).eq(HolidayDate::getWay, 1));
+        // 保存系统数据
+        for (Map.Entry<String, HolidayDate> entry : mData.entrySet()) {
+            holidayDateMapper.insert(entry.getValue());
+        }
+        return true;
+    }
+
+    /**
+     * Init month list.
+     * 按月爬取节假日
+     *
+     * @param year  the year
+     * @param month the month
+     * @return the list
+     */
+    public static List<HolidayDate> getYearMonthHoliday(int year, int month) {
+        List<HolidayDate> holidayDateList = new ArrayList<>();
+        try {
+            String result = HolidayUtil.getMonth(year + "", month + "");
+            JSONObject json = JSON.parseObject(result);
+            System.out.println(result);
+            JSONArray data = json.getJSONArray("data");
+            JSONObject dataObj = JSON.parseObject(data.get(0).toString());
+            List<AlmanacVo> almanacs = JSONArray.parseArray(dataObj.getString("almanac"), AlmanacVo.class);
+            for (AlmanacVo almanac : almanacs) {
+                if (almanac.getMonth().equals(String.valueOf(month)) && almanac.getStatus() != null) {
+                    HolidayDate date = HolidayDate.builder()
+                            .year(year).month(month).day(Integer.parseInt(almanac.getDay()))
+                            .date(DateUtils.format(new Date(year - 1900, month - 1, Integer.parseInt(almanac.getDay())), "yyyy-MM-dd"))
+                            .build();
+                    String status = almanac.getStatus();
+                    if (status.equals("1")) {
+                        date.setStatus(3);
+                    } else if (status.equals("2")) {
+                        date.setStatus(2);
+                    }
+                    holidayDateList.add(date);
+                }
+            }
+        } catch (ClassCastException classCastException) {
+            throw new MyException("可能是当前月份(" + month + "月)没有节日");
+        } catch (Exception e) {
+            throw new MyException(e.getMessage());
+        }
+        return holidayDateList;
+    }
+
+
+}

+ 27 - 0
src/main/java/com/xjrsoft/module/holiday/vo/AlmanacVo.java

@@ -0,0 +1,27 @@
+package com.xjrsoft.module.holiday.vo;
+
+import lombok.Data;
+
+@Data
+public class AlmanacVo {
+    String animal;
+    String avoid;
+    String cnDay;
+    String day;
+    String gzDate;
+    String gzMonth;
+    String gzYear;
+    String isBigMonth;
+    String lDate;
+    String lMonth;
+    String lunarDate;
+    String lunarMonth;
+    String lunarYear;
+    String month;
+    String oDate;
+    String status;
+    String suit;
+    String term;
+    String type;
+    String year;
+}

+ 83 - 0
src/main/java/com/xjrsoft/module/holiday/vo/HolidayDateListVo.java

@@ -0,0 +1,83 @@
+package com.xjrsoft.module.holiday.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 fanxp
+* @Date: 2024-03-26
+* @Version 1.0
+*/
+@Data
+public class HolidayDateListVo {
+
+    /**
+    * 主键编号
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("主键编号")
+    @ApiModelProperty("主键编号")
+    private String id;
+    /**
+    * 日期yyyy-MM-dd
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("日期yyyy-MM-dd")
+    @ApiModelProperty("日期yyyy-MM-dd")
+    private String date;
+    /**
+    * 
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("")
+    @ApiModelProperty("")
+    private Integer year;
+    /**
+    * 
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("")
+    @ApiModelProperty("")
+    private Integer month;
+    /**
+    * 
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("")
+    @ApiModelProperty("")
+    private Integer day;
+    /**
+    * 0=普通工作日 1=周末 2=需要补班的工作日 3=法定节假日
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("0=普通工作日 1=周末 2=需要补班的工作日 3=法定节假日")
+    @ApiModelProperty("0=普通工作日 1=周末 2=需要补班的工作日 3=法定节假日")
+    private Integer status;
+    /**
+    * 方式 1=系统数据 2=用户数据
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("方式 1=系统数据 2=用户数据")
+    @ApiModelProperty("方式 1=系统数据 2=用户数据")
+    private Integer way;
+    /**
+    * 删除状态 0=正常 1=删除
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("删除状态 0=正常 1=删除")
+    @ApiModelProperty("删除状态 0=正常 1=删除")
+    private Integer deleteStatus;
+
+}

+ 83 - 0
src/main/java/com/xjrsoft/module/holiday/vo/HolidayDatePageVo.java

@@ -0,0 +1,83 @@
+package com.xjrsoft.module.holiday.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 fanxp
+* @Date: 2024-03-26
+* @Version 1.0
+*/
+@Data
+public class HolidayDatePageVo {
+
+    /**
+    * 主键编号
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("主键编号")
+    @ApiModelProperty("主键编号")
+    private String id;
+    /**
+    * 日期yyyy-MM-dd
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("日期yyyy-MM-dd")
+    @ApiModelProperty("日期yyyy-MM-dd")
+    private String date;
+    /**
+    * 
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("")
+    @ApiModelProperty("")
+    private Integer year;
+    /**
+    * 
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("")
+    @ApiModelProperty("")
+    private Integer month;
+    /**
+    * 
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("")
+    @ApiModelProperty("")
+    private Integer day;
+    /**
+    * 0=普通工作日 1=周末 2=需要补班的工作日 3=法定节假日
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("0=普通工作日 1=周末 2=需要补班的工作日 3=法定节假日")
+    @ApiModelProperty("0=普通工作日 1=周末 2=需要补班的工作日 3=法定节假日")
+    private Integer status;
+    /**
+    * 方式 1=系统数据 2=用户数据
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("方式 1=系统数据 2=用户数据")
+    @ApiModelProperty("方式 1=系统数据 2=用户数据")
+    private Integer way;
+    /**
+    * 删除状态 0=正常 1=删除
+    */
+    @ContentStyle(dataFormat = 49)
+    @ExcelProperty("删除状态 0=正常 1=删除")
+    @ApiModelProperty("删除状态 0=正常 1=删除")
+    private Integer deleteStatus;
+
+}

+ 64 - 0
src/main/java/com/xjrsoft/module/holiday/vo/HolidayDateVo.java

@@ -0,0 +1,64 @@
+package com.xjrsoft.module.holiday.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 fanxp
+* @Date: 2024-03-26
+* @Version 1.0
+*/
+@Data
+public class HolidayDateVo {
+
+    /**
+    * 主键编号
+    */
+    @ApiModelProperty("主键编号")
+    private Long id;
+    /**
+    * 日期yyyy-MM-dd
+    */
+    @ApiModelProperty("日期yyyy-MM-dd")
+    private String date;
+    /**
+    * 
+    */
+    @ApiModelProperty("")
+    private Integer year;
+    /**
+    * 
+    */
+    @ApiModelProperty("")
+    private Integer month;
+    /**
+    * 
+    */
+    @ApiModelProperty("")
+    private Integer day;
+    /**
+    * 0=普通工作日 1=周末 2=需要补班的工作日 3=法定节假日
+    */
+    @ApiModelProperty("0=普通工作日 1=周末 2=需要补班的工作日 3=法定节假日")
+    private Integer status;
+    /**
+    * 方式 1=系统数据 2=用户数据
+    */
+    @ApiModelProperty("方式 1=系统数据 2=用户数据")
+    private Integer way;
+    /**
+    * 删除状态 0=正常 1=删除
+    */
+    @ApiModelProperty("删除状态 0=正常 1=删除")
+    private Integer deleteStatus;
+
+
+
+}

+ 45 - 0
src/main/java/com/xjrsoft/module/job/AttendanceMessageTask.java

@@ -0,0 +1,45 @@
+package com.xjrsoft.module.job;
+
+import cn.hutool.extra.spring.SpringUtil;
+import com.xjrsoft.common.constant.GlobalConstant;
+import com.xjrsoft.common.utils.DatasourceUtil;
+import com.xjrsoft.module.attendance.entity.AttendanceRuleDetails;
+import com.xjrsoft.module.attendance.service.IAttendanceMessageSetService;
+import com.xjrsoft.module.attendance.service.IAttendanceRuleCategoryService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import javax.sql.DataSource;
+import java.util.List;
+
+/**
+ * 考勤消息通知
+ * @author dzx
+ * @date 2024年5月21日
+ */
+@Component
+@Slf4j
+public class AttendanceMessageTask {
+    @Autowired
+    private IAttendanceMessageSetService messageSetService;
+
+    @Autowired
+    private IAttendanceRuleCategoryService ruleCategoryService;
+    @Scheduled(cron = "0 */15 * * * ?")
+    public void RefreshConnectionPool() {
+        String active = SpringUtil.getActiveProfile();
+        if(!"prod".equals(active)){
+            log.info("非正式环境,无法执行数据推送");
+            return;
+        }
+
+        List<AttendanceRuleDetails> ruleDetails = ruleCategoryService.getTodayRules();
+
+        try {
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+        }
+    }
+}

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

@@ -2,12 +2,14 @@ package com.xjrsoft.module.job;
 
 import cn.hutool.db.Db;
 import cn.hutool.extra.spring.SpringUtil;
-import com.google.gson.JsonArray;
 import com.xjrsoft.common.constant.GlobalConstant;
 import com.xjrsoft.common.utils.DatasourceUtil;
+import com.xjrsoft.module.hikvision.entity.HikvisionData;
+import com.xjrsoft.module.hikvision.util.DataUtil;
 import com.xjrsoft.module.schedule.entity.JianyueData;
-import com.xjrsoft.module.schedule.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;
 import org.springframework.stereotype.Component;
 
@@ -25,7 +27,8 @@ import java.util.Set;
 @Component
 @Slf4j
 public class HikvisionBaseDataTask {
-
+    @Autowired
+    private FaceImportMapper faceImportMapper;
 
     @Scheduled(cron = "0 */15 * * * ?")
     public void RefreshConnectionPool() {
@@ -45,48 +48,45 @@ public class HikvisionBaseDataTask {
                 tables.add(jianyueData.getTableName());
             }
             sql = "SELECT * FROM hikvision_data WHERE 0 = 0";
-            List<JianyueData> list = use.query(sql, JianyueData.class);
-            Map<String, Map<Long, String>> dataMap = new HashMap<>();
+            List<HikvisionData> list = use.query(sql, HikvisionData.class);
+            Map<String, Map<String, String>> dataMap = new HashMap<>();
             for (String table : tables) {
-                Map<Long, String> tableData = new HashMap<>();
-                for (JianyueData jianyueData : list) {
-                    if(!table.equals(jianyueData.getTableName())){
+                Map<String, String> tableData = new HashMap<>();
+                for (HikvisionData hikvisiondata : list) {
+                    if(!table.equals(hikvisiondata.getTableName())){
                         continue;
                     }
-                    tableData.put(jianyueData.getSourceId(), jianyueData.getJianyueId());
+                    tableData.put(hikvisiondata.getSourceId(), hikvisiondata.getHikvisionId());
                 }
                 dataMap.put(table, tableData);
             }
             DataUtil dataUtil = new DataUtil();
-            //查询校区
-            JsonArray schoolDistrictData = dataUtil.getSchoolDistrictData();
+            //查询根机构
+            //JsonArray schoolDistrictData = dataUtil.getSchoolDistrictData();
             //推送组织机构
             String tableName = "xjr_department";
-            Map<Long, String> department = dataUtil.insertGrade(use, tableName, schoolDistrictData.get(0).getAsString(), dataMap.get(tableName));
+            Map<String, String> department = dataUtil.insertDepartment(use, tableName, dataMap.get(tableName));
             if(department.isEmpty() && dataMap.get(tableName) != null){
                 department = dataMap.get(tableName);
             }
 
-            //推送学期
-            tableName = "base_semester";
-            dataUtil.insertSemester(use, tableName, dataMap.get(tableName));
-            //推送标签
-            tableName = "base_label";
-            Map<Long, String> tagMap = dataUtil.insertCourseTag(use, tableName, dataMap.get(tableName));
-            if(tagMap.isEmpty() && dataMap.get(tableName) != null){
-                tagMap = dataMap.get(tableName);
-            }
-
-
             //推送教职工
             tableName = "base_teacher";
-            Map<Long, String> teacherMap = dataUtil.insertTeacher(use, tableName, dataMap.get(tableName));
-            if(teacherMap.isEmpty() && dataMap.get(tableName) != null){
-                teacherMap = dataMap.get(tableName);
-            }
-            //推送学生
-//            tableName = "base_student";
-//            dataUtil.insertStudent(use, tableName, grade, dataMap.get(tableName));
+            dataUtil.insertTeacher(use, tableName, dataMap.get(tableName), department);
+
+            //推送车辆
+            String carTableName = "car_message_apply";
+            Map<String, String> baseCar = dataMap.get(carTableName);
+            dataUtil.insertCar(use, carTableName, baseCar, faceImportMapper);
+
+            tableName = "base_class";
+            Map<String, String> baseClass = dataMap.get(tableName);
+            Map<String, String> classes = dataUtil.insertClass(use, tableName, baseClass);
+
+
+            tableName = "base_student";
+            Map<String, String> baseStudent = dataMap.get(tableName);
+            Map<String, String> student = dataUtil.insertStudentOne(use, tableName, baseStudent);
 
             log.info("数据推送完成");
         } catch (Exception e) {

+ 37 - 0
src/main/java/com/xjrsoft/module/job/HikvisionLeaveTask.java

@@ -0,0 +1,37 @@
+package com.xjrsoft.module.job;
+
+import cn.hutool.db.Db;
+import cn.hutool.extra.spring.SpringUtil;
+import com.xjrsoft.common.constant.GlobalConstant;
+import com.xjrsoft.common.utils.DatasourceUtil;
+import com.xjrsoft.module.hikvision.entity.HikvisionData;
+import com.xjrsoft.module.hikvision.util.DataUtil;
+import com.xjrsoft.module.schedule.entity.JianyueData;
+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;
+import org.springframework.stereotype.Component;
+
+import javax.sql.DataSource;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * 用于请假后删除权限
+ * @author dzx
+ * @date 2024年5月21日
+ */
+@Component
+@Slf4j
+public class HikvisionLeaveTask {
+    @Autowired
+    private FaceImportMapper faceImportMapper;
+
+    @Scheduled(cron = "0 */15 * * * ?")
+    public void RefreshConnectionPool() {
+    }
+}

+ 32 - 0
src/main/java/com/xjrsoft/module/job/HolidayTask.java

@@ -0,0 +1,32 @@
+package com.xjrsoft.module.job;
+
+import com.xjrsoft.common.utils.DateUtils;
+import com.xjrsoft.module.holiday.service.IHolidayDateService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import java.util.Calendar;
+import java.util.Date;
+
+@Component
+@Slf4j
+public class HolidayTask {
+
+    @Autowired
+    private IHolidayDateService holidayDateService;
+
+    /**
+     * 定时拉取节假日数据
+     */
+    @Scheduled(cron = "0 0 1 * * ?")
+    public void RefreshHoliday() {
+        System.out.printf("定时拉取节假日数据:%s", DateUtils.format(new Date(), DateUtils.DATE_TIME_PATTERN));
+        Date date = new Date();
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(date);
+
+        holidayDateService.initHoliday(calendar.get(Calendar.YEAR));
+    }
+}

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

@@ -0,0 +1,51 @@
+package com.xjrsoft.module.job;
+
+import cn.hutool.db.Db;
+import cn.hutool.extra.spring.SpringUtil;
+import com.xjrsoft.common.constant.GlobalConstant;
+import com.xjrsoft.common.utils.DatasourceUtil;
+import com.xjrsoft.module.hikvision.util.Out_In_RecordUtil;
+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;
+import org.springframework.stereotype.Component;
+
+import javax.sql.DataSource;
+
+/**
+ * @author dzx
+ * @date 2024/5/8
+ */
+@Component
+@Slf4j
+public class InsertOutInRecordTask {
+    @Autowired
+    private FaceImportMapper faceImportMapper;
+
+    Out_In_RecordUtil out_in_recordUtil = new Out_In_RecordUtil();
+
+    @Scheduled(cron = "0 */15 * * * ?")
+    public void RefreshConnectionPool() {
+        String active = SpringUtil.getActiveProfile();
+        if(!"prod".equals(active)){
+            log.info("非正式环境,无法执行数据推送");
+            return;
+        }
+        log.info("开始拉取海康威视基础数据");
+        DataSource datasource = DatasourceUtil.getDataSource(GlobalConstant.DEFAULT_DATASOURCE_KEY);
+        try {
+            Db use = Db.use(datasource);
+
+            //教师&学生拉取数据
+            out_in_recordUtil.GetTeacherAndStudentRecords(use, faceImportMapper);
+            //拉取车辆数据
+            out_in_recordUtil.GetVehicleRecord(use, faceImportMapper);
+
+            log.info("数据拉取完成");
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+        }
+    }
+}
+

+ 37 - 0
src/main/java/com/xjrsoft/module/liteflow/node/CarMessageApplyNode.java

@@ -0,0 +1,37 @@
+package com.xjrsoft.module.liteflow.node;
+
+import cn.hutool.core.convert.Convert;
+import com.xjrsoft.module.personnel.entity.CarMessageApply;
+import com.xjrsoft.module.personnel.service.ICarMessageApplyService;
+import com.xjrsoft.module.student.service.IBaseStudentAssessmentClassRelationService;
+import com.yomahub.liteflow.core.NodeComponent;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * 车辆申请,通过后修改状态
+ */
+@Component("car_message_apply_node")
+public class CarMessageApplyNode extends NodeComponent {
+
+    @Autowired
+    private ICarMessageApplyService carMessageApplyService;
+
+    @Override
+    public void process() throws Exception {
+        // 获取表单中数据编号
+        Map<String, Object> params = this.getFirstContextBean();
+        Object value = util.getFormDatKey(params,"id");
+        Long formId = Convert.toLong(value);
+        if (formId != null) {
+            // 数据处理
+            CarMessageApply carMessageApply = carMessageApplyService.getById(formId);
+            carMessageApply.setStatus(1);
+            carMessageApply.setExamStatus(1);
+
+            carMessageApplyService.updateById(carMessageApply);
+        }
+    }
+}

+ 49 - 0
src/main/java/com/xjrsoft/module/liteflow/node/ImportStudentFaceNode.java

@@ -0,0 +1,49 @@
+package com.xjrsoft.module.liteflow.node;
+
+import cn.hutool.core.convert.Convert;
+import com.xjrsoft.module.hikvision.mapper.HikvisionDataMapper;
+import com.xjrsoft.module.hikvision.util.FaceImportUtil;
+import com.xjrsoft.module.personnel.entity.StundentFaceProcess;
+import com.xjrsoft.module.personnel.service.IStundentFaceProcessService;
+import com.xjrsoft.module.teacher.mapper.FaceImportMapper;
+import com.yomahub.liteflow.core.NodeComponent;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * 导出学生照片到海康平台
+ */
+@Component("import_student_face_node")
+public class ImportStudentFaceNode extends NodeComponent {
+    @Autowired
+    private IStundentFaceProcessService stundentFaceProcessService;
+
+    @Autowired
+    private HikvisionDataMapper hikvisionDataMapper;
+
+    @Autowired
+    private FaceImportMapper faceImportMapper;
+
+    @Override
+    public void process() throws Exception {
+        // 获取表单中数据编号
+        Map<String, Object> params = this.getFirstContextBean();
+        Object value = util.getFormDatKey(params,"id");
+        Long formId = Convert.toLong(value);
+        if (formId != null) {
+            String fileUrl = faceImportMapper.GetStudentHikvisionImgById(formId);
+            // 数据处理
+            StundentFaceProcess dataObj = stundentFaceProcessService.getById(formId);
+            dataObj.setStatus(1);
+            dataObj.setExamStatus(1);
+            String result = FaceImportUtil.ImportStudentFace(hikvisionDataMapper.getStudentHikvisionId(dataObj.getUserId()), fileUrl);
+            dataObj.setHikvisionResult(result);
+            stundentFaceProcessService.updateById(dataObj);
+
+
+        }
+    }
+}
+

+ 49 - 0
src/main/java/com/xjrsoft/module/liteflow/node/ImportTeacherFaceNode.java

@@ -0,0 +1,49 @@
+package com.xjrsoft.module.liteflow.node;
+
+import cn.hutool.core.convert.Convert;
+import com.xjrsoft.module.hikvision.mapper.HikvisionDataMapper;
+import com.xjrsoft.module.personnel.entity.TeacherFaceProcess;
+import com.xjrsoft.module.personnel.service.ITeacherFaceProcessService;
+import com.xjrsoft.module.teacher.mapper.FaceImportMapper;
+import com.yomahub.liteflow.core.NodeComponent;
+import com.xjrsoft.module.hikvision.util.FaceImportUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * 导出老师照片到海康平台
+ */
+@Component("import_teacher_face_node")
+public class ImportTeacherFaceNode extends NodeComponent {
+
+    @Autowired
+    private ITeacherFaceProcessService teacherFaceProcessService;
+
+    @Autowired
+    private HikvisionDataMapper hikvisionDataMapper;
+
+    @Autowired
+    private FaceImportMapper faceImportMapper;
+
+    @Override
+    public void process() throws Exception {
+        // 获取表单中数据编号
+        Map<String, Object> params = this.getFirstContextBean();
+        Object value = util.getFormDatKey(params,"id");
+        Long formId = Convert.toLong(value);
+        if (formId != null) {
+
+            String fileUrl = faceImportMapper.GetTeacherHikvisionImgById(formId);
+
+            // 数据处理
+            TeacherFaceProcess dataObj = teacherFaceProcessService.getById(formId);
+            dataObj.setStatus(1);
+            dataObj.setExamStatus(1);
+            String reslut = FaceImportUtil.ImportTeacherFace(hikvisionDataMapper.getTeacherHikvisionId(dataObj.getUserId()), fileUrl);
+            dataObj.setHikvisionResult(reslut);
+            teacherFaceProcessService.updateById(dataObj);
+        }
+    }
+}

+ 39 - 0
src/main/java/com/xjrsoft/module/liteflow/node/ReservationSchoolNode.java

@@ -0,0 +1,39 @@
+package com.xjrsoft.module.liteflow.node;
+
+import cn.hutool.core.convert.Convert;
+import com.xjrsoft.module.personnel.entity.CarMessageApply;
+import com.xjrsoft.module.personnel.entity.ReservationSchool;
+import com.xjrsoft.module.personnel.service.ICarMessageApplyService;
+import com.xjrsoft.module.personnel.service.IReservationSchoolService;
+import com.yomahub.liteflow.core.NodeComponent;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * 预约进校-进校人员,通过后修改状态
+ */
+@Component("reservation_school_node")
+public class ReservationSchoolNode extends NodeComponent {
+
+    @Autowired
+    private IReservationSchoolService reservationSchoolService;
+
+    @Override
+    public void process() throws Exception {
+        // 获取表单中数据编号
+        Map<String, Object> params = this.getFirstContextBean();
+        Object value = util.getFormDatKey(params,"id");
+        Long formId = Convert.toLong(value);
+        if (formId != null) {
+            // 数据处理
+            ReservationSchool dataObj = reservationSchoolService.getByIdDeep(formId);
+            dataObj.setStatus(1);
+            dataObj.setExamStatus(1);
+            reservationSchoolService.updateById(dataObj);
+
+            reservationSchoolService.registration(dataObj);
+        }
+    }
+}

+ 37 - 0
src/main/java/com/xjrsoft/module/liteflow/node/StudentAdmissionApplicationNode.java

@@ -0,0 +1,37 @@
+package com.xjrsoft.module.liteflow.node;
+
+import cn.hutool.core.convert.Convert;
+import com.xjrsoft.module.personnel.entity.ReservationSchool;
+import com.xjrsoft.module.personnel.service.IReservationSchoolService;
+import com.xjrsoft.module.student.entity.StudentAdmissionApplication;
+import com.xjrsoft.module.student.service.IStudentAdmissionApplicationService;
+import com.yomahub.liteflow.core.NodeComponent;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * 预约进校-进校人员,通过后修改状态
+ */
+@Component("student_admission_application_node")
+public class StudentAdmissionApplicationNode extends NodeComponent {
+
+    @Autowired
+    private IStudentAdmissionApplicationService studentAdmissionApplicationService;
+
+    @Override
+    public void process() throws Exception {
+        // 获取表单中数据编号
+        Map<String, Object> params = this.getFirstContextBean();
+        Object value = util.getFormDatKey(params,"id");
+        Long formId = Convert.toLong(value);
+        if (formId != null) {
+            // 数据处理
+            StudentAdmissionApplication dataObj = studentAdmissionApplicationService.getById(formId);
+            dataObj.setStatus(1);
+
+            studentAdmissionApplicationService.updateById(dataObj);
+        }
+    }
+}

Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff