yusm пре 5 дана
родитељ
комит
871a3c9e24

+ 6 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/controller/AttendanceController.java

@@ -38,5 +38,11 @@ public class AttendanceController {
         return attendanceService.getCalendarByMonth(month);
     }
 
+    //考勤记录导出
+    @RequestMapping("/exportAttendanceData")
+    public HttpRespMsg exportAttendanceData(String month,HttpServletRequest request){
+        return attendanceService.exportAttendanceData(month,request);
+    }
+
 }
 

+ 2 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/AttendanceService.java

@@ -20,4 +20,6 @@ public interface AttendanceService extends IService<Attendance> {
     HttpRespMsg importAttendanceData(String month, MultipartFile file, HttpServletRequest request);
 
     HttpRespMsg getCalendarByMonth(String month);
+
+    HttpRespMsg exportAttendanceData(String month, HttpServletRequest request);
 }

+ 420 - 12
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/impl/AttendanceServiceImpl.java

@@ -3,16 +3,15 @@ package com.management.platform.service.impl;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.management.platform.entity.*;
 import com.management.platform.mapper.AttendanceMapper;
+import com.management.platform.mapper.WxCorpInfoMapper;
 import com.management.platform.service.*;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.management.platform.util.ExcelUtil;
 import com.management.platform.util.HttpRespMsg;
-import com.management.platform.util.MessageUtils;
 import lombok.extern.slf4j.Slf4j;
-import org.apache.poi.EncryptedDocumentException;
-import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
 import org.apache.poi.ss.usermodel.*;
-import org.apache.poi.xssf.usermodel.XSSFCell;
+
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.StringUtils;
@@ -20,18 +19,20 @@ import org.springframework.web.multipart.MultipartFile;
 
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
-import java.io.IOException;
+
 import java.io.InputStream;
-import java.text.DateFormat;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.time.DayOfWeek;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.YearMonth;
+import java.math.BigDecimal;
+
+import java.time.*;
+import java.time.chrono.ChronoLocalDateTime;
 import java.time.format.DateTimeFormatter;
+import java.time.format.TextStyle;
 import java.util.*;
 import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+import static com.management.platform.constant.Constant.*;
