|
@@ -7,7 +7,9 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
import com.github.yulichang.base.MPJBaseServiceImpl;
|
|
|
import com.github.yulichang.wrapper.MPJLambdaWrapper;
|
|
|
import com.google.gson.JsonArray;
|
|
|
+import com.google.gson.JsonElement;
|
|
|
import com.google.gson.JsonObject;
|
|
|
+import com.google.gson.JsonParser;
|
|
|
import com.xjrsoft.common.exception.MyException;
|
|
|
import com.xjrsoft.common.utils.VoToColumnUtil;
|
|
|
import com.xjrsoft.module.attendance.dto.AddAttendanceStatisticsDto;
|
|
@@ -27,11 +29,24 @@ import com.xjrsoft.module.attendance.vo.AttendanceStatisticsPageVo;
|
|
|
import com.xjrsoft.module.attendance.vo.AttendanceStatisticsRecordVo;
|
|
|
import com.xjrsoft.module.organization.entity.User;
|
|
|
import com.xjrsoft.module.organization.service.IUserService;
|
|
|
+import com.xjrsoft.module.organization.vo.UserIdDeptNameVo;
|
|
|
import lombok.AllArgsConstructor;
|
|
|
import me.zhyd.oauth.log.Log;
|
|
|
+import org.apache.poi.ss.usermodel.Cell;
|
|
|
+import org.apache.poi.ss.usermodel.CellStyle;
|
|
|
+import org.apache.poi.ss.usermodel.Font;
|
|
|
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
|
|
|
+import org.apache.poi.ss.usermodel.IndexedColors;
|
|
|
+import org.apache.poi.ss.usermodel.Row;
|
|
|
+import org.apache.poi.ss.usermodel.Sheet;
|
|
|
+import org.apache.poi.ss.usermodel.VerticalAlignment;
|
|
|
+import org.apache.poi.ss.usermodel.Workbook;
|
|
|
+import org.apache.poi.ss.util.CellRangeAddress;
|
|
|
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
|
+import java.io.ByteArrayOutputStream;
|
|
|
import java.io.IOException;
|
|
|
import java.time.LocalDate;
|
|
|
import java.time.format.DateTimeFormatter;
|
|
@@ -42,6 +57,7 @@ import java.util.HashMap;
|
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
|
import java.util.Objects;
|
|
|
+import java.util.concurrent.CompletableFuture;
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
/**
|
|
@@ -70,7 +86,9 @@ public class AttendanceStatisticsServiceImpl extends MPJBaseServiceImpl<Attendan
|
|
|
AttendanceStatistics attendanceStatistics = BeanUtil.toBean(dto, AttendanceStatistics.class);
|
|
|
attendanceStatistics.setCreateDate(new Date());
|
|
|
statisticsMapper.insert(attendanceStatistics);
|
|
|
-
|
|
|
+ CompletableFuture.runAsync(() -> {
|
|
|
+ refreshRecord(attendanceStatistics.getId());
|
|
|
+ });
|
|
|
return true;
|
|
|
}
|
|
|
|
|
@@ -176,17 +194,22 @@ public class AttendanceStatisticsServiceImpl extends MPJBaseServiceImpl<Attendan
|
|
|
.in(TeacherAttendanceRecord::getUserId, userIds)
|
|
|
.between(TeacherAttendanceRecord::getCreateDate, statistics.getStartDate(), statistics.getEndDate())
|
|
|
);
|
|
|
- //3.2、计算出所有的天数
|
|
|
- List<LocalDate> dateList = getDatesBetween(statistics.getStartDate(), statistics.getEndDate());
|
|
|
- //3.3、循环用户进行统计查询
|
|
|
+
|
|
|
+ //3.2、准备相关需要的数据
|
|
|
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
|
|
|
DateTimeFormatter timeDtf = DateTimeFormatter.ofPattern("HH:mm");
|
|
|
Map<String, String> weekCnMap = initWeekCn();
|
|
|
Map<String, String> weekEnMap = initWeekEn();
|
|
|
+ List<UserIdDeptNameVo> teacherDeptName = userService.getTeacherDeptName();
|
|
|
+ Map<Long, UserIdDeptNameVo> userDeptMap = teacherDeptName.stream().collect(Collectors.toMap(UserIdDeptNameVo::getId, x -> x));
|
|
|
|
|
|
- //3.4、查询这个考勤规则下面的所有细则并转换成map
|
|
|
+ //3.3、查询这个考勤规则下面的所有细则并转换成map
|
|
|
List<AttendanceRuleDetails> ruleList = ruleCategoryService.getRules(statistics.getAttendanceRuleCategoryId());
|
|
|
Map<String, AttendanceRuleDetails> ruleMap = ruleList.stream().collect(Collectors.toMap(AttendanceRuleDetails::getDateType, x -> x));
|
|
|
+
|
|
|
+ //3.4、计算出所有的天数
|
|
|
+ List<LocalDate> dateList = getDatesBetween(statistics.getStartDate(), statistics.getEndDate(), ruleMap, weekEnMap);
|
|
|
+
|
|
|
//3.5、循环计算,并存入insertList,方便后续批量入库
|
|
|
List<AttendanceStatisticsRecord> insertList = new ArrayList<>();
|
|
|
for (User user : userList) {
|
|
@@ -196,9 +219,13 @@ public class AttendanceStatisticsServiceImpl extends MPJBaseServiceImpl<Attendan
|
|
|
Long leaveCount = 0L;
|
|
|
Long absenteeCount = 0L;
|
|
|
JsonArray daysData = new JsonArray();
|
|
|
+ int sortCode = 1;
|
|
|
for (LocalDate localDate : dateList) {
|
|
|
String dayOfWeekName = localDate.getDayOfWeek().name();
|
|
|
AttendanceRuleDetails ruleDetails = ruleMap.get(weekEnMap.get(dayOfWeekName));
|
|
|
+ if(ruleDetails != null && (ruleDetails.getIsAttendance() == null || ruleDetails.getIsAttendance() == 0)){
|
|
|
+ continue;
|
|
|
+ }
|
|
|
JsonObject daysJson = new JsonObject();
|
|
|
daysJson.addProperty("date", localDate.format(dtf));
|
|
|
daysJson.addProperty("week", weekCnMap.get(dayOfWeekName));
|
|
@@ -216,18 +243,28 @@ public class AttendanceStatisticsServiceImpl extends MPJBaseServiceImpl<Attendan
|
|
|
}else if("请假".equals(attendanceRecord.getAttendanceStatus())){
|
|
|
leaveCount ++;
|
|
|
content += "请假";
|
|
|
+ }else if("不考勤".equals(attendanceRecord.getAttendanceStatus())){
|
|
|
+
|
|
|
}else{
|
|
|
absenteeCount ++;
|
|
|
content += "缺勤";
|
|
|
}
|
|
|
}
|
|
|
daysJson.addProperty("content", content);
|
|
|
+ daysJson.addProperty("sortCode", sortCode);
|
|
|
daysData.add(daysJson);
|
|
|
+ sortCode ++;
|
|
|
}
|
|
|
record.setNormalCount(normalCount);
|
|
|
record.setLeaveCount(leaveCount);
|
|
|
record.setAbsenteeCount(absenteeCount);
|
|
|
record.setDaysData(daysData.toString());
|
|
|
+ UserIdDeptNameVo deptNameVo = userDeptMap.get(record.getUserId());
|
|
|
+ if(deptNameVo != null){
|
|
|
+ record.setDeptIds(deptNameVo.getDeptIds());
|
|
|
+ record.setDeptName(deptNameVo.getDeptName());
|
|
|
+ }
|
|
|
+
|
|
|
insertList.add(record);
|
|
|
}
|
|
|
|
|
@@ -240,6 +277,7 @@ public class AttendanceStatisticsServiceImpl extends MPJBaseServiceImpl<Attendan
|
|
|
statistics = this.getById(id);
|
|
|
statistics.setStatus(1);
|
|
|
statistics.setModifyDate(new Date());
|
|
|
+ statistics.setAttendanceDays(dateList.size());
|
|
|
this.updateById(statistics);
|
|
|
}catch (Exception e){
|
|
|
Log.error(e.getMessage(), e);
|
|
@@ -255,12 +293,16 @@ public class AttendanceStatisticsServiceImpl extends MPJBaseServiceImpl<Attendan
|
|
|
|
|
|
|
|
|
|
|
|
- private List<LocalDate> getDatesBetween(LocalDate startDate, LocalDate endDate) {
|
|
|
+ private List<LocalDate> getDatesBetween(LocalDate startDate, LocalDate endDate, Map<String, AttendanceRuleDetails> ruleMap, Map<String, String> weekEnMap) {
|
|
|
List<LocalDate> dates = new ArrayList<>();
|
|
|
|
|
|
long numOfDaysBetween = ChronoUnit.DAYS.between(startDate, endDate) + 1; // +1 包含结束日期
|
|
|
for (long i = 0; i < numOfDaysBetween; i++) {
|
|
|
- dates.add(startDate.plusDays(i));
|
|
|
+ LocalDate localDate = startDate.plusDays(i);
|
|
|
+ AttendanceRuleDetails ruleDetails = ruleMap.get(weekEnMap.get(localDate.getDayOfWeek().name()));
|
|
|
+ if(ruleDetails != null && ruleDetails.getIsAttendance() != null && ruleDetails.getIsAttendance() == 1){
|
|
|
+ dates.add(localDate);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
return dates;
|
|
@@ -296,6 +338,241 @@ public class AttendanceStatisticsServiceImpl extends MPJBaseServiceImpl<Attendan
|
|
|
|
|
|
@Override
|
|
|
public byte[] recordExport(Long id) throws IOException {
|
|
|
- return new byte[0];
|
|
|
+ AttendanceStatistics statistics = this.getById(id);
|
|
|
+ List<AttendanceStatisticsRecordVo> recordList = this.getRecordList(new AttendanceStatisticsRecordDto() {{
|
|
|
+ setId(id);
|
|
|
+ }});
|
|
|
+
|
|
|
+ List<ArrayList<String>> dataList = new ArrayList<>();
|
|
|
+ int sortCode = 1;
|
|
|
+ JsonParser parser = new JsonParser();
|
|
|
+ List<String> dateList = new ArrayList<>();
|
|
|
+ List<String> weekList = new ArrayList<>();
|
|
|
+ for (AttendanceStatisticsRecordVo recordVo : recordList) {
|
|
|
+ ArrayList<String> data = new ArrayList<>();
|
|
|
+ data.add(sortCode + "");
|
|
|
+ data.add(recordVo.getName());
|
|
|
+ data.add(recordVo.getUserName());
|
|
|
+ data.add(recordVo.getDeptName());
|
|
|
+ data.add(recordVo.getNormalCount() + "");
|
|
|
+ data.add(recordVo.getLeaveCount() + "");
|
|
|
+ data.add(recordVo.getAbsenteeCount() + "");
|
|
|
+ JsonArray daysData = parser.parse(recordVo.getDaysData()).getAsJsonArray();
|
|
|
+ for (JsonElement daysDatum : daysData) {
|
|
|
+ JsonObject daysJson = daysDatum.getAsJsonObject();
|
|
|
+ data.add(daysJson.get("content").getAsString());
|
|
|
+ if(!dateList.contains(daysJson.get("date").getAsString())){
|
|
|
+ dateList.add(daysJson.get("date").getAsString());
|
|
|
+ }
|
|
|
+ if(!weekList.contains(daysJson.get("week").getAsString())){
|
|
|
+ weekList.add(daysJson.get("week").getAsString());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ dataList.add(data);
|
|
|
+ }
|
|
|
+
|
|
|
+ int allColumn = 7 + statistics.getAttendanceDays();//总列数
|
|
|
+ Workbook workbook = new XSSFWorkbook();
|
|
|
+ // 创建一个工作表(sheet)
|
|
|
+ String sheetName = "数据";
|
|
|
+ Sheet sheet = workbook.createSheet(sheetName);
|
|
|
+
|
|
|
+ // 第一行表头
|
|
|
+ createFirstTitle(workbook, sheet, allColumn - 1);
|
|
|
+ // 第二行表头
|
|
|
+ createSecondTitle(workbook, sheet, statistics, 3);
|
|
|
+ // 第三行表头
|
|
|
+ createThirdTitle(workbook, sheet, weekList);
|
|
|
+ // 第四行表头
|
|
|
+ createFourthTitle(workbook, sheet, 7, dateList);
|
|
|
+ //生成数据
|
|
|
+ int dataRowNumber = 4;
|
|
|
+
|
|
|
+ for (ArrayList<String> rowData : dataList) {
|
|
|
+ Row dataRow = sheet.createRow(dataRowNumber);
|
|
|
+ for (int i = 0; i < rowData.size(); i ++){
|
|
|
+ String content = rowData.get(i);
|
|
|
+ Font font = workbook.createFont();
|
|
|
+ font.setBold(false);// 设置为粗体
|
|
|
+ font.setFontName("宋体");
|
|
|
+ if(content.contains("缺勤")){
|
|
|
+ font.setColor(IndexedColors.RED.getIndex()); // 设置字体颜色为红色
|
|
|
+ }else if(content.contains("正常")){
|
|
|
+ font.setColor(IndexedColors.BLUE.getIndex()); // 设置字体颜色为蓝色
|
|
|
+ }else if(content.contains("请假")){
|
|
|
+ font.setColor(IndexedColors.YELLOW.getIndex()); // 设置字体颜色为黄色
|
|
|
+ }
|
|
|
+ font.setFontHeightInPoints((short)12);
|
|
|
+
|
|
|
+ CellStyle cellStyle = workbook.createCellStyle();
|
|
|
+ cellStyle.setFont(font); // 将字体应用到样式
|
|
|
+ cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
|
|
|
+
|
|
|
+ Cell row1cell2 = dataRow.createCell(i);
|
|
|
+ row1cell2.setCellValue(content);
|
|
|
+ row1cell2.setCellStyle(cellStyle);
|
|
|
+ }
|
|
|
+
|
|
|
+ dataRowNumber ++;
|
|
|
+ }
|
|
|
+ //写入文件
|
|
|
+ ByteArrayOutputStream bot = new ByteArrayOutputStream();
|
|
|
+ workbook.write(bot);
|
|
|
+ return bot.toByteArray();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建第一行表头
|
|
|
+ * @param workbook
|
|
|
+ * @param sheet
|
|
|
+ * @param mergeCoulmn 合并后面多少列(不包含自己)
|
|
|
+ */
|
|
|
+ void createFirstTitle(Workbook workbook, Sheet sheet, int mergeCoulmn) {
|
|
|
+ int rowNumber = 0;
|
|
|
+ Font font = workbook.createFont();
|
|
|
+ font.setBold(true);// 设置为粗体
|
|
|
+ font.setFontName("宋体");
|
|
|
+ //font.setColor(IndexedColors.RED.getIndex()); // 设置字体颜色为红色
|
|
|
+ font.setFontHeightInPoints((short)24);
|
|
|
+
|
|
|
+ CellStyle cellStyle = workbook.createCellStyle();
|
|
|
+ cellStyle.setFont(font); // 将字体应用到样式
|
|
|
+ cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
|
|
|
+ cellStyle.setAlignment(HorizontalAlignment.CENTER);
|
|
|
+
|
|
|
+ Row row = sheet.createRow(rowNumber);
|
|
|
+ //合并第一行的列
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(rowNumber, rowNumber, 0, mergeCoulmn));
|
|
|
+
|
|
|
+ //3、处理表头
|
|
|
+ String title1 = "坐班考勤 - 汇总统计";
|
|
|
+ // 创建单元格并设置值
|
|
|
+ Cell cell = row.createCell(0);
|
|
|
+ cell.setCellValue(title1);
|
|
|
+ cell.setCellStyle(cellStyle);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 生成第二行表头
|
|
|
+ * @param workbook
|
|
|
+ * @param sheet
|
|
|
+ * @param statistics
|
|
|
+ * @param mergeCoulmn 合并后面多少列(不包含自己)
|
|
|
+ */
|
|
|
+ void createSecondTitle(Workbook workbook, Sheet sheet, AttendanceStatistics statistics, int mergeCoulmn) {
|
|
|
+ int rowNumber = 1;
|
|
|
+ Font font = workbook.createFont();
|
|
|
+ font.setFontName("宋体");
|
|
|
+ font.setFontHeightInPoints((short)12);
|
|
|
+
|
|
|
+ CellStyle cellStyle = workbook.createCellStyle();
|
|
|
+ cellStyle.setFont(font); // 将字体应用到样式
|
|
|
+ cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
|
|
|
+ cellStyle.setAlignment(HorizontalAlignment.CENTER);
|
|
|
+
|
|
|
+ Row row1 = sheet.createRow(rowNumber);
|
|
|
+ Cell row1cell1 = row1.createCell(0);
|
|
|
+ DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
|
+ String content = "查询的考勤日期范围:" + statistics.getStartDate().format(dtf) + "至" + statistics.getEndDate() + ";";
|
|
|
+ if(statistics.getTimePeriod() == 1){
|
|
|
+ content += "时间段:上午";
|
|
|
+ }else if(statistics.getTimePeriod() == 2){
|
|
|
+ content += "时间段:下午";
|
|
|
+ }
|
|
|
+ row1cell1.setCellValue(content);
|
|
|
+ row1cell1.setCellStyle(cellStyle);
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(rowNumber, rowNumber, 0, mergeCoulmn));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 生成第三行表头
|
|
|
+ * 表头:序号、姓名、工号、部门、正常考勤次数、请假次数、缺勤次数,后续周几
|
|
|
+ * @param workbook
|
|
|
+ * @param sheet
|
|
|
+ * @param weekList 周几
|
|
|
+ */
|
|
|
+ void createThirdTitle(Workbook workbook, Sheet sheet, List<String> weekList) {
|
|
|
+ int rowNumber = 2;
|
|
|
+ Font font = workbook.createFont();
|
|
|
+ font.setFontName("宋体");
|
|
|
+ font.setFontHeightInPoints((short)12);
|
|
|
+
|
|
|
+ CellStyle cellStyle = workbook.createCellStyle();
|
|
|
+ cellStyle.setFont(font); // 将字体应用到样式
|
|
|
+ cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
|
|
|
+ cellStyle.setAlignment(HorizontalAlignment.CENTER);
|
|
|
+
|
|
|
+ Row row1 = sheet.createRow(rowNumber);
|
|
|
+ Cell row1cell1 = row1.createCell(0);
|
|
|
+ row1cell1.setCellValue("序号");
|
|
|
+ row1cell1.setCellStyle(cellStyle);
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(rowNumber, rowNumber + 1, 0, 0));
|
|
|
+
|
|
|
+ Cell row1cell2 = row1.createCell(1);
|
|
|
+ row1cell2.setCellValue("姓名");
|
|
|
+ row1cell2.setCellStyle(cellStyle);
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(rowNumber, rowNumber + 1, 1, 1));
|
|
|
+
|
|
|
+ Cell row1cell3 = row1.createCell(2);
|
|
|
+ row1cell3.setCellValue("工号");
|
|
|
+ row1cell3.setCellStyle(cellStyle);
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(rowNumber, rowNumber + 1, 2, 2));
|
|
|
+
|
|
|
+ Cell row1cell4 = row1.createCell(3);
|
|
|
+ row1cell4.setCellValue("组织机构");
|
|
|
+ row1cell4.setCellStyle(cellStyle);
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(rowNumber, rowNumber + 1, 3, 3));
|
|
|
+
|
|
|
+ Cell row1cell5 = row1.createCell(4);
|
|
|
+ row1cell5.setCellValue("正常考勤次数");
|
|
|
+ row1cell5.setCellStyle(cellStyle);
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(rowNumber, rowNumber + 1, 4, 4));
|
|
|
+
|
|
|
+ Cell row1cell6 = row1.createCell(5);
|
|
|
+ row1cell6.setCellValue("请假次数");
|
|
|
+ row1cell6.setCellStyle(cellStyle);
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(rowNumber, rowNumber + 1, 5, 5));
|
|
|
+
|
|
|
+ Cell row1cell7 = row1.createCell(6);
|
|
|
+ row1cell7.setCellValue("缺勤次数");
|
|
|
+ row1cell7.setCellStyle(cellStyle);
|
|
|
+ sheet.addMergedRegion(new CellRangeAddress(rowNumber, rowNumber + 1, 6, 6));
|
|
|
+
|
|
|
+ int cellNumber = 7;
|
|
|
+ for (String dayOfWeek : weekList) {
|
|
|
+ Cell row1cell = row1.createCell(cellNumber);
|
|
|
+ row1cell.setCellValue(dayOfWeek);
|
|
|
+ row1cell.setCellStyle(cellStyle);
|
|
|
+ cellNumber ++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ *
|
|
|
+ * @param workbook
|
|
|
+ * @param sheet
|
|
|
+ * @param startColumn 开始列
|
|
|
+ * @param dateList 2024年10月20日
|
|
|
+ */
|
|
|
+ void createFourthTitle(Workbook workbook, Sheet sheet, int startColumn, List<String> dateList) {
|
|
|
+ int rowNumber = 3;
|
|
|
+ Font font = workbook.createFont();
|
|
|
+ font.setFontName("宋体");
|
|
|
+ font.setFontHeightInPoints((short)12);
|
|
|
+
|
|
|
+ CellStyle cellStyle = workbook.createCellStyle();
|
|
|
+ cellStyle.setFont(font); // 将字体应用到样式
|
|
|
+ cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
|
|
|
+ cellStyle.setAlignment(HorizontalAlignment.CENTER);
|
|
|
+
|
|
|
+ Row row1 = sheet.createRow(rowNumber);
|
|
|
+
|
|
|
+ for (String date : dateList) {
|
|
|
+ Cell row1cell = row1.createCell(startColumn);
|
|
|
+ row1cell.setCellValue(date);
|
|
|
+ row1cell.setCellStyle(cellStyle);
|
|
|
+ startColumn ++;
|
|
|
+ }
|
|
|
}
|
|
|
}
|