AttendanceStatisticsServiceImpl.java 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592
  1. package com.xjrsoft.module.attendance.service.impl;
  2. import cn.hutool.core.bean.BeanUtil;
  3. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  4. import com.baomidou.mybatisplus.core.toolkit.Wrappers;
  5. import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
  6. import com.github.yulichang.base.MPJBaseServiceImpl;
  7. import com.github.yulichang.wrapper.MPJLambdaWrapper;
  8. import com.google.gson.JsonArray;
  9. import com.google.gson.JsonElement;
  10. import com.google.gson.JsonObject;
  11. import com.google.gson.JsonParser;
  12. import com.xjrsoft.common.enums.DeleteMark;
  13. import com.xjrsoft.common.exception.MyException;
  14. import com.xjrsoft.common.utils.VoToColumnUtil;
  15. import com.xjrsoft.module.attendance.dto.AddAttendanceStatisticsDto;
  16. import com.xjrsoft.module.attendance.dto.AttendanceStatisticsPageDto;
  17. import com.xjrsoft.module.attendance.dto.AttendanceStatisticsRecordDto;
  18. import com.xjrsoft.module.attendance.entity.AttendanceRuleDetails;
  19. import com.xjrsoft.module.attendance.entity.AttendanceStatistics;
  20. import com.xjrsoft.module.attendance.entity.AttendanceStatisticsRecord;
  21. import com.xjrsoft.module.attendance.entity.AttendanceUserRelation;
  22. import com.xjrsoft.module.attendance.entity.TeacherAttendanceRecord;
  23. import com.xjrsoft.module.attendance.mapper.AttendanceStatisticsMapper;
  24. import com.xjrsoft.module.attendance.service.IAttendanceRuleCategoryService;
  25. import com.xjrsoft.module.attendance.service.IAttendanceStatisticsRecordService;
  26. import com.xjrsoft.module.attendance.service.IAttendanceStatisticsService;
  27. import com.xjrsoft.module.attendance.service.ITeacherAttendanceRecordService;
  28. import com.xjrsoft.module.attendance.vo.AttendanceStatisticsPageVo;
  29. import com.xjrsoft.module.attendance.vo.AttendanceStatisticsRecordVo;
  30. import com.xjrsoft.module.holiday.entity.HolidayDate;
  31. import com.xjrsoft.module.holiday.service.IHolidayDateService;
  32. import com.xjrsoft.module.organization.entity.User;
  33. import com.xjrsoft.module.organization.service.IUserService;
  34. import com.xjrsoft.module.organization.vo.UserIdDeptNameVo;
  35. import com.xjrsoft.module.teacher.entity.BaseTeacher;
  36. import lombok.AllArgsConstructor;
  37. import me.zhyd.oauth.log.Log;
  38. import org.apache.poi.ss.usermodel.Cell;
  39. import org.apache.poi.ss.usermodel.CellStyle;
  40. import org.apache.poi.ss.usermodel.Font;
  41. import org.apache.poi.ss.usermodel.HorizontalAlignment;
  42. import org.apache.poi.ss.usermodel.IndexedColors;
  43. import org.apache.poi.ss.usermodel.Row;
  44. import org.apache.poi.ss.usermodel.Sheet;
  45. import org.apache.poi.ss.usermodel.VerticalAlignment;
  46. import org.apache.poi.ss.usermodel.Workbook;
  47. import org.apache.poi.ss.util.CellRangeAddress;
  48. import org.apache.poi.xssf.usermodel.XSSFWorkbook;
  49. import org.springframework.stereotype.Service;
  50. import org.springframework.transaction.annotation.Transactional;
  51. import java.io.ByteArrayOutputStream;
  52. import java.io.IOException;
  53. import java.time.LocalDate;
  54. import java.time.format.DateTimeFormatter;
  55. import java.time.temporal.ChronoUnit;
  56. import java.util.ArrayList;
  57. import java.util.Arrays;
  58. import java.util.Date;
  59. import java.util.HashMap;
  60. import java.util.List;
  61. import java.util.Map;
  62. import java.util.Objects;
  63. import java.util.concurrent.CompletableFuture;
  64. import java.util.stream.Collectors;
  65. /**
  66. * @title: 考勤统计
  67. * @Author dzx
  68. * @Date: 2024-10-19
  69. * @Version 1.0
  70. */
  71. @Service
  72. @AllArgsConstructor
  73. public class AttendanceStatisticsServiceImpl extends MPJBaseServiceImpl<AttendanceStatisticsMapper, AttendanceStatistics> implements IAttendanceStatisticsService {
  74. private final AttendanceStatisticsMapper statisticsMapper;
  75. private final IAttendanceStatisticsRecordService statisticsRecordService;
  76. private final ITeacherAttendanceRecordService recordService;
  77. private final IUserService userService;
  78. private final IAttendanceRuleCategoryService ruleCategoryService;
  79. private final IHolidayDateService holidayDateService;
  80. @Override
  81. @Transactional(rollbackFor = Exception.class)
  82. public Boolean add(AddAttendanceStatisticsDto dto) {
  83. AttendanceStatistics attendanceStatistics = BeanUtil.toBean(dto, AttendanceStatistics.class);
  84. attendanceStatistics.setCreateDate(new Date());
  85. attendanceStatistics.setStatus(0);
  86. statisticsMapper.insert(attendanceStatistics);
  87. refreshRecord(attendanceStatistics.getId());
  88. return true;
  89. }
  90. @Override
  91. @Transactional(rollbackFor = Exception.class)
  92. public Boolean update(AttendanceStatistics attendanceStatistics) {
  93. statisticsMapper.updateById(attendanceStatistics);
  94. //********************************* AttendanceStatisticsRecord 增删改 开始 *******************************************/
  95. {
  96. // 查出所有子级的id
  97. List<AttendanceStatisticsRecord> attendanceStatisticsRecordList = statisticsRecordService.list(Wrappers.lambdaQuery(AttendanceStatisticsRecord.class).eq(AttendanceStatisticsRecord::getAttendanceStatisticsId, attendanceStatistics.getId()).select(AttendanceStatisticsRecord::getId));
  98. List<Long> attendanceStatisticsRecordIds = attendanceStatisticsRecordList.stream().map(AttendanceStatisticsRecord::getId).collect(Collectors.toList());
  99. //原有子表单 没有被删除的主键
  100. List<Long> attendanceStatisticsRecordOldIds = attendanceStatistics.getAttendanceStatisticsRecordList().stream().map(AttendanceStatisticsRecord::getId).filter(Objects::nonNull).collect(Collectors.toList());
  101. //找到需要删除的id
  102. List<Long> attendanceStatisticsRecordRemoveIds = attendanceStatisticsRecordIds.stream().filter(item -> !attendanceStatisticsRecordOldIds.contains(item)).collect(Collectors.toList());
  103. for (AttendanceStatisticsRecord attendanceStatisticsRecord : attendanceStatistics.getAttendanceStatisticsRecordList()) {
  104. //如果不等于空则修改
  105. if (attendanceStatisticsRecord.getId() != null) {
  106. statisticsRecordService.updateById(attendanceStatisticsRecord);
  107. }
  108. //如果等于空 则新增
  109. else {
  110. //已经不存在的id 删除
  111. attendanceStatisticsRecord.setAttendanceStatisticsId(attendanceStatistics.getId());
  112. statisticsRecordService.save(attendanceStatisticsRecord);
  113. }
  114. }
  115. //已经不存在的id 删除
  116. if(attendanceStatisticsRecordRemoveIds.size() > 0){
  117. statisticsRecordService.removeBatchByIds(attendanceStatisticsRecordRemoveIds);
  118. }
  119. }
  120. //********************************* AttendanceStatisticsRecord 增删改 结束 *******************************************/
  121. return true;
  122. }
  123. @Override
  124. @Transactional(rollbackFor = Exception.class)
  125. public Boolean delete(List<Long> ids) {
  126. statisticsMapper.deleteBatchIds(ids);
  127. statisticsRecordService.remove(Wrappers.lambdaQuery(AttendanceStatisticsRecord.class).in(AttendanceStatisticsRecord::getAttendanceStatisticsId, ids));
  128. return true;
  129. }
  130. @Override
  131. public Page<AttendanceStatisticsPageVo> getPage(Page<AttendanceStatisticsPageVo> page, AttendanceStatisticsPageDto dto) {
  132. return this.baseMapper.getPage(page, dto);
  133. }
  134. @Override
  135. public List<AttendanceStatisticsRecordVo> getRecordList(AttendanceStatisticsRecordDto dto) {
  136. return this.baseMapper.getRecordList(dto);
  137. }
  138. /**
  139. * 1、修改状态为统计中
  140. * 2、删除以前的数据
  141. * 3、重新计算数据并入库
  142. * 4、将状态改为统计完成
  143. */
  144. @Override
  145. @Transactional(rollbackFor = Exception.class)
  146. public Boolean refreshRecord(Long id) {
  147. try {
  148. //1、修改状态为统计中
  149. AttendanceStatistics statistics = this.getById(id);
  150. statistics.setStatus(0);
  151. statistics.setModifyDate(new Date());
  152. this.updateById(statistics);
  153. //2、删除以前的数据
  154. statisticsRecordService.remove(
  155. new QueryWrapper<AttendanceStatisticsRecord>().lambda()
  156. .eq(AttendanceStatisticsRecord::getAttendanceStatisticsId, id)
  157. );
  158. /**
  159. * 3、重新计算数据并入库
  160. */
  161. //3.1、根据考勤规则和统计的时间段查询这个规则下面所涉及到的老师
  162. List<User> userList = userService.list(
  163. new MPJLambdaWrapper<User>()
  164. .select(User::getId)
  165. .select(User.class, x -> VoToColumnUtil.fieldsToColumns(User.class).contains(x.getProperty()))
  166. .innerJoin(AttendanceUserRelation.class, AttendanceUserRelation::getUserId, User::getId)
  167. .innerJoin(BaseTeacher.class, BaseTeacher::getUserId, User::getId)
  168. .eq(AttendanceUserRelation::getAttendanceRuleCategoryId, statistics.getAttendanceRuleCategoryId())
  169. .eq(AttendanceUserRelation::getDeleteMark, DeleteMark.NODELETE.getCode())
  170. );
  171. if(userList.isEmpty()){
  172. throw new MyException("该规则下无考勤人员");
  173. }
  174. List<Long> userIds = userList.stream().map(User::getId).collect(Collectors.toList());
  175. //查询固化的考勤数据
  176. List<TeacherAttendanceRecord> attendanceRecords = recordService.list(
  177. new QueryWrapper<TeacherAttendanceRecord>().lambda()
  178. .eq(TeacherAttendanceRecord::getTimeInterval, statistics.getTimePeriod())
  179. .in(TeacherAttendanceRecord::getUserId, userIds)
  180. .between(TeacherAttendanceRecord::getAttendanceDate, statistics.getStartDate(), statistics.getEndDate())
  181. .eq(TeacherAttendanceRecord::getDeleteMark, DeleteMark.NODELETE.getCode())
  182. );
  183. //3.2、准备相关需要的数据
  184. DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
  185. DateTimeFormatter timeDtf = DateTimeFormatter.ofPattern("HH:mm");
  186. Map<String, String> weekCnMap = initWeekCn();
  187. Map<String, String> weekEnMap = initWeekEn();
  188. List<UserIdDeptNameVo> teacherDeptName = userService.getTeacherDeptName();
  189. Map<Long, UserIdDeptNameVo> userDeptMap = teacherDeptName.stream().collect(Collectors.toMap(UserIdDeptNameVo::getId, x -> x));
  190. //3.3、查询这个考勤规则下面的所有细则并转换成map
  191. List<AttendanceRuleDetails> ruleList = ruleCategoryService.getRules(statistics.getAttendanceRuleCategoryId());
  192. Map<String, AttendanceRuleDetails> ruleMap = ruleList.stream().collect(Collectors.toMap(AttendanceRuleDetails::getDateType, x -> x));
  193. //3.4、计算出所有的天数
  194. List<LocalDate> dateList = getDatesBetween(statistics.getStartDate(), statistics.getEndDate(), ruleMap, weekEnMap);
  195. //3.5、循环计算,并存入insertList,方便后续批量入库
  196. List<AttendanceStatisticsRecord> insertList = new ArrayList<>();
  197. List<String> leaveTypeList = new ArrayList<>();
  198. leaveTypeList.add("事假");leaveTypeList.add("公假");leaveTypeList.add("病假");leaveTypeList.add("会议活动");
  199. for (User user : userList) {
  200. AttendanceStatisticsRecord record = new AttendanceStatisticsRecord();
  201. record.setUserId(user.getId());
  202. record.setAttendanceStatisticsId(statistics.getId());
  203. Long normalCount = 0L;
  204. Long leaveCount = 0L;
  205. Long absenteeCount = 0L;
  206. JsonArray daysData = new JsonArray();
  207. int sortCode = 1;
  208. for (LocalDate localDate : dateList) {
  209. String dayOfWeekName = localDate.getDayOfWeek().name();
  210. AttendanceRuleDetails ruleDetails = ruleMap.get(weekEnMap.get(dayOfWeekName));
  211. if(ruleDetails != null && (ruleDetails.getIsAttendance() == null || ruleDetails.getIsAttendance() == 0)){
  212. continue;
  213. }
  214. JsonObject daysJson = new JsonObject();
  215. daysJson.addProperty("date", localDate.format(dtf));
  216. daysJson.addProperty("week", weekCnMap.get(dayOfWeekName));
  217. String content = "";
  218. if(statistics.getTimePeriod() == 1){
  219. content += "(" + ruleDetails.getAmStartTime().toLocalTime().format(timeDtf) + ")上班 ";
  220. }else if(statistics.getTimePeriod() == 2){
  221. content += "(" + ruleDetails.getPmStartTime().toLocalTime().format(timeDtf) + ")上班 ";
  222. }
  223. List<TeacherAttendanceRecord> collect = attendanceRecords.stream()
  224. .filter(el -> el.getAttendanceDate().equals(localDate) && el.getUserId().equals(user.getId())
  225. && !"不考勤".equals(el.getAttendanceStatus())
  226. )
  227. .collect(Collectors.toList());
  228. for (TeacherAttendanceRecord attendanceRecord : collect) {
  229. if("到校".equals(attendanceRecord.getAttendanceStatus())){
  230. normalCount ++;
  231. content += "正常(" + attendanceRecord.getRecordTime().toLocalTime().format(timeDtf) + ")";
  232. }else if(leaveTypeList.contains(attendanceRecord.getAttendanceStatus())){
  233. leaveCount ++;
  234. content += "请假";
  235. }else{
  236. absenteeCount ++;
  237. content += "缺勤";
  238. }
  239. }
  240. daysJson.addProperty("content", content);
  241. daysJson.addProperty("sortCode", sortCode);
  242. daysData.add(daysJson);
  243. sortCode ++;
  244. }
  245. record.setNormalCount(normalCount);
  246. record.setLeaveCount(leaveCount);
  247. record.setAbsenteeCount(absenteeCount);
  248. record.setDaysData(daysData.toString());
  249. UserIdDeptNameVo deptNameVo = userDeptMap.get(record.getUserId());
  250. if(deptNameVo != null){
  251. record.setDeptIds(deptNameVo.getDeptIds());
  252. record.setDeptName(deptNameVo.getDeptName());
  253. }
  254. insertList.add(record);
  255. }
  256. //3.6、插入数据
  257. if(!insertList.isEmpty()){
  258. statisticsRecordService.saveBatch(insertList);
  259. }
  260. //4、将状态改为统计完成
  261. statistics = this.getById(id);
  262. statistics.setStatus(1);
  263. statistics.setModifyDate(new Date());
  264. statistics.setPersonCount(insertList.size());
  265. statistics.setAttendanceDays(dateList.size());
  266. this.updateById(statistics);
  267. return true;
  268. }catch (Exception e){
  269. Log.error(e.getMessage(), e);
  270. if(e.getClass().equals(MyException.class)){
  271. throw new MyException(e.getMessage());
  272. }else{
  273. throw new MyException("刷新出错,请联系管理员");
  274. }
  275. }
  276. }
  277. private List<LocalDate> getDatesBetween(LocalDate startDate, LocalDate endDate, Map<String, AttendanceRuleDetails> ruleMap, Map<String, String> weekEnMap) {
  278. List<LocalDate> dates = new ArrayList<>();
  279. List<HolidayDate> holidayDates = holidayDateService.list(
  280. new QueryWrapper<HolidayDate>().lambda()
  281. .eq(HolidayDate::getStatus, 3)
  282. );
  283. List<String> holidayDateList = holidayDates.stream().map(HolidayDate::getDate).collect(Collectors.toList());
  284. DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
  285. long numOfDaysBetween = ChronoUnit.DAYS.between(startDate, endDate) + 1; // +1 包含结束日期
  286. for (long i = 0; i < numOfDaysBetween; i++) {
  287. LocalDate localDate = startDate.plusDays(i);
  288. AttendanceRuleDetails holidays = ruleMap.get("holidays");
  289. if(holidayDateList.contains(localDate.format(formatter)) && (holidays.getIsAttendance() == null || holidays.getIsAttendance() == 0)){
  290. continue;
  291. }
  292. AttendanceRuleDetails ruleDetails = ruleMap.get(weekEnMap.get(localDate.getDayOfWeek().name()));
  293. if(ruleDetails != null && ruleDetails.getIsAttendance() != null && ruleDetails.getIsAttendance() == 1){
  294. dates.add(localDate);
  295. }
  296. }
  297. return dates;
  298. }
  299. private Map<String, String> initWeekCn() {
  300. Map<String, String> result = new HashMap<>();
  301. result.put("MONDAY", "周一");
  302. result.put("TUESDAY", "周二");
  303. result.put("WEDNESDAY", "周三");
  304. result.put("THURSDAY", "周四");
  305. result.put("FRIDAY", "周五");
  306. result.put("SATURDAY", "周六");
  307. result.put("SUNDAY", "周日");
  308. return result;
  309. }
  310. private Map<String, String> initWeekEn() {
  311. Map<String, String> result = new HashMap<>();
  312. result.put("MONDAY", "monday");
  313. result.put("TUESDAY", "tuesday");
  314. result.put("WEDNESDAY", "wednesday");
  315. result.put("THURSDAY", "thursday");
  316. result.put("FRIDAY", "friday");
  317. result.put("SATURDAY", "saturday");
  318. result.put("SUNDAY", "sunday");
  319. return result;
  320. }
  321. @Override
  322. public byte[] recordExport(Long id) throws IOException {
  323. AttendanceStatistics statistics = this.getById(id);
  324. List<AttendanceStatisticsRecordVo> recordList = this.getRecordList(new AttendanceStatisticsRecordDto() {{
  325. setId(id);
  326. }});
  327. List<ArrayList<String>> dataList = new ArrayList<>();
  328. int sortCode = 1;
  329. JsonParser parser = new JsonParser();
  330. List<String> dateList = new ArrayList<>();
  331. List<String> weekList = new ArrayList<>();
  332. for (AttendanceStatisticsRecordVo recordVo : recordList) {
  333. ArrayList<String> data = new ArrayList<>();
  334. data.add(sortCode + "");
  335. data.add(recordVo.getName());
  336. data.add(recordVo.getUserName());
  337. data.add(recordVo.getDeptName());
  338. data.add(recordVo.getNormalCount() + "");
  339. data.add(recordVo.getLeaveCount() + "");
  340. data.add(recordVo.getAbsenteeCount() + "");
  341. JsonArray daysData = parser.parse(recordVo.getDaysData()).getAsJsonArray();
  342. for (JsonElement daysDatum : daysData) {
  343. JsonObject daysJson = daysDatum.getAsJsonObject();
  344. data.add(daysJson.get("content").getAsString());
  345. if(!dateList.contains(daysJson.get("date").getAsString())){
  346. dateList.add(daysJson.get("date").getAsString());
  347. }
  348. if(!weekList.contains(daysJson.get("week").getAsString())){
  349. weekList.add(daysJson.get("week").getAsString());
  350. }
  351. }
  352. dataList.add(data);
  353. }
  354. int allColumn = 7 + statistics.getAttendanceDays();//总列数
  355. Workbook workbook = new XSSFWorkbook();
  356. // 创建一个工作表(sheet)
  357. String sheetName = "数据";
  358. Sheet sheet = workbook.createSheet(sheetName);
  359. // 第一行表头
  360. createFirstTitle(workbook, sheet, allColumn - 1);
  361. // 第二行表头
  362. createSecondTitle(workbook, sheet, statistics, 3);
  363. // 第三行表头
  364. createThirdTitle(workbook, sheet, weekList);
  365. // 第四行表头
  366. createFourthTitle(workbook, sheet, 7, dateList);
  367. //生成数据
  368. int dataRowNumber = 4;
  369. for (ArrayList<String> rowData : dataList) {
  370. Row dataRow = sheet.createRow(dataRowNumber);
  371. for (int i = 0; i < rowData.size(); i ++){
  372. String content = rowData.get(i);
  373. Font font = workbook.createFont();
  374. font.setBold(false);// 设置为粗体
  375. font.setFontName("宋体");
  376. if(content != null && content.contains("缺勤")){
  377. font.setColor(IndexedColors.RED.getIndex()); // 设置字体颜色为红色
  378. }else if(content != null && content.contains("正常")){
  379. font.setColor(IndexedColors.BLUE.getIndex()); // 设置字体颜色为蓝色
  380. }else if(content != null && content.contains("请假")){
  381. font.setColor(IndexedColors.YELLOW.getIndex()); // 设置字体颜色为黄色
  382. }
  383. font.setFontHeightInPoints((short)12);
  384. CellStyle cellStyle = workbook.createCellStyle();
  385. cellStyle.setFont(font); // 将字体应用到样式
  386. cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
  387. Cell row1cell2 = dataRow.createCell(i);
  388. row1cell2.setCellValue(content);
  389. row1cell2.setCellStyle(cellStyle);
  390. }
  391. dataRowNumber ++;
  392. }
  393. //写入文件
  394. ByteArrayOutputStream bot = new ByteArrayOutputStream();
  395. workbook.write(bot);
  396. return bot.toByteArray();
  397. }
  398. /**
  399. * 创建第一行表头
  400. * @param mergeCoulmn 合并后面多少列(不包含自己)
  401. */
  402. void createFirstTitle(Workbook workbook, Sheet sheet, int mergeCoulmn) {
  403. int rowNumber = 0;
  404. Font font = workbook.createFont();
  405. font.setBold(true);// 设置为粗体
  406. font.setFontName("宋体");
  407. //font.setColor(IndexedColors.RED.getIndex()); // 设置字体颜色为红色
  408. font.setFontHeightInPoints((short)24);
  409. CellStyle cellStyle = workbook.createCellStyle();
  410. cellStyle.setFont(font); // 将字体应用到样式
  411. cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
  412. cellStyle.setAlignment(HorizontalAlignment.CENTER);
  413. Row row = sheet.createRow(rowNumber);
  414. //合并第一行的列
  415. sheet.addMergedRegion(new CellRangeAddress(rowNumber, rowNumber, 0, mergeCoulmn));
  416. //3、处理表头
  417. String title1 = "坐班考勤 - 汇总统计";
  418. // 创建单元格并设置值
  419. Cell cell = row.createCell(0);
  420. cell.setCellValue(title1);
  421. cell.setCellStyle(cellStyle);
  422. }
  423. /**
  424. * 生成第二行表头
  425. * @param mergeCoulmn 合并后面多少列(不包含自己)
  426. */
  427. void createSecondTitle(Workbook workbook, Sheet sheet, AttendanceStatistics statistics, int mergeCoulmn) {
  428. int rowNumber = 1;
  429. Font font = workbook.createFont();
  430. font.setFontName("宋体");
  431. font.setFontHeightInPoints((short)12);
  432. CellStyle cellStyle = workbook.createCellStyle();
  433. cellStyle.setFont(font); // 将字体应用到样式
  434. cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
  435. cellStyle.setAlignment(HorizontalAlignment.CENTER);
  436. Row row1 = sheet.createRow(rowNumber);
  437. Cell row1cell1 = row1.createCell(0);
  438. DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
  439. String content = "查询的考勤日期范围:" + statistics.getStartDate().format(dtf) + "至" + statistics.getEndDate() + ";";
  440. if(statistics.getTimePeriod() == 1){
  441. content += "时间段:上午";
  442. }else if(statistics.getTimePeriod() == 2){
  443. content += "时间段:下午";
  444. }
  445. row1cell1.setCellValue(content);
  446. row1cell1.setCellStyle(cellStyle);
  447. sheet.addMergedRegion(new CellRangeAddress(rowNumber, rowNumber, 0, mergeCoulmn));
  448. }
  449. /**
  450. * 生成第三行表头
  451. * 表头:序号、姓名、工号、部门、正常考勤次数、请假次数、缺勤次数,后续周几
  452. * @param weekList 周几
  453. */
  454. void createThirdTitle(Workbook workbook, Sheet sheet, List<String> weekList) {
  455. int rowNumber = 2;
  456. Font font = workbook.createFont();
  457. font.setFontName("宋体");
  458. font.setFontHeightInPoints((short)12);
  459. CellStyle cellStyle = workbook.createCellStyle();
  460. cellStyle.setFont(font); // 将字体应用到样式
  461. cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
  462. cellStyle.setAlignment(HorizontalAlignment.CENTER);
  463. Row row1 = sheet.createRow(rowNumber);
  464. Cell row1cell1 = row1.createCell(0);
  465. row1cell1.setCellValue("序号");
  466. row1cell1.setCellStyle(cellStyle);
  467. sheet.addMergedRegion(new CellRangeAddress(rowNumber, rowNumber + 1, 0, 0));
  468. Cell row1cell2 = row1.createCell(1);
  469. row1cell2.setCellValue("姓名");
  470. row1cell2.setCellStyle(cellStyle);
  471. sheet.addMergedRegion(new CellRangeAddress(rowNumber, rowNumber + 1, 1, 1));
  472. Cell row1cell3 = row1.createCell(2);
  473. row1cell3.setCellValue("工号");
  474. row1cell3.setCellStyle(cellStyle);
  475. sheet.addMergedRegion(new CellRangeAddress(rowNumber, rowNumber + 1, 2, 2));
  476. Cell row1cell4 = row1.createCell(3);
  477. row1cell4.setCellValue("组织机构");
  478. row1cell4.setCellStyle(cellStyle);
  479. sheet.addMergedRegion(new CellRangeAddress(rowNumber, rowNumber + 1, 3, 3));
  480. Cell row1cell5 = row1.createCell(4);
  481. row1cell5.setCellValue("正常考勤次数");
  482. row1cell5.setCellStyle(cellStyle);
  483. sheet.addMergedRegion(new CellRangeAddress(rowNumber, rowNumber + 1, 4, 4));
  484. Cell row1cell6 = row1.createCell(5);
  485. row1cell6.setCellValue("请假次数");
  486. row1cell6.setCellStyle(cellStyle);
  487. sheet.addMergedRegion(new CellRangeAddress(rowNumber, rowNumber + 1, 5, 5));
  488. Cell row1cell7 = row1.createCell(6);
  489. row1cell7.setCellValue("缺勤次数");
  490. row1cell7.setCellStyle(cellStyle);
  491. sheet.addMergedRegion(new CellRangeAddress(rowNumber, rowNumber + 1, 6, 6));
  492. int cellNumber = 7;
  493. for (String dayOfWeek : weekList) {
  494. Cell row1cell = row1.createCell(cellNumber);
  495. row1cell.setCellValue(dayOfWeek);
  496. row1cell.setCellStyle(cellStyle);
  497. cellNumber ++;
  498. }
  499. }
  500. /**
  501. *
  502. * @param startColumn 开始列
  503. * @param dateList 2024年10月20日
  504. */
  505. void createFourthTitle(Workbook workbook, Sheet sheet, int startColumn, List<String> dateList) {
  506. int rowNumber = 3;
  507. Font font = workbook.createFont();
  508. font.setFontName("宋体");
  509. font.setFontHeightInPoints((short)12);
  510. CellStyle cellStyle = workbook.createCellStyle();
  511. cellStyle.setFont(font); // 将字体应用到样式
  512. cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
  513. cellStyle.setAlignment(HorizontalAlignment.CENTER);
  514. Row row1 = sheet.createRow(rowNumber);
  515. for (String date : dateList) {
  516. Cell row1cell = row1.createCell(startColumn);
  517. row1cell.setCellValue(date);
  518. row1cell.setCellStyle(cellStyle);
  519. startColumn ++;
  520. }
  521. }
  522. }