+import static com.management.platform.service.impl.AttendanceStaffServiceImpl.calculateOvertimeHours;
 
 /**
  * <p>
@@ -47,6 +48,9 @@ public class AttendanceServiceImpl extends ServiceImpl<AttendanceMapper, Attenda
     @Resource
     private UserService userService;
 
+    @Resource
+    private DepartmentService departmentService;
+
     @Resource
     private AttendanceService attendanceService;
 
@@ -56,6 +60,22 @@ public class AttendanceServiceImpl extends ServiceImpl<AttendanceMapper, Attenda
     @Resource
     private AttendanceStaffService attendanceStaffService;
 
+    @Resource
+    private ApplyFormService applyFormService;
+
+    @Value(value = "${upload.path}")
+    private String path;
+
+    @Resource
+    WxCorpInfoMapper wxCorpInfoMapper;
+
+    private static final List<String> holidays = Arrays.asList("2025-01-01",
+            "2025-01-28", "2025-01-29", "2025-01-30", "2025-01-31", "2025-02-03", "2025-02-04",
+            "2025-04-04",
+            "2025-05-01", "2025-05-02", "2025-05-05",
+            "2025-06-02",
+            "2025-10-01", "2025-10-02", "2025-10-03", "2025-10-06", "2025-10-07", "2025-10-08" );
+
     @Override
     @Transactional(rollbackFor = Exception.class)
     public HttpRespMsg importAttendanceData(String month, MultipartFile file, HttpServletRequest request) {
@@ -224,6 +244,337 @@ public class AttendanceServiceImpl extends ServiceImpl<AttendanceMapper, Attenda
         return msg;
     }
 
+    @Override
+    public HttpRespMsg exportAttendanceData(String month, HttpServletRequest request) {
+        HttpRespMsg msg=new HttpRespMsg();
+        User user = userService.getById(request.getHeader("token"));
+        WxCorpInfo wxCorpInfo = wxCorpInfoMapper.selectOne(new QueryWrapper<WxCorpInfo>().eq("company_id", user.getCompanyId()));
+
+        Map<String, Object> monthInfo = getMonthInfo(month, holidays);
+        String firstDay = monthInfo.get("firstDay").toString();
+        String lastDay = monthInfo.get("lastDay").toString();
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM");
+        DateTimeFormatter formatter1 = DateTimeFormatter.ofPattern("yyyy/MM/dd");
+        DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+        YearMonth yearMonth = YearMonth.parse(month, formatter);
+        LocalDate startDate = yearMonth.atDay(1);
+        LocalDate endDate = startDate.plusMonths(1);
+        int year = yearMonth.getYear();
+        int monthValue = yearMonth.getMonthValue();
+        String title=year+"年"+monthValue+"月考勤表";
+
+        ArrayList<ArrayList<String>> list = new ArrayList<>();
+        List<User> userList = userService.list(new QueryWrapper<User>().eq("is_active", 1));
+        List<Department> departmentList = departmentService.list(new QueryWrapper<Department>());
+        List<AttendanceStaff> staffList = attendanceStaffService.list(new QueryWrapper<AttendanceStaff>().between("clock_date", firstDay, lastDay));
+        List<ApplyForm> applyFormList = applyFormService.getListByFirstDateAndLastDate(startDate, endDate);
+
+        for (int i = 0; i < userList.size(); i++) {
+            ArrayList<String> strings = new ArrayList<>();
+            strings.add((i+1)+"");
+            User u = userList.get(i);
+            strings.add(u.getJobNumber());//员工编号
+            strings.add(u.getName());
+            Optional<Department> deptFirst = departmentList.stream().filter(d -> u.getDepartmentId() != null && d.getDepartmentId().equals(u.getDepartmentId())).findFirst();
+            if (deptFirst.isPresent()) {
+                strings.add(deptFirst.get().getDepartmentName());
+            }else {
+                strings.add("");
+            }
+            strings.add(u.getInductionDate()==null?"":u.getInductionDate().format(formatter1));//入职日期
+            strings.add(u.getInactiveDate()==null?"":u.getInactiveDate().format(formatter1));//离职日期
+            strings.add("");//备注
+
+            List<AttendanceStaff> staffCollect = staffList.stream().filter(s -> s.getJobNumber().equals(u.getJobNumber())).collect(Collectors.toList());
+            strings.add(staffCollect.size()+"");//实际出勤天
+
+            BigDecimal total8 = getDecimal(applyFormList,"病假",u.getJobNumber());
+            strings.add(total8.toString());
+            BigDecimal total9 = getDecimal(applyFormList,"带薪假",u.getJobNumber());
+            strings.add(total9.toString());
+            BigDecimal total10 = getDecimal(applyFormList,"育儿假",u.getJobNumber());
+            strings.add(total10.toString());
+            BigDecimal total11 = getDecimal(applyFormList,"工伤假",u.getJobNumber());
+            strings.add(total11.toString());
+            BigDecimal total12 = getDecimal(applyFormList,"旷工",u.getJobNumber());
+            strings.add(total12.toString());
+            BigDecimal total13 = getDecimal(applyFormList,"事假",u.getJobNumber());
+            strings.add(total13.toString());
+            BigDecimal total14 = getDecimal(applyFormList,"排休",u.getJobNumber());
+            strings.add(total14.toString());
+            BigDecimal total15 = getDecimal(applyFormList,"调休假",u.getJobNumber());
+            strings.add(total15.toString());
+            BigDecimal total16 = getDecimal(applyFormList,"年假",u.getJobNumber());
+            strings.add(total16.toString());
+            BigDecimal total17 = getDecimal(applyFormList,"出差",u.getJobNumber());
+            strings.add(total17.toString());
+            int countLess=0;
+            int countMore=0;
+            for (AttendanceStaff staff : staffCollect) {
+                Integer type = staff.getAttendanceType();
+                LocalDateTime clockStartTime = staff.getClockStartTime();
+                LocalDateTime clockEndTime = staff.getClockEndTime();
+                LocalTime startTime = clockStartTime.toLocalTime();
+                LocalTime endTime = clockEndTime.toLocalTime();
+
+                if (type == BAI_BAN) {
+                    if (startTime.isAfter(LocalTime.of(8,0,0))) {
+                        Duration duration = Duration.between(LocalTime.of(8,0,0),startTime );
+                        long v = duration.toMinutes();
+                        if (v>30) {
+                            countMore++;
+                        }else {
+                            countLess++;
+                        }
+                    }
+                    if (endTime.isBefore(LocalTime.of(17, 0, 0))) {
+                        Duration duration = Duration.between(endTime,LocalTime.of(17,0,0) );
+                        long v = duration.toMinutes();
+                        if (v>30) {
+                            countMore++;
+                        }else {
+                            countLess++;
+                        }
+                    }
+
+                }
+                else if (type == ZHONG_BAN) {
+                    if (startTime.isAfter(LocalTime.of(13, 0, 0))) {
+                        Duration duration = Duration.between(LocalTime.of(13,0,0),startTime);
+                        long v = duration.toMinutes();
+                        if (v>30) {
+                            countMore++;
+                        }else {
+                            countLess++;
+                        }
+                    }
+
+                    if (endTime.isBefore(LocalTime.of(21, 0, 0))) {
+                        Duration duration = Duration.between(endTime,LocalTime.of(21,0,0));
+                        long v = duration.toMinutes();
+                        if (v>30) {
+                            countMore++;
+                        }else {
+                            countLess++;
+                        }
+                    }
+                }
+                else if (type == XIAO_YE_BAN) {
+                    if (startTime.isAfter(LocalTime.of(16, 0, 0))) {
+
+                        Duration duration = Duration.between(LocalTime.of(16,0,0),startTime );
+                        long v = duration.toMinutes();
+                        if (v>30) {
+                            countMore++;
+                        }else {
+                            countLess++;
+                        }
+                    }
+
+                    if (endTime.isBefore(LocalTime.of(23, 59, 59)) && endTime.isAfter(LocalTime.of(16, 0, 0))) {
+
+                        Duration duration = Duration.between(endTime,LocalTime.of(23,59, 59) );
+                        long v = duration.toMinutes();
+                        if (v>30) {
+                            countMore++;
+                        }else {
+                            countLess++;
+                        }
+                    }
+                }
+                else if (type == XIAO_YE_BAN_2) {
+                    if (startTime.isAfter(LocalTime.of(17, 0, 0))) {
+
+                        Duration duration = Duration.between(LocalTime.of(17,0,0),startTime );
+                        long v = duration.toMinutes();
+                        if (v>30) {
+                            countMore++;
+                        }else {
+                            countLess++;
+                        }
+                    }
+                    if (endTime.isBefore(LocalTime.of(23, 59, 59)) && endTime.isAfter(LocalTime.of(17, 0, 0))) {
+                        Duration duration = Duration.between(endTime,LocalTime.of(23,59, 59) );
+                        long v = duration.toMinutes();
+                        if (v>30) {
+                            countMore++;
+                        }else {
+                            countLess++;
+                        }
+                    }else if (endTime.isBefore(LocalTime.of(1, 0, 0))) {
+
+                        Duration duration = Duration.between(endTime,LocalTime.of(1,0, 0) );
+                        long v = duration.toMinutes();
+                        if (v>30) {
+                            countMore++;
+                        }else {
+                            countLess++;
+                        }
+                    }
+                }
+                else if (type == DA_YE_BAN) {
+                    if (startTime.isAfter(LocalTime.of(0, 0, 0))&&startTime.isBefore(LocalTime.of(4, 0, 0))) {
+                        Duration duration = Duration.between(LocalTime.of(0, 0, 0),startTime );
+                        long v = duration.toMinutes();
+                        if (v>30) {
+                            countMore++;
+                        }else {
+                            countLess++;
+                        }
+                    }
+                    if (endTime.isBefore(LocalTime.of(8, 0, 0))) {
+
+                        Duration duration = Duration.between(endTime,LocalTime.of(8,0, 0) );
+                        long v = duration.toMinutes();
+                        if (v>30) {
+                            countMore++;
+                        }else {
+                            countLess++;
+                        }
+                    }
+                }
+                else if (type==BAI_BAN_YI_CHANG_1) {
+                    if (startTime.isAfter(LocalTime.of(9, 0, 0))) {
+                        Duration duration = Duration.between(LocalTime.of(9,0,0),startTime );
+                        long v = duration.toMinutes();
+                        if (v>30) {
+                            countMore++;
+                        }else {
+                            countLess++;
+                        }
+                    }
+
+                    if (endTime.isBefore(LocalTime.of(18, 0, 0))) {
+                        Duration duration = Duration.between(endTime,LocalTime.of(18,0,0) );
+                        long v = duration.toMinutes();
+                        if (v>30) {
+                            countMore++;
+                        }else {
+                            countLess++;
+                        }
+                    }
+                }
+                else if (type==BAI_BAN_YI_CHANG_2) {
+                    if (startTime.isAfter(LocalTime.of(10, 0, 0))) {
+
+                        Duration duration = Duration.between(LocalTime.of(10,0,0),startTime );
+                        long v = duration.toMinutes();
+                        if (v>30) {
+                            countMore++;
+                        }else {
+                            countLess++;
+                        }
+                    }
+                    if (endTime.isBefore(LocalTime.of(19, 0, 0))) {
+
+                        Duration duration = Duration.between(endTime,LocalTime.of(19,0,0) );
+                        long v = duration.toMinutes();
+                        if (v>30) {
+                            countMore++;
+                        }else {
+                            countLess++;
+                        }
+                    }
+                }
+                else if (type == XIAO_YE_BAN_YI_CHANG_1) {
+                    if (startTime.isAfter(LocalTime.of(14, 0, 0))) {
+                        Duration duration = Duration.between(LocalTime.of(14,0,0),startTime );
+                        long v = duration.toMinutes();
+                        if (v>30) {
+                            countMore++;
+                        }else {
+                            countLess++;
+                        }
+                    }
+
+                    if (endTime.isBefore(LocalTime.of(22, 0, 0))) {
+                        Duration duration = Duration.between(endTime,LocalTime.of(22,0, 0) );
+                        long v = duration.toMinutes();
+                        if (v>30) {
+                            countMore++;
+                        }else {
+                            countLess++;
+                        }
+                    }
+                }
+                else if (type == XIAO_YE_BAN_YI_CHANG_2) {
+                    if (startTime.isAfter(LocalTime.of(15, 0, 0))) {
+                        Duration duration = Duration.between(LocalTime.of(15,0,0),startTime );
+                        long v = duration.toMinutes();
+                        if (v>30) {
+                            countMore++;
+                        }else {
+                            countLess++;
+                        }
+                    }
+
+                    if (endTime.isBefore(LocalTime.of(23, 0, 0))&&endTime.isAfter(LocalTime.of(15,0,0))) {
+                        Duration duration = Duration.between(endTime,LocalTime.of(23,0, 0) );
+                        long v = duration.toMinutes();
+                        if (v>30) {
+                            countMore++;
+                        }else {
+                            countLess++;
+                        }
+                    }else if (!endTime.isBefore(LocalTime.of(23, 0, 0))&&!endTime.isAfter(LocalTime.of(23,59,59))) {
+                        double v = calculateOvertimeHours(LocalTime.of(23, 0, 0), endTime);
+                        if (v>30) {
+                            countMore++;
+                        }else {
+                            countLess++;
+                        }
+                    }
+                    else {
+                        double v = calculateOvertimeHours(LocalTime.of(23, 0, 0), endTime);
+                        if (v>30) {
+                            countMore++;
+                        }else {
+                            countLess++;
+                        }
+                    }
+                }
+            }
+            strings.add(countLess+"");
+            strings.add(countMore+"");
+            List<ApplyForm> unDaKacollect = applyFormList.stream().filter(a -> a.getType() == 6&&a.getApplyId().equals(u.getJobNumber())).collect(Collectors.toList());
+            strings.add(unDaKacollect.size()+"");
+
+            int xiaoyeCount = (int) staffCollect.stream().filter(s -> s.getAttendanceTypeName().equals("小夜班")).count();
+            int dayeCount = (int) staffCollect.stream().filter(s -> s.getAttendanceTypeName().equals("大夜班")).count();
+            int size = staffCollect.size();
+            int other=size-xiaoyeCount-dayeCount;
+            strings.add(other+"");//其他
+            strings.add(xiaoyeCount+"");//小夜班
+            strings.add(dayeCount+"");//大夜班
+
+            BigDecimal zhouMoSum = applyFormList.stream().filter(a -> a.getApplyId().equals(u.getJobNumber())
+                            && (a.getStartTime().toLocalDate().getDayOfWeek() == DayOfWeek.SATURDAY || a.getStartTime().toLocalDate().getDayOfWeek() == DayOfWeek.SUNDAY))
+                    .map(ApplyForm::getSumTime)
+                    .reduce(BigDecimal.ZERO, BigDecimal::add);
+            BigDecimal faDingSum = applyFormList.stream().filter(a -> a.getApplyId().equals(u.getJobNumber())
+                    && holidays.contains(a.getStartTime().toLocalDate().format(formatter2)))
+                    .map(ApplyForm::getSumTime)
+                    .reduce(BigDecimal.ZERO, BigDecimal::add);
+            BigDecimal total = applyFormList.stream().filter(a -> a.getApplyId().equals(u.getJobNumber())).map(ApplyForm::getSumTime)
+                    .reduce(BigDecimal.ZERO, BigDecimal::add);
+            BigDecimal qiTaSum=total.subtract(faDingSum).subtract(zhouMoSum);
+            strings.add(zhouMoSum.toString());
+            strings.add(faDingSum.toString());
+            strings.add(qiTaSum.toString());
+
+            list.add(strings);
+        }
+
+        msg.data= ExcelUtil.exportAttendanceList(title, firstDay, lastDay, monthInfo.get("workDays").toString(), list, path);
+        return msg;
+    }
+
+    private static BigDecimal getDecimal(List<ApplyForm> applyFormList,String billName,String jobNum) {
+        return applyFormList.stream().filter(a -> a.getType() == 3
+                && a.getApplyBillName().equals(billName)
+        &&a.getApplyId().equals(jobNum)).map(ApplyForm::getSumTime).reduce(BigDecimal.ZERO, BigDecimal::add);
+    }
+
     private static String getDayWeekName(int value) {
         String dayWeekName="";
         switch (value) {
@@ -309,6 +660,7 @@ public class AttendanceServiceImpl extends ServiceImpl<AttendanceMapper, Attenda
     private List<LocalDate> getCustomHolidays(YearMonth yearMonth) {
         List<LocalDate> holidays = new ArrayList<>();
 
+        //todo 手动去维护或者数据库手动维护
         // 2025年中国法定节假日列表
         String[] holidayDates = {
                 "2025-01-01", // 元旦
@@ -329,4 +681,60 @@ public class AttendanceServiceImpl extends ServiceImpl<AttendanceMapper, Attenda
         }
         return holidays;
     }
+
+    /**
+     * 获取月份信息
+     * @param yearMonthStr 格式 "yyyy-MM"(如 "2023-05")
+     * @param holidays 法定节假日列表(如 ["2023-05-01", "2023-05-02"])
+     * @return Map<String, Object> 包含月份名称、第一天、最后一天、工作日天数
+     */
+    public static Map<String, Object> getMonthInfo(String yearMonthStr, List<String> holidays) {
+        // 解析输入
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM");
+        YearMonth yearMonth = YearMonth.parse(yearMonthStr, formatter);
+
+        // 1. 月份名称(本地化)
+        String monthName = yearMonth.getMonth().getDisplayName(TextStyle.FULL, Locale.CHINA);
+
+        // 2. 月份的第一天
+        LocalDate firstDay = yearMonth.atDay(1);
+
+        // 3. 月份的最后一天
+        LocalDate lastDay = yearMonth.atEndOfMonth();
+
+        // 4. 计算工作日天数(排除周末和法定节假日)
+        long workDays = calculateWorkDays(yearMonth, holidays);
+
+        // 返回结果
+        Map<String, Object> result = new HashMap<>();
+        result.put("monthName", monthName);  // 月份名称(如 "五月")
+        result.put("firstDay", firstDay);     // 月份第一天(LocalDate)
+        result.put("lastDay", lastDay);       // 月份最后一天(LocalDate)
+        result.put("workDays", workDays);     // 工作日天数(long)
+        return result;
+    }
+
+    /**
+     * 计算某个月的工作日天数(排除周末和法定节假日)
+     */
+    private static long calculateWorkDays(YearMonth yearMonth, List<String> holidays) {
+        // 获取月份的所有日期
+        List<LocalDate> datesInMonth = IntStream.rangeClosed(1, yearMonth.lengthOfMonth())
+                .mapToObj(day -> yearMonth.atDay(day))
+                .collect(Collectors.toList());
+
+        // 过滤:排除周末 + 法定节假日
+        return datesInMonth.stream()
+                .filter(date -> {
+                    // 1. 排除周六、周日
+                    DayOfWeek dayOfWeek = date.getDayOfWeek();
+                    if (dayOfWeek == DayOfWeek.SATURDAY || dayOfWeek == DayOfWeek.SUNDAY) {
+                        return false;
+                    }
+                    // 2. 排除法定节假日
+                    String dateStr = date.format(DateTimeFormatter.ISO_LOCAL_DATE);
+                    return !holidays.contains(dateStr);
+                })
+                .count();
+    }
 }

+ 237 - 10
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/util/ExcelUtil.java

@@ -1,23 +1,14 @@
 package com.management.platform.util;
 
-import com.management.platform.entity.CorpwxJobResult;
-import com.management.platform.entity.WxCorpInfo;
-import com.management.platform.mapper.CorpwxJobResultMapper;
-import com.management.platform.service.CorpwxJobResultService;
-import com.management.platform.service.WxCorpInfoService;
-import org.apache.poi.hssf.usermodel.*;
 import org.apache.poi.ss.usermodel.*;
 import org.apache.poi.ss.util.CellRangeAddress;
-import org.apache.poi.ss.util.RegionUtil;
-import org.apache.poi.xssf.streaming.SXSSFRow;
 import org.apache.poi.xssf.streaming.SXSSFWorkbook;
 import org.apache.poi.xssf.usermodel.*;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
-import javax.annotation.PostConstruct;
 import java.io.File;
 import java.io.FileOutputStream;
+import java.util.ArrayList;
 import java.util.List;
 
 @Component
@@ -593,4 +584,240 @@ public class ExcelUtil {
         }
         return true;
     }
+
+    public static String exportAttendanceList(String title, String startDate, String endDate, String dateCount, ArrayList<ArrayList<String>> list, String path) {
+        String result="系统提示:Excel文件导出成功!";
+        String fileName= title+System.currentTimeMillis()+".xlsx";
+
+        try {
+            // 创建工作簿
+            SXSSFWorkbook workBook = new SXSSFWorkbook();
+            // 创建工作类
+
+            Sheet sheetOne = workBook.createSheet();
+            workBook.setSheetName(0,title);
+            sheetOne.setDefaultColumnWidth(16);
+
+            //设置字体样式
+            Font headFont = workBook.createFont();
+            headFont.setBold(true);
+            headFont.setFontHeightInPoints((short) 10);
+            headFont.setFontName("黑体");
+
+            Font titleFont = workBook.createFont();
+            titleFont.setBold(true);
+            titleFont.setFontHeightInPoints((short) 10);
+            titleFont.setFontName("黑体");
+
+            Font font = workBook.createFont();
+            font.setFontHeightInPoints((short) 10);
+            font.setFontName("宋体");
+
+            //设置单元格样式
+            XSSFCellStyle  headStyle = (XSSFCellStyle) workBook.createCellStyle();
+            headStyle.setFont(headFont);
+            headStyle.setAlignment(HorizontalAlignment.CENTER);
+            headStyle.setVerticalAlignment(org.apache.poi.ss.usermodel.VerticalAlignment.CENTER);
+            headStyle.setWrapText(true);
+            headStyle.setBorderBottom(BorderStyle.THIN); //下边框
+            headStyle.setBorderLeft(BorderStyle.THIN);//左边框
+            headStyle.setBorderTop(BorderStyle.THIN);//上边框
+            headStyle.setBorderRight(BorderStyle.THIN);//右边框
+
+            //设置自定义颜色
+            XSSFColor xssfColor = new XSSFColor();
+            byte[] colorRgb = { (byte)118, (byte)147, (byte)60 };
+            xssfColor.setRGB(colorRgb);
+
+
+            CellStyle titleStyle = workBook.createCellStyle();
+            titleStyle.setFont(titleFont);
+            titleStyle.setAlignment(HorizontalAlignment.CENTER);
+            titleStyle.setVerticalAlignment(org.apache.poi.ss.usermodel.VerticalAlignment.CENTER);
+            titleStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);  //填充单元格
+            titleStyle.setFillForegroundColor((short)9);    //填色
+            titleStyle.setWrapText(true);
+            titleStyle.setBorderBottom(BorderStyle.THIN); //下边框
+            titleStyle.setBorderLeft(BorderStyle.THIN);//左边框
+            titleStyle.setBorderTop(BorderStyle.THIN);//上边框
+            titleStyle.setBorderRight(BorderStyle.THIN);//右边框
+
+            CellStyle cellStyle = workBook.createCellStyle();
+            cellStyle.setFont(font);
+            cellStyle.setAlignment(HorizontalAlignment.CENTER);
+            cellStyle.setVerticalAlignment(org.apache.poi.ss.usermodel.VerticalAlignment.CENTER);
+            cellStyle.setWrapText(true);
+            cellStyle.setBorderBottom(BorderStyle.THIN); //下边框
+            cellStyle.setBorderLeft(BorderStyle.THIN);//左边框
+            cellStyle.setBorderTop(BorderStyle.THIN);//上边框
+            cellStyle.setBorderRight(BorderStyle.THIN);//右边框
+
+            // 设置边框颜色(重要!)
+            cellStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());
+            cellStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());
+            cellStyle.setTopBorderColor(IndexedColors.BLACK.getIndex());
+            cellStyle.setRightBorderColor(IndexedColors.BLACK.getIndex());
+
+
+            // 创建表头行第一行
+            Row headerRowFirst = sheetOne.createRow(0);
+            int totalCount=27;
+            for (int i = 0; i < totalCount; i++) {
+                Cell cell = headerRowFirst.createCell(i);
+                cell.setCellStyle(headStyle);
+                if (i==0){
+                    cell.setCellValue("");
+                }else if(i==1){
+                    cell.setCellValue("月计薪天数");
+                }else if(i==2){
+                    cell.setCellValue(dateCount);
+                }else if(i==3){
+                    cell.setCellValue("结算开始日(每月1号)");
+                }else if(i==4){
+                    cell.setCellValue(startDate);
+                }else if(i==5){
+                    cell.setCellValue("结算结束日");
+                }else if(i==6){
+                    cell.setCellValue(endDate);
+                }else if (i==7){
+                    cell.setCellValue("原始考勤数据");
+                }else cell.setCellValue("");
+            }
+            sheetOne.addMergedRegion(new CellRangeAddress(0, 0, 7,totalCount-1 ));//合并第一行
+
+            // 创建表头行第二行
+            Row headerRowSecond = sheetOne.createRow(1);
+            for (int i = 0; i < totalCount; i++) {
+                Cell cell = headerRowSecond.createCell(i);
+                cell.setCellStyle(headStyle);
+                if (i==0){
+                    cell.setCellValue("");
+                }else cell.setCellValue((i));
+            }
+
+            //创建表头行第三行
+            Row headerRowThird = sheetOne.createRow(2);
+            for (int i = 0; i < totalCount; i++) {
+                Cell cell = headerRowThird.createCell(i);
+                cell.setCellStyle(headStyle);
+                if (i==0){
+                    cell.setCellValue("序号");
+                }else if(i==1){
+                    cell.setCellValue("员工编号");
+                }else if(i==2){
+                    cell.setCellValue("姓名");
+                }else if(i==3){
+                    cell.setCellValue("部门/车间/工位");
+                }else if(i==4){
+                    cell.setCellValue("入职日期");
+                }else if(i==5){
+                    cell.setCellValue("离职日期");
+                }else if(i==6){
+                    cell.setCellValue("备注");
+                }else if (i==7){
+                    cell.setCellValue("实际出勤/天");
+                }else if(i==8){
+                    cell.setCellValue("病假/h");
+                }else if(i==9){
+                    cell.setCellValue("带薪假/h");
+                }else if(i==10){
+                    cell.setCellValue("育儿假/h");
+                }else if(i==11){
+                    cell.setCellValue("工伤假/h");
+                }else if(i==12){
+                    cell.setCellValue("旷工/h");
+                }else if(i==13){
+                    cell.setCellValue("事假/h");
+                }else if (i==14){
+                    cell.setCellValue("排休/h");
+                }else if (i==15){
+                    cell.setCellValue("调(补)休/h");
+                }else if(i==16){
+                    cell.setCellValue("年休/h");
+                }else if(i==17){
+                    cell.setCellValue("出差/h");
+                }else if(i==18){
+                    cell.setCellValue("考勤违纪-次数");
+                }else if(i==19){
+                    cell.setCellValue("");
+                }else if(i==20){
+                    cell.setCellValue("");
+                }else if(i==21){
+                    cell.setCellValue("夜班次数-仅南京");
+                }else if (i==22){
+                    cell.setCellValue("");
+                }else if (i==23){
+                    cell.setCellValue("");
+                }else if(i==24){
+                    cell.setCellValue("加班数据/h");
+                }else if (i==25){
+                    cell.setCellValue("");
+                }else {
+                    cell.setCellValue("");
+                }
+            }
+            sheetOne.addMergedRegion(new CellRangeAddress(2, 2, 18, 20));//合并第三行
+            sheetOne.addMergedRegion(new CellRangeAddress(2, 2, 21, 23));//合并第三行
+            sheetOne.addMergedRegion(new CellRangeAddress(2, 2, 24, 26));//合并第三行
+
+            // 创建表头行第二行
+            Row headerRowFourth = sheetOne.createRow(3);
+            for (int i = 0; i < totalCount; i++) {
+                Cell cell = headerRowFourth.createCell(i);
+                cell.setCellStyle(headStyle);
+                if (i<18){
+                    cell.setCellValue("");
+                }else if (i==18){
+                    cell.setCellValue("迟到、早退30min以内");
+                }else if (i==19){
+                    cell.setCellValue("迟到、早退30min(含)以上");
+                }else if (i==20){
+                    cell.setCellValue("未打卡");
+                }else if (i==21){
+                    cell.setCellValue("其他/H");
+                }else if (i==22){
+                    cell.setCellValue("车间小夜");
+                }else if (i==23){
+                    cell.setCellValue("车间大夜");
+                }else if (i==24){
+                    cell.setCellValue("周末");
+                }else if (i==25){
+                    cell.setCellValue("法定");
+                }else {
+                    cell.setCellValue("平时");
+                }
+            }
+
+            //合并第三,四行
+            for (int i = 0; i < 18; i++) {
+                sheetOne.addMergedRegion(new CellRangeAddress(2, 3, i, i));
+            }
+
+
+            if (!list.isEmpty()){
+                for (int i = 0; i < list.size(); i++) {
+                    Row row = sheetOne.createRow(4+i);
+                    ArrayList<String> strings = (ArrayList<String>) list.get(i);
+                    for (int j = 0; j < strings.size(); j++) {
+                        Cell cell = row.createCell(j);
+                        cell.setCellStyle(cellStyle);
+                        cell.setCellValue(strings.get(j));
+                    }
+                }
+            }
+
+            File dir = new File(path);
+            if (!dir.exists()) {
+                dir.mkdirs();
+            }
+            FileOutputStream os = new FileOutputStream(path+fileName);//保存到本地
+            workBook.write(os);
+            os.flush();
+            os.close();
+        }catch(Exception e) {
+            System.out.println(result);
+            e.printStackTrace();
+        }
+        return "/upload/"+fileName;
+    }
 }