AttendanceMessageTask.java 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. package com.xjrsoft.module.job;
  2. import cn.hutool.core.util.IdUtil;
  3. import cn.hutool.core.util.StrUtil;
  4. import cn.hutool.db.Entity;
  5. import cn.hutool.extra.spring.SpringUtil;
  6. import com.alibaba.fastjson.JSONObject;
  7. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  8. import com.github.yulichang.wrapper.MPJLambdaWrapper;
  9. import com.xjrsoft.common.mybatis.SqlRunnerAdapter;
  10. import com.xjrsoft.common.utils.VoToColumnUtil;
  11. import com.xjrsoft.common.utils.WeChatUtil;
  12. import com.xjrsoft.config.CommonPropertiesConfig;
  13. import com.xjrsoft.module.attendance.entity.AttendanceMessageSet;
  14. import com.xjrsoft.module.attendance.entity.AttendanceMessageUserRelation;
  15. import com.xjrsoft.module.attendance.entity.AttendanceRuleDetails;
  16. import com.xjrsoft.module.attendance.service.IAttendanceMessageSetService;
  17. import com.xjrsoft.module.attendance.service.IAttendanceRuleCategoryService;
  18. import com.xjrsoft.module.concat.service.IXjrUserService;
  19. import com.xjrsoft.module.holiday.entity.HolidayDate;
  20. import com.xjrsoft.module.holiday.service.IHolidayDateService;
  21. import com.xjrsoft.module.organization.dto.WeChatSendMessageDto;
  22. import com.xjrsoft.module.organization.entity.UserRoleRelation;
  23. import com.xjrsoft.module.organization.service.IWeChatService;
  24. import com.xjrsoft.module.outint.entity.StudentOutInRecord;
  25. import com.xjrsoft.module.outint.entity.TeacherOutInRecord;
  26. import com.xjrsoft.module.outint.service.IStudentOutInRecordService;
  27. import com.xjrsoft.module.outint.service.ITeacherOutInRecordService;
  28. import com.xjrsoft.module.student.entity.BaseStudent;
  29. import com.xjrsoft.module.teacher.entity.BaseTeacher;
  30. import com.xjrsoft.module.teacher.entity.XjrUser;
  31. import lombok.extern.slf4j.Slf4j;
  32. import org.springframework.beans.factory.annotation.Autowired;
  33. import org.springframework.scheduling.annotation.Async;
  34. import org.springframework.scheduling.annotation.Scheduled;
  35. import org.springframework.stereotype.Component;
  36. import java.text.SimpleDateFormat;
  37. import java.time.LocalDateTime;
  38. import java.time.format.DateTimeFormatter;
  39. import java.time.temporal.ChronoUnit;
  40. import java.util.*;
  41. import java.util.stream.Collectors;
  42. /**
  43. * 考勤消息通知,给领导推送每个时段的考勤情况
  44. *
  45. * @author dzx
  46. * @date 2024年6月7日
  47. */
  48. @Component
  49. @Slf4j
  50. public class AttendanceMessageTask {
  51. @Autowired
  52. private IAttendanceMessageSetService messageSetService;
  53. @Autowired
  54. private IAttendanceRuleCategoryService ruleCategoryService;
  55. @Autowired
  56. private IHolidayDateService holidayDateService;
  57. @Autowired
  58. private IXjrUserService userService;
  59. @Autowired
  60. private IStudentOutInRecordService studentOutInRecordService;
  61. @Autowired
  62. private ITeacherOutInRecordService teachertOutInRecordService;
  63. @Autowired
  64. private IWeChatService weChatService;
  65. @Autowired
  66. private CommonPropertiesConfig commonPropertiesConfig;
  67. @Autowired
  68. private WeChatUtil weChatUtil;
  69. @Async
  70. @Scheduled(cron = "0 */1 * * * ?")
  71. public void RefreshConnectionPool() {
  72. String active = SpringUtil.getActiveProfile();
  73. if (!"prod".equals(active)) {
  74. log.info("非正式环境,无法执行数据推送");
  75. return;
  76. }
  77. doExecute();
  78. }
  79. public void doExecute() {
  80. LocalDateTime now = LocalDateTime.now();
  81. HolidayDate holidayDate = holidayDateService.getOne(
  82. new QueryWrapper<HolidayDate>().lambda()
  83. .eq(HolidayDate::getDate, now.toLocalDate())
  84. );
  85. //查询到了数据,且当天不是“普通工作日”或“需要补班的工作日”
  86. if (holidayDate != null && holidayDate.getWay() != null && holidayDate.getWay() != 0 && holidayDate.getWay() != 2) {
  87. log.info("非工作日,不需要提醒");
  88. return;
  89. }
  90. //未查询到数据
  91. String dayOfWeek = now.getDayOfWeek().name();
  92. if (holidayDate == null || "SUNDAY".equals(dayOfWeek) || "SATURDAY".equals(dayOfWeek)) {
  93. log.info("非工作日,不需要提醒");
  94. // return;
  95. }
  96. //查询今天的考勤规则
  97. List<AttendanceRuleDetails> ruleDetails = ruleCategoryService.getTodayRules();
  98. List<AttendanceMessageSet> list = messageSetService.list();
  99. //判断是上午还是下午
  100. Integer timePeriod = null;
  101. String timePeriodStr = null;
  102. if (now.getHour() <= 12) {
  103. timePeriod = 1;
  104. timePeriodStr = "上午考勤";
  105. } else if (now.getHour() <= 18) {
  106. timePeriod = 2;
  107. timePeriodStr = "下午考勤";
  108. } else {
  109. timePeriod = 3;
  110. timePeriodStr = "晚上考勤";
  111. }
  112. DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
  113. int userCount = 0;
  114. Set<Integer> roleTypes = list.stream().map(AttendanceMessageSet::getRoleType).collect(Collectors.toSet());
  115. //查询需要通知的人
  116. String table = "attendance_message_log";
  117. boolean isInsert = true;
  118. for (AttendanceMessageSet messageSet : list) {
  119. LocalDateTime recentlyTime = null;
  120. String characterKey = "character_string18";
  121. String wechatTemplate = weChatUtil.getAttendanceMsgLateTemplate();
  122. if (messageSet.getMessageCategory() != null && messageSet.getMessageCategory() == 1) {
  123. wechatTemplate = weChatUtil.getAttendanceMsgLateTemplate();
  124. characterKey = "character_string18";
  125. //获取最近的时间
  126. recentlyTime = getRecentlyTime(ruleDetails, now);
  127. if (recentlyTime.getHour() != now.getHour() || (recentlyTime.getHour() == now.getHour() && recentlyTime.getMinute() != now.getMinute())) {
  128. log.info("未到时间,不进行推送");
  129. isInsert = false;
  130. continue;
  131. }
  132. Entity entity = Entity.create(table);
  133. entity.set("send_time", recentlyTime);
  134. entity.set("template_id", wechatTemplate);
  135. String sql = "SELECT COUNT(*) FROM " + table + " WHERE delete_mark = 0 AND template_id = '" + wechatTemplate
  136. + "' AND send_time = '" + recentlyTime.format(formatter) + "'";
  137. long count = SqlRunnerAdapter.db().selectCount(sql);
  138. if (count > 0) {//已经推送过,不再进行推送
  139. log.info("已推送过,不进行推送");
  140. isInsert = false;
  141. continue;
  142. }
  143. } else if (messageSet.getMessageCategory() != null && messageSet.getMessageCategory() == 3) {
  144. wechatTemplate = weChatUtil.getAttendanceMsgAbsenceTemplate();
  145. recentlyTime = getRecentlyOverTime(ruleDetails, now);
  146. characterKey = "character_string36";
  147. if (recentlyTime.getHour() != now.getHour() || (recentlyTime.getHour() == now.getHour() && recentlyTime.getMinute() != now.getMinute())) {
  148. log.info("未到时间,不进行推送");
  149. isInsert = false;
  150. continue;
  151. }
  152. String sql = "SELECT COUNT(*) FROM " + table + " WHERE delete_mark = 0 AND template_id = '" + wechatTemplate
  153. + "' AND send_time = '" + recentlyTime.format(formatter) + "'";
  154. long count = SqlRunnerAdapter.db().selectCount(sql);
  155. if (count > 0) {//已经推送过,不再进行推送
  156. log.info("已推送过,不进行推送");
  157. isInsert = false;
  158. continue;
  159. }
  160. }
  161. if (!messageSet.getTimePeriod().contains(timePeriod + "")) {
  162. isInsert = false;
  163. continue;
  164. }
  165. List<XjrUser> userList = userService.list(
  166. new MPJLambdaWrapper<XjrUser>().distinct()
  167. .select(XjrUser::getId)
  168. .select(XjrUser.class, x -> VoToColumnUtil.fieldsToColumns(XjrUser.class).contains(x.getProperty()))
  169. .leftJoin(UserRoleRelation.class, UserRoleRelation::getUserId, XjrUser::getId)
  170. .leftJoin(AttendanceMessageUserRelation.class, AttendanceMessageUserRelation::getUserId, XjrUser::getId)
  171. .in(UserRoleRelation::getRoleId, roleTypes)
  172. .eq(AttendanceMessageUserRelation::getAttendanceMessageSetId, messageSet.getId())
  173. );
  174. //没有需要通知的,直接跳过
  175. if (userList.isEmpty()) {
  176. isInsert = false;
  177. continue;
  178. }
  179. if (recentlyTime == null) {
  180. isInsert = false;
  181. continue;
  182. }
  183. String format = recentlyTime.format(formatter);
  184. userCount += userList.size();
  185. if (messageSet.getRoleType() != null && messageSet.getRoleType() == 1) {
  186. //教师总人数
  187. long teacherCout = userService.count(
  188. new MPJLambdaWrapper<XjrUser>()
  189. .leftJoin(BaseTeacher.class, BaseTeacher::getUserId, XjrUser::getId)
  190. );
  191. //查询进入记录,就是实际到校的人数
  192. List<TeacherOutInRecord> outInRecords = teachertOutInRecordService.list(
  193. new MPJLambdaWrapper<TeacherOutInRecord>()
  194. .le(TeacherOutInRecord::getRecordTime, recentlyTime)
  195. .eq(TeacherOutInRecord::getStatus, 1)
  196. .eq("DATE_FORMAT(record_time, '%Y-%m-%d')", recentlyTime.toLocalDate())
  197. );
  198. List<Long> collect = outInRecords.stream().map(TeacherOutInRecord::getUserId).collect(Collectors.toList());
  199. WeChatSendMessageDto weChatSendMessageDto = new WeChatSendMessageDto();
  200. weChatSendMessageDto.setTemplateId(wechatTemplate);
  201. JSONObject paramJson = new JSONObject();
  202. JSONObject thing6 = new JSONObject();
  203. thing6.put("value", "教职工");
  204. paramJson.put("thing6", thing6);
  205. JSONObject time11 = new JSONObject();
  206. time11.put("value", format);
  207. paramJson.put("time11", time11);
  208. JSONObject const23 = new JSONObject();
  209. const23.put("value", timePeriodStr);
  210. paramJson.put("const23", const23);
  211. //迟到人数或者缺勤人数
  212. JSONObject character_string18 = new JSONObject();
  213. character_string18.put("value", teacherCout - collect.size());
  214. paramJson.put(characterKey, character_string18);
  215. JSONObject character_string16 = new JSONObject();
  216. character_string16.put("value", teacherCout);
  217. paramJson.put("character_string16", character_string16);
  218. weChatSendMessageDto.setContent(paramJson);
  219. weChatSendMessageDto.setUrl(StrUtil.format("{}pages/attendance/teacher/index", commonPropertiesConfig.getDomainApp()));
  220. for (XjrUser xjrUser : userList) {
  221. weChatSendMessageDto.setMsgId(IdUtil.getSnowflakeNextId() + "");
  222. weChatSendMessageDto.setUserId(xjrUser.getOpenId());
  223. weChatService.sendTemplateMessage(weChatSendMessageDto);
  224. }
  225. } else if (messageSet.getRoleType() != null && messageSet.getRoleType() == 2) {
  226. //教师总人数
  227. long teacherCout = userService.count(
  228. new MPJLambdaWrapper<XjrUser>()
  229. .leftJoin(BaseStudent.class, BaseStudent::getUserId, XjrUser::getId)
  230. );
  231. //查询进入记录,就是实际到校的人数
  232. long outInRecords = studentOutInRecordService.count(
  233. new MPJLambdaWrapper<StudentOutInRecord>()
  234. .le(StudentOutInRecord::getRecordTime, recentlyTime)
  235. .eq(StudentOutInRecord::getStatus, 1)
  236. );
  237. WeChatSendMessageDto weChatSendMessageDto = new WeChatSendMessageDto();
  238. weChatSendMessageDto.setTemplateId(wechatTemplate);
  239. JSONObject paramJson = new JSONObject();
  240. JSONObject thing6 = new JSONObject();
  241. thing6.put("value", "学生");
  242. paramJson.put("thing6", thing6);
  243. JSONObject time11 = new JSONObject();
  244. time11.put("value", format);
  245. paramJson.put("time11", time11);
  246. JSONObject const23 = new JSONObject();
  247. const23.put("value", timePeriodStr);
  248. paramJson.put("const23", const23);
  249. JSONObject character_string18 = new JSONObject();
  250. character_string18.put("value", teacherCout - outInRecords);
  251. paramJson.put(characterKey, character_string18);
  252. JSONObject character_string16 = new JSONObject();
  253. character_string16.put("value", teacherCout);
  254. paramJson.put("const3", character_string16);
  255. weChatSendMessageDto.setContent(paramJson);
  256. weChatSendMessageDto.setUrl(StrUtil.format("{}pages/attendance/class/index", commonPropertiesConfig.getDomainApp()));
  257. for (XjrUser xjrUser : userList) {
  258. weChatSendMessageDto.setMsgId(IdUtil.getSnowflakeNextId() + "");
  259. weChatSendMessageDto.setUserId(xjrUser.getOpenId());
  260. weChatService.sendTemplateMessage(weChatSendMessageDto);
  261. }
  262. isInsert = true;
  263. }
  264. if (isInsert) {
  265. SimpleDateFormat sdf = new SimpleDateFormat("yyy-MM-dd HH:mm:ss");
  266. Entity entity = Entity.create(table);
  267. entity.set("id", IdUtil.getSnowflakeNextId());
  268. entity.set("content", "消息推送人数:" + userCount);
  269. entity.set("create_date", sdf.format(new Date()));
  270. entity.set("content", "消息推送人数:" + userCount);
  271. entity.set("template_id", wechatTemplate);
  272. entity.set("send_time", recentlyTime);
  273. SqlRunnerAdapter.db().dynamicInsert(table, entity);
  274. }
  275. }
  276. }
  277. LocalDateTime getRecentlyTime(List<AttendanceRuleDetails> ruleDetails, LocalDateTime now) {
  278. List<LocalDateTime> result = new ArrayList<>();
  279. for (AttendanceRuleDetails ruleDetail : ruleDetails) {
  280. if (ruleDetail.getIsAllowInOutSchool() != null && ruleDetail.getIsAllowInOutSchool() == 1
  281. && ruleDetail.getIsAttendance() != null && ruleDetail.getIsAttendance() == 1) {
  282. if (ruleDetail.getAmStartTime() != null) {
  283. LocalDateTime amStartTime = now.with(ruleDetail.getAmStartTime().toLocalTime());
  284. result.add(amStartTime);
  285. }
  286. if (ruleDetail.getPmStartTime() != null) {
  287. LocalDateTime pmStartTime = now.with(ruleDetail.getPmStartTime().toLocalTime());
  288. result.add(pmStartTime);
  289. }
  290. if (ruleDetail.getEveningStartTime() != null) {
  291. LocalDateTime eveningStartTime = now.with(ruleDetail.getEveningStartTime().toLocalTime());
  292. result.add(eveningStartTime);
  293. }
  294. }
  295. }
  296. if (result.isEmpty()) {
  297. return null;
  298. }
  299. Map<Long, LocalDateTime> timeMap = new HashMap<>();
  300. for (LocalDateTime localDateTime : result) {
  301. long between = ChronoUnit.SECONDS.between(now, localDateTime);
  302. timeMap.put(Math.abs(between), localDateTime);
  303. }
  304. List<Long> collect = timeMap.keySet().stream().collect(Collectors.toList());
  305. Collections.sort(collect, Long::compare);
  306. return timeMap.get(collect.get(0));
  307. }
  308. LocalDateTime getRecentlyOverTime(List<AttendanceRuleDetails> ruleDetails, LocalDateTime now) {
  309. List<LocalDateTime> result = new ArrayList<>();
  310. for (AttendanceRuleDetails ruleDetail : ruleDetails) {
  311. if (ruleDetail.getIsAllowInOutSchool() != null && ruleDetail.getIsAllowInOutSchool() == 1
  312. && ruleDetail.getIsAttendance() != null && ruleDetail.getIsAttendance() == 1) {
  313. if (ruleDetail.getAmStartTime() != null) {
  314. LocalDateTime amStartTime = now.with(ruleDetail.getAmStartTime().toLocalTime());
  315. if (ruleDetail.getOverMinutes() != null) {
  316. amStartTime.plusMinutes(ruleDetail.getOverMinutes());
  317. }
  318. result.add(amStartTime);
  319. }
  320. if (ruleDetail.getPmStartTime() != null) {
  321. LocalDateTime pmStartTime = now.with(ruleDetail.getPmStartTime().toLocalTime());
  322. if (ruleDetail.getOverMinutes() != null) {
  323. pmStartTime.plusMinutes(ruleDetail.getOverMinutes());
  324. }
  325. result.add(pmStartTime);
  326. }
  327. if (ruleDetail.getEveningStartTime() != null) {
  328. LocalDateTime eveningStartTime = now.with(ruleDetail.getEveningStartTime().toLocalTime());
  329. if (ruleDetail.getOverMinutes() != null) {
  330. eveningStartTime.plusMinutes(ruleDetail.getOverMinutes());
  331. }
  332. result.add(eveningStartTime);
  333. }
  334. }
  335. }
  336. if (result.isEmpty()) {
  337. return null;
  338. }
  339. Map<Long, LocalDateTime> timeMap = new HashMap<>();
  340. for (LocalDateTime localDateTime : result) {
  341. long between = ChronoUnit.SECONDS.between(now, localDateTime);
  342. timeMap.put(Math.abs(between), localDateTime);
  343. }
  344. List<Long> collect = timeMap.keySet().stream().collect(Collectors.toList());
  345. Collections.sort(collect, Long::compare);
  346. return timeMap.get(collect.get(0));
  347. }
  348. }