Просмотр исходного кода

增加加班审核消息通知

QuYueTing 1 неделя назад
Родитель
Сommit
71644741fa
15 измененных файлов с 489 добавлено и 157 удалено
  1. 51 7
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/OvertimeController.java
  2. 103 53
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ReportController.java
  3. 16 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/WxCorpInfoController.java
  4. 1 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/Overtime.java
  5. 1 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/ReportService.java
  6. 5 4
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/WxCorpInfoService.java
  7. 28 11
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/DepartmentServiceImpl.java
  8. 0 3
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/FinanceServiceImpl.java
  9. 28 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ReportServiceImpl.java
  10. 81 61
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/WxCorpInfoServiceImpl.java
  11. 49 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/util/DateTimeUtil.java
  12. 11 1
      fhKeeper/formulahousekeeper/timesheet/src/views/financeAudit/financeAudit.vue
  13. 45 4
      fhKeeper/formulahousekeeper/timesheet/src/views/workReport/daily.vue
  14. 66 6
      fhKeeper/formulahousekeeper/timesheet_h5/src/views/edit/index.vue
  15. 4 4
      fhKeeper/formulahousekeeper/timesheet_h5/src/views/project/edit.vue

+ 51 - 7
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/OvertimeController.java

@@ -4,16 +4,13 @@ package com.management.platform.controller;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.management.platform.entity.Department;
-import com.management.platform.entity.DepartmentAuditor;
-import com.management.platform.entity.Overtime;
-import com.management.platform.entity.User;
+import com.management.platform.entity.*;
 import com.management.platform.mapper.DepartmentAuditorMapper;
 import com.management.platform.mapper.DepartmentMapper;
 import com.management.platform.mapper.UserMapper;
-import com.management.platform.service.OvertimeService;
-import com.management.platform.service.SysFunctionService;
-import com.management.platform.service.UserService;
+import com.management.platform.mapper.WxCorpInfoMapper;
+import com.management.platform.service.*;
+import com.management.platform.service.impl.WxCorpInfoServiceImpl;
 import com.management.platform.util.HttpRespMsg;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.util.StringUtils;
@@ -58,6 +55,10 @@ public class OvertimeController {
     private UserMapper userMapper;
     @Resource
     private DepartmentAuditorMapper departmentAuditorMapper;
+    @Resource
+    private WxCorpInfoService wxCorpInfoService;
+    @Resource
+    private SysRoleFunctionService sysRoleFunctionService;
 
     /**
      * 分页查询加班列表
@@ -310,6 +311,8 @@ public class OvertimeController {
         boolean success = overtimeService.save(overtime);
         if (!success) {
             msg.setError("新增加班记录失败");
+        } else {
+            sendApproveNotification(currentUser.getCompanyId(), overtime);
         }
         return msg;
     }
@@ -351,10 +354,43 @@ public class OvertimeController {
         boolean success = overtimeService.updateById(overtime);
         if (!success) {
             msg.setError("修改加班记录失败");
+        } else {
+            sendApproveNotification(currentUser.getCompanyId(), overtime);
         }
         return msg;
     }
 
+    //发送审核通知消息
+    private void sendApproveNotification(Integer companyId, Overtime overtime) {
+        WxCorpInfo wxCorpInfo = wxCorpInfoService.getOne(new QueryWrapper<WxCorpInfo>().eq("company_id", companyId));
+        if (wxCorpInfo != null) {
+            //发送企业微信消息提醒,给审核人发送消息
+            if (overtime.getStatus() == 0) {
+                //待HR审核,检查有一级审核权限的人
+                SysFunction function = sysFunctionService.getOne(new QueryWrapper<SysFunction>().eq("id", "一级审核"));
+                List<SysRoleFunction> list = sysRoleFunctionService.list(new QueryWrapper<SysRoleFunction>().eq("function_id", function));
+                List<Integer> roleIds = list.stream().map(SysRoleFunction::getRoleId).collect(Collectors.toList());
+                if (roleIds.size() > 0) {
+                    List<User> userList = userMapper.selectList(new QueryWrapper<User>().eq("company_id", companyId).in("role_id", roleIds));
+                    if (userList.size() > 0) {
+                        String wxUserIds = userList.stream().map(User::getCorpwxUserid).collect(Collectors.joining("|"));
+                        wxCorpInfoService.sendWXCorpMsg(wxCorpInfo, wxUserIds,  "有加班单待您审核,请及时处理", null, WxCorpInfoServiceImpl.TEXT_CARD_MSG_OVERTIME_APPLY);
+                    }
+                }
+            } else if (overtime.getStatus() == 1) {
+                //审核通过,检查有二级审核权限的人
+                String auditorId = overtime.getCurrentDeptAuditorId();
+                if (auditorId != null) {
+                    User user = userMapper.selectById(auditorId);
+                    if (user != null) {
+                        String wxUserIds = user.getCorpwxUserid();
+                        wxCorpInfoService.sendWXCorpMsg(wxCorpInfo, wxUserIds,  "有加班单待您审核,请及时处理", null, WxCorpInfoServiceImpl.TEXT_CARD_MSG_OVERTIME_APPLY);
+                    }
+                }
+            }
+        }
+    }
+
     /**
      * 删除加班记录
      *
@@ -485,11 +521,13 @@ public class OvertimeController {
                 }
 //                overtime.setStatus(2);//最终审核通过了
             }
+            sendApproveNotification(overtime.getCompanyId(), overtime);
         } else {
             overtime.setStatus(3);//驳回
             if (!StringUtils.isEmpty(denyReason)) {
                 overtime.setDenyReason(denyReason);
             }
+            sendDenyNotification(overtime);
         }
         boolean success = overtimeService.updateById(overtime);
         if (!success) {
@@ -514,4 +552,10 @@ public class OvertimeController {
         return msg;
     }
 
+    private void sendDenyNotification(Overtime overtime) {
+        WxCorpInfo wxCorpInfo = wxCorpInfoService.getOne(new QueryWrapper<WxCorpInfo>().eq("company_id", overtime.getCompanyId()));
+        User user = userMapper.selectById(overtime.getUserId());
+        wxCorpInfoService.sendWXCorpMsg(wxCorpInfo, user.getCorpwxUserid(),  "有加班单被驳回:"+overtime.getDenyReason(), null, WxCorpInfoServiceImpl.TEXT_CARD_MSG_OVERTIME_DENY);
+    }
+
 }

+ 103 - 53
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ReportController.java

@@ -506,8 +506,11 @@ public class ReportController {
                                   String weeklyAttachment,
                                   String[] extraField4,
                                   String[] extraField5,
-                                  Boolean abnormalTime,
-                                  String[] constructionStagesStr //柘中定制的施工进度
+                                  @RequestParam (required = false, defaultValue = "false") Boolean abnormalTime,
+                                  String[] constructionStagesStr, //柘中定制的施工进度
+                                  String abnormalStartTime,//补考勤上班时间
+                                  String abnormalEndTime, //补考勤下班时间
+                                  Integer abnormalEndDay //下班是否为次日:0-当日,1-次日
                                     ) {
         List<Report> reportList = new ArrayList<>();
         String token = request.getHeader("Token");
@@ -1515,7 +1518,6 @@ public class ReportController {
             httpRespMsg.setError(MessageUtils.message("access.verificationError"));
             return httpRespMsg;
         }
-        //校验工作时长
         for (Report report : reportList) {
             if (report.getWorkingTime() == null) {
                 HttpRespMsg httpRespMsg = new HttpRespMsg();
@@ -1523,65 +1525,81 @@ public class ReportController {
                 httpRespMsg.setError(MessageUtils.message("profession.duration"));
                 return httpRespMsg;
             }
-
-            if (report.getIsOvertime() != null && report.getIsOvertime() == 1) {
-                if (report.getOvertimeHours() <= 0) {
-                    HttpRespMsg httpRespMsg = new HttpRespMsg();
-                    //httpRespMsg.setError("加班时长必须大于0");
-                    httpRespMsg.setError(MessageUtils.message("profession.workDurationError"));
-                    return httpRespMsg;
-                } else if (report.getOvertimeHours() - report.getWorkingTime() > 0.1) {
-
-                    HttpRespMsg httpRespMsg = new HttpRespMsg();
-                    DecimalFormat decimalFormat = new DecimalFormat("0.0");
-                    decimalFormat.setRoundingMode(RoundingMode.HALF_UP);
-                    //httpRespMsg.setError("加班时长("+report.getOvertimeHours()+"h)不能超过工作时长("+report.getWorkingTime()+"h)");
-                    httpRespMsg.setError(MessageUtils.message("profession.OvertimeHoursError",decimalFormat.format(report.getOvertimeHours()),
-                            decimalFormat.format(report.getWorkingTime())));
-                    return httpRespMsg;
-                }
-            }
         }
-        //如果开启了加班时长校验
-        if(comTimeType.getFillOvertime()==1){
-            if (comTimeType.getWorkOvertimeNeedCheck()==1) {
-                for (Report report : reportList) {
-                    if(WorkDayCalculateUtils.isWorkDay(report.getCreateDate())){
+
+        if (!abnormalTime) {//非异常填报,需要校验加班时长
+            //校验工作时长
+            for (Report report : reportList) {
+                if (report.getIsOvertime() != null && report.getIsOvertime() == 1) {
+                    if (report.getOvertimeHours() <= 0) {
                         HttpRespMsg httpRespMsg = new HttpRespMsg();
-                        double sum = reportList.stream().filter(rl -> rl.getCreateDate().equals(report.getCreateDate()) && rl.getCreatorId().equals(report.getCreatorId())).mapToDouble(Report::getWorkingTime).sum();
-                        BigDecimal bigDecimal=new BigDecimal(sum);
-                        bigDecimal=bigDecimal.subtract(new BigDecimal(comTimeType.getAllday()));
-                        if(report.getOvertimeHours() != null && report.getOvertimeHours()>0 && report.getOvertimeHours()-bigDecimal.doubleValue() > 0.001){
-                            httpRespMsg.setError("加班时长不得超过总工作时长-正常工作时长");
-                            return httpRespMsg;
-                        }
+                        //httpRespMsg.setError("加班时长必须大于0");
+                        httpRespMsg.setError(MessageUtils.message("profession.workDurationError"));
+                        return httpRespMsg;
+                    } else if ((report.getOvertimeHours() - report.getWorkingTime() > 0.1)) {
+                        HttpRespMsg httpRespMsg = new HttpRespMsg();
+                        DecimalFormat decimalFormat = new DecimalFormat("0.0");
+                        decimalFormat.setRoundingMode(RoundingMode.HALF_UP);
+                        //httpRespMsg.setError("加班时长("+report.getOvertimeHours()+"h)不能超过工作时长("+report.getWorkingTime()+"h)");
+                        httpRespMsg.setError(MessageUtils.message("profession.OvertimeHoursError",decimalFormat.format(report.getOvertimeHours()),
+                                decimalFormat.format(report.getWorkingTime())));
+                        return httpRespMsg;
                     }
                 }
             }
-            //校验加班时长是否超过打卡中的加班时长
-            if (draft == 0 && comTimeType.getVerifyCardOvertime() == 1) {
-                User curReporter = userMapper.selectById(reportList.get(0).getCreatorId());
-                for (Report report : reportList) {
-                    if(WorkDayCalculateUtils.isWorkDay(report.getCreateDate())){
-                        HttpRespMsg httpRespMsg = new HttpRespMsg();
-                        double overTimeSum = reportList.stream().filter(rl -> rl.getCreateDate().equals(report.getCreateDate()) && rl.getCreatorId().equals(report.getCreatorId())).mapToDouble(Report::getOvertimeHours).sum();
-                        UserCorpwxTime userCorpwxTime = userCorpwxTimeMapper.selectOne(new QueryWrapper<UserCorpwxTime>().ne("ot_status", 0).eq("corpwx_userid", curReporter.getCorpwxUserid()).eq("create_date", report.getCreateDate()));
-                        if(overTimeSum > 0){
-                            if (userCorpwxTime == null || userCorpwxTime.getOtTime() == 0) {
-                                httpRespMsg.setError("未同步到加班时长,请先补填加班申请");
-                                return httpRespMsg;
-                            } else if (overTimeSum - userCorpwxTime.getOtTime() > 0.001) {
-                                httpRespMsg.setError("填报加班时长不得超过考勤加班时长("+userCorpwxTime.getOtTime()+"h)");
+            //如果开启了加班时长校验
+            if(comTimeType.getFillOvertime()==1){
+                if (comTimeType.getWorkOvertimeNeedCheck()==1) {
+                    for (Report report : reportList) {
+                        if(WorkDayCalculateUtils.isWorkDay(report.getCreateDate())){
+                            HttpRespMsg httpRespMsg = new HttpRespMsg();
+                            double sum = reportList.stream().filter(rl -> rl.getCreateDate().equals(report.getCreateDate()) && rl.getCreatorId().equals(report.getCreatorId())).mapToDouble(Report::getWorkingTime).sum();
+                            BigDecimal bigDecimal = new BigDecimal(sum);
+                            bigDecimal=bigDecimal.subtract(new BigDecimal(comTimeType.getAllday()));
+                            if(report.getOvertimeHours() != null && report.getOvertimeHours()>0 && report.getOvertimeHours()-bigDecimal.doubleValue() > 0.001){
+                                httpRespMsg.setError("加班时长不得超过总工作时长("+sum+"h)-正常工作时长"+(comTimeType.getAllday())+"h");
                                 return httpRespMsg;
                             }
-
+                        }
+                    }
+                }
+                //校验加班时长是否超过打卡中的加班时长
+                if (draft == 0 && comTimeType.getVerifyCardOvertime() == 1) {
+                    User curReporter = userMapper.selectById(reportList.get(0).getCreatorId());
+                    for (Report report : reportList) {
+                        if(WorkDayCalculateUtils.isWorkDay(report.getCreateDate())){
+                            HttpRespMsg httpRespMsg = new HttpRespMsg();
+                            double overTimeSum = reportList.stream().filter(rl -> rl.getCreateDate().equals(report.getCreateDate()) && rl.getCreatorId().equals(report.getCreatorId())).mapToDouble(Report::getOvertimeHours).sum();
+                            UserCorpwxTime userCorpwxTime = userCorpwxTimeMapper.selectOne(new QueryWrapper<UserCorpwxTime>().ne("ot_status", 0).eq("corpwx_userid", curReporter.getCorpwxUserid()).eq("create_date", report.getCreateDate()));
+                            if(overTimeSum > 0){
+                                if (company.getPackageOvertime() == 1) {//启用了加班管理模块,去校验加班申请的时长
+                                    Overtime overtime = overtimeMapper.selectOne(new QueryWrapper<Overtime>().select("sum(duration) as duration").eq("user_id", curReporter.getId()).eq("date", report.getCreateDate()).ne("status", -1).ne("status", 3).ne("status", 4));
+                                    if (overtime == null) {
+                                        httpRespMsg.setError("请先补填加班申请单");
+                                        return httpRespMsg;
+                                    } else {
+                                        double applyOvertime = 1.0*overtime.getDuration()/3600;//转化为小时
+                                        if (Math.abs(overTimeSum - applyOvertime) > 0.001) {
+                                            httpRespMsg.setError("填报加班时长不得超过加班申请时长("+applyOvertime+"h)");
+                                            return httpRespMsg;
+                                        }
+                                    }
+                                } else {
+                                    if (userCorpwxTime == null || userCorpwxTime.getOtTime() == 0) {
+                                        httpRespMsg.setError("未同步到企微加班时长,请先补填加班申请");
+                                        return httpRespMsg;
+                                    } else if (Math.abs(overTimeSum - userCorpwxTime.getOtTime()) > 0.001) {
+                                        httpRespMsg.setError("填报加班时长不得超过考勤加班时长("+userCorpwxTime.getOtTime()+"h)");
+                                        return httpRespMsg;
+                                    }
+                                }
+                            }
                         }
                     }
                 }
             }
         }
 
-
         //如果开启了项目人天
         String warningPercentProjects = "";
         String warningLackProjects = "";
@@ -2466,9 +2484,40 @@ public class ReportController {
                 }
             }
         }
-        HttpRespMsg httpRespMsg = reportService.editReport(reportList, createDate.length > 0 ? createDate[0] : null, targetUserList, hourCost, user.getCompanyId(), summary, weeklyAttachment);
+        //校验补的考勤
+        if (company.getId() == Constant.XI_HE_CHAO_DAO_COMPANY_ID || company.getId() == Constant.XI_HE_CHAO_DAO_JIA_XING_COMPANY_ID) {
+            if (abnormalTime != null && abnormalTime) {
+                if (abnormalStartTime == null || abnormalEndTime == null || abnormalEndDay == null) {
+                    HttpRespMsg msg = new HttpRespMsg();
+                    msg.setError("补考勤上班时间、下班时间、下班是否为次日不能为空");
+                    return msg;
+                }
+                //校验上下班时间是否合法
+                if (abnormalEndDay == 0) {
+                    if (abnormalStartTime.compareTo(abnormalEndTime) >= 0) {
+                        HttpRespMsg msg = new HttpRespMsg();
+                        msg.setError("补考勤下班时间必须大于上班时间");
+                        return msg;
+                    }
+                } else {
+                    //跨天,不可超过24小时间隔
+                    if (abnormalEndTime.compareTo(abnormalStartTime) >= 0) {
+                        HttpRespMsg msg = new HttpRespMsg();
+                        msg.setError("跨天上下班不可超过24小时");
+                        return msg;
+                    }
+                }
+            }
+        }
+        HttpRespMsg httpRespMsg = reportService.editReport(reportList, createDate.length > 0 ? createDate[0] : null, targetUserList, hourCost, user.getCompanyId(), summary, weeklyAttachment, abnormalStartTime, abnormalEndTime, abnormalEndDay);
         //填报自动通过功能:【上海绎维】、【火石演示】、【博通容合】、【威派格】使用;以及设置了自动审核通过的公司
-        if (company.getId() == 862 || company.getId() == 3344 || company.getId() == 936 || comTimeType.getAutoProjectApprove()) {
+        //开启了按时间自动审核的功能,直接通过
+        boolean companySetAutoApprove = comTimeType.getReportAutoApprove() == 1 && comTimeType.getReportAutoApproveDays() == 0;
+        if (companySetAutoApprove) {
+            List<String> reportIds = reportList.stream().map(Report::getId).map(String::valueOf).collect(Collectors.toList());
+            //直接修改状态为审核通过
+            reportMapper.update(new Report().setState(1), new LambdaQueryWrapper<Report>().in(Report::getId, reportIds));
+        } else if (company.getId() == 862 || company.getId() == 3344 || company.getId() == 936 || comTimeType.getAutoProjectApprove()) {
             //项目审核人是提交人的情况,直接审核
             List<String> reportIds = new ArrayList<>();
             for (int i = 0; i<id.length; i++) {
@@ -2476,8 +2525,7 @@ public class ReportController {
                 if (oneId == -1) {
                     Report report = reportList.get(i);
                     if (report.getState() == 0) {//部门也直接审核通过
-                        if (report.getCreatorId().equals(report.getProjectAuditorId()) || (comTimeType.getAutoProjectApprove() && report.getIsDeptAudit() == 1 && report.getAuditDeptManagerid().equals(report.getCreatorId()))) {
-                            //直接审核
+                        if ((report.getCreatorId().equals(report.getProjectAuditorId()) || (comTimeType.getAutoProjectApprove() && report.getIsDeptAudit() == 1 && report.getAuditDeptManagerid().equals(report.getCreatorId())))) {
                             reportIds.add(report.getId().toString());
                         }
                     }
@@ -2528,9 +2576,11 @@ public class ReportController {
         if (company.getEnableAi()) {
             userRecentReportService.addReport(user.getId(), company.getId(), reportList);
         }
+
         return httpRespMsg;
     }
 
+
     //针对景昱,设置人员的财务工时
     private List<Report> setWorktimeFinance(TimeType comTimeType, List<Report> reportList) {
         //按周填报可能是多天的,需要按照天进行提取当天总工时

+ 16 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/WxCorpInfoController.java

@@ -5,6 +5,7 @@ import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.management.platform.entity.Overtime;
+import com.management.platform.entity.Report;
 import com.management.platform.entity.User;
 import com.management.platform.entity.WxCorpInfo;
 import com.management.platform.mapper.ReportMapper;
@@ -187,5 +188,20 @@ public class WxCorpInfoController {
         }
         return msg;
     }
+
+    @RequestMapping("/refreshUserAllowance")
+    public HttpRespMsg refreshUserAllowance(Integer companyId, String startDate, String endDate, String userId) {
+        HttpRespMsg msg = new HttpRespMsg();
+        QueryWrapper<Report> queryWrapper = new QueryWrapper<Report>().select("distinct creator_id,create_date")
+                .eq("company_id", companyId).between("create_date", startDate, endDate);
+        if (userId != null) {
+            queryWrapper.eq("creator_id", userId);
+        }
+        List<Report> reportList = reportMapper.selectList(queryWrapper);
+        int time = reportList.size() / 100 + 1;
+        wxCorpInfoService.handleUserAllowanceByReport(reportList);
+        msg.msg = "刷新餐补任务进行中...,请稍后检查报表, 大约需要" + time + "分钟";
+        return msg;
+    }
 }
 

+ 1 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/Overtime.java

@@ -110,7 +110,7 @@ public class Overtime extends Model<Overtime> {
     private String file;
 
     /**
-     * 0-待部门审核,1-待HR审核,2-审核通过,3-审核驳回, -1(已撤回), 4-已作废
+     * 0-待HR审核,1-待部门审核,2-审核通过,3-审核驳回, -1(已撤回), 4-已作废
      */
     @TableField("status")
     private Integer status;

+ 1 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/ReportService.java

@@ -38,7 +38,7 @@ public interface ReportService extends IService<Report> {
 
     HttpRespMsg getMissingCardTimeUserList(String startDate, String endDate, Integer departmentId, HttpServletRequest request);
 
-    HttpRespMsg editReport(List<Report> reportList, String date, List<User> userList, BigDecimal hourCost, Integer companyId, String summary, String weeklyAttachment);
+    HttpRespMsg editReport(List<Report> reportList, String date, List<User> userList, BigDecimal hourCost, Integer companyId, String summary, String weeklyAttachment, String abnormalStartTime, String abnormalEndTime, Integer abnormalEndDay);
 
     HttpRespMsg deleteReport(String userId, String date);
 

+ 5 - 4
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/WxCorpInfoService.java

@@ -3,14 +3,12 @@ package com.management.platform.service;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.extension.service.IService;
-import com.management.platform.entity.LeaveSheet;
-import com.management.platform.entity.User;
-import com.management.platform.entity.UserCorpwxTime;
-import com.management.platform.entity.WxCorpInfo;
+import com.management.platform.entity.*;
 import com.management.platform.util.HttpRespMsg;
 
 import javax.servlet.http.HttpServletRequest;
 import java.io.File;
+import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.util.HashMap;
 import java.util.List;
@@ -109,4 +107,7 @@ public interface WxCorpInfoService extends IService<WxCorpInfo> {
      * @return 加班审批详情列表
      */
     JSONArray getAndSaveOvertimeApprovalList(Integer companyId, String userId, String startDate, String endDate) throws Exception;
+
+    //根据员工提交日报触发,计算补贴
+    public void handleUserAllowanceByReport(List<Report> reportList);
 }

+ 28 - 11
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/DepartmentServiceImpl.java

@@ -8,10 +8,7 @@ import com.management.platform.entity.vo.DepartmentMasterVO;
 import com.management.platform.entity.vo.DepartmentVO;
 import com.management.platform.entity.vo.SysRichFunction;
 import com.management.platform.mapper.*;
-import com.management.platform.service.DepartmentService;
-import com.management.platform.service.ExcelExportService;
-import com.management.platform.service.SysRoleFunctionService;
-import com.management.platform.service.WxCorpInfoService;
+import com.management.platform.service.*;
 import com.management.platform.util.HttpRespMsg;
 import com.management.platform.util.ListUtil;
 import com.management.platform.util.MessageUtils;
@@ -53,10 +50,14 @@ public class DepartmentServiceImpl extends ServiceImpl<DepartmentMapper, Departm
     @Resource
     private SysFunctionMapper sysFunctionMapper;
     @Resource
+    private SysModuleMapper sysModuleMapper;
+    @Resource
     private DepartmentMapper departmentMapper;
     @Resource
     private DepartmentService departmentService;
     @Resource
+    private SysFunctionService sysFunctionService;
+    @Resource
     private ProjectMapper projectMapper;
     @Resource
     private ParticipationMapper participationMapper;
@@ -91,6 +92,8 @@ public class DepartmentServiceImpl extends ServiceImpl<DepartmentMapper, Departm
     private TaskFilesMapper taskFilesMapper;
     @Autowired
     private DepartmentEnableMapper departmentEnableMapper;
+    @Autowired
+    private SysRoleModuleMapper sysRoleModuleMapper;
 
     //新增部门
     @Override
@@ -540,16 +543,30 @@ public class DepartmentServiceImpl extends ServiceImpl<DepartmentMapper, Departm
         List<Department> departmentList = departmentMapper.selectList(new QueryWrapper<Department>().eq("manager_id", targetUser.getId()).eq("company_id", companyId));
         List<DepartmentOtherManager> departmentOtherManagerList = departmentOtherManagerMapper.selectList(new QueryWrapper<DepartmentOtherManager>().eq("other_manager_id", targetUser.getId()));
         List<SysRichFunction> functionAllList = sysFunctionMapper.getRoleFunctions(targetUser.getRoleId(), "查看全公司");
-        List<SysRichFunction> functionDpartList = sysFunctionMapper.getRoleFunctions(targetUser.getRoleId(), "查看负责部门");
-        List<SysRichFunction> functionTimeList = sysFunctionMapper.getRoleFunctions(targetUser.getRoleId(), "查看工时统计");
-        List<SysRichFunction> functionCostList = sysFunctionMapper.getRoleFunctions(targetUser.getRoleId(), "查看成本统计");
+//        List<SysRichFunction> functionDpartList = sysFunctionMapper.getRoleFunctions(targetUser.getRoleId(), "查看负责部门");
+
+        SysModule statisticModule = sysModuleMapper.selectOne(new QueryWrapper<SysModule>().eq("name", "工时成本统计"));
+        SysRoleModule myStatisticRole = sysRoleModuleMapper.selectOne(new QueryWrapper<SysRoleModule>().eq("role_id", targetUser.getRoleId()).eq("module_id", statisticModule.getId()));
+        boolean hasDeptPermission = false;
+        boolean hasTimePermission = false;
+        boolean hasCostPermission = false;
+        if (myStatisticRole != null) {
+            hasDeptPermission = sysFunctionService.hasPriviledge(targetUser.getRoleId(), "查看负责部门");
+            hasTimePermission = sysFunctionMapper.getRoleFunctions(targetUser.getRoleId(), "查看工时统计").size() > 0;
+            hasCostPermission = sysFunctionMapper.getRoleFunctions(targetUser.getRoleId(), "查看成本统计").size() > 0;
+        } else {//查看本部门工时也算,按照不部门负责人逻辑处理
+            hasDeptPermission = sysFunctionService.hasPriviledge(targetUser.getRoleId(), "查看本部门工时");
+            hasTimePermission = true;
+            hasCostPermission = true;
+        }
+
         //判断查看权限
         if(functionAllList.size()==0){
             deptIds=new ArrayList<>();
             //是不是要加
             deptIds.add(-1);
-            if(functionDpartList.size()>0){
-                if(functionTimeList.size()>0||functionCostList.size()>0){
+            if(hasDeptPermission){
+                if(hasTimePermission || hasCostPermission){
                     List<Integer> collect = departmentList.stream().map(dp -> dp.getDepartmentId()).distinct().collect(Collectors.toList());
                     List<Integer> otherCollect = departmentOtherManagerList.stream().map(dom -> dom.getDepartmentId()).distinct().collect(Collectors.toList());
                     collect.addAll(otherCollect);
@@ -600,13 +617,13 @@ public class DepartmentServiceImpl extends ServiceImpl<DepartmentMapper, Departm
         list.sort(Comparator.comparing(l->l.getSeq()));
         resultMap.put("totalCostMoney", totalCostMoney);
         resultMap.put("costList", list);
-        if(functionCostList.size()==0){
+        if(!hasCostPermission){
             resultMap.put("totalCostMoney",new BigDecimal(0));
             list.forEach(li->{
                 li.setCostMoney(new BigDecimal(0));
             });
         }
-        if(functionTimeList.size()==0){
+        if(!hasTimePermission){
             list.forEach(li->{
                 li.setCostTime(0.0);
             });

+ 0 - 3
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/FinanceServiceImpl.java

@@ -2516,9 +2516,6 @@ public class FinanceServiceImpl extends ServiceImpl<FinanceMapper, Finance> impl
                                         System.out.println("总时长=="+sum);
                                         for (int i=0;i<filteredList.size(); i++) {
                                             ProjectSumItem p = filteredList.get(i);
-                                            if(p.projectId==88194){
-                                                System.out.println("123123123123");
-                                            }
                                             BigDecimal ratio = new BigDecimal(p.workingTime / sum);
                                             System.out.println("+p.getWorkingtime="+p.workingTime+", project="+p.project);
                                             //避免偏差

+ 28 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ReportServiceImpl.java

@@ -7,6 +7,7 @@ import com.aliyun.dingtalkcontact_1_0.models.SearchUserResponse;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.management.platform.constant.Constant;
 import com.management.platform.entity.*;
 import com.management.platform.entity.vo.*;
 import com.management.platform.mapper.*;
@@ -1404,7 +1405,7 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
     //新增或编辑报告
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public HttpRespMsg editReport(List<Report> reportList, String date, List<User> userList, BigDecimal hourCost, Integer companyId, String summary, String weeklyAttachment) {
+    public HttpRespMsg editReport(List<Report> reportList, String date, List<User> userList, BigDecimal hourCost, Integer companyId, String summary, String weeklyAttachment, String abnormalStartTime, String abnormalEndTime, Integer abnormalEndDay) {
         HttpRespMsg httpRespMsg = new HttpRespMsg();
         TimeType timeType = timeTypeMapper.selectById(companyId);
         if ("null".equals(summary)) {
@@ -1753,6 +1754,31 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
             }
         }
 
+        //针对羲合超导,需要计算补贴
+        if (companyId == Constant.XI_HE_CHAO_DAO_COMPANY_ID || companyId == Constant.XI_HE_CHAO_DAO_JIA_XING_COMPANY_ID) {
+            if (abnormalStartTime != null && abnormalEndTime != null && abnormalEndDay != null) {
+                //保存手动添加的考勤记录,添加到企微考勤表
+                LocalDate createDate = LocalDate.parse(date);
+                UserCorpwxTime userCorpwxTime = new UserCorpwxTime();
+                User user = userMapper.selectById(reportList.get(0).getCreatorId());
+                userCorpwxTime.setCompanyId(user.getCompanyId());
+                userCorpwxTime.setWxCorpid(wxCorpInfoService.getOne(new QueryWrapper<WxCorpInfo>().eq("company_id", user.getCompanyId())).getCorpid());
+                userCorpwxTime.setCorpwxUserid(user.getCorpwxUserid());
+                userCorpwxTime.setName(user.getName());
+                userCorpwxTime.setCreateDate(createDate);
+                userCorpwxTime.setStartTime(abnormalStartTime);
+                userCorpwxTime.setEndTime(abnormalEndTime);
+                String convertEndTime = (abnormalEndDay==1?"次日":"") + abnormalEndTime;
+                userCorpwxTime.setWorkHours(DateTimeUtil.calculateWorkHours(abnormalStartTime, convertEndTime));
+                userCorpwxTime.setWeekDay(createDate.getDayOfWeek().getValue());
+                userCorpwxTime.setWeekDayTxt(DateTimeUtil.getWeekDayTxt(createDate.getDayOfWeek().getValue()));
+                //固定下拉,不能改了
+                userCorpwxTime.setModifiedByAdmin(2);
+                wxCorpInfoService.setUserCorpWxCardTime(userCorpwxTime);
+            }
+            wxCorpInfoService.handleUserAllowanceByReport(reportList);
+        }
+
         return httpRespMsg;
     }
 
@@ -15249,6 +15275,7 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                     log.setUserName(user.getName());
                     reportImportLogMapper.insert(log);
                 }
+//                wxCorpInfoService.handleUserAllowanceByReport(reportList);
             } else {
                 //msg.setError("工时数据不能为空");
                 msg.setError(MessageUtils.message("report.dataNullError"));

+ 81 - 61
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/WxCorpInfoServiceImpl.java

@@ -127,6 +127,8 @@ public class WxCorpInfoServiceImpl extends ServiceImpl<WxCorpInfoMapper, WxCorpI
     public static final int TEXT_CARD_MSG_PROJECT_REJECTED = 31;
     public static final int TEXT_CARD_MSG_PROJECT_APPROVED = 32;
     public static final int TEXT_CARD_MSG_MEMB_MISS_REPORT = 33;
+    public static final int TEXT_CARD_MSG_OVERTIME_APPLY = 34;//加班申请待审核消息
+    public static final int TEXT_CARD_MSG_OVERTIME_DENY = 35;//加班申请待审核消息
     private static Object userLock = new Object();
 
     @Value("${suitId}")
@@ -167,6 +169,8 @@ public class WxCorpInfoServiceImpl extends ServiceImpl<WxCorpInfoMapper, WxCorpI
     SysConfigMapper sysConfigMapper;
     @Resource
     TimeTypeService timeTypeService;
+    @Resource
+    private ReportMapper reportMapper;
 
     @Resource
     UserMapper userMapper;
@@ -390,6 +394,10 @@ public class WxCorpInfoServiceImpl extends ServiceImpl<WxCorpInfoMapper, WxCorpI
                     title = "日报提交提醒";
                 } else if (msgType.equals(TEXT_CARD_MSG_MEMB_MISS_REPORT)) {
                     title = "员工漏填提醒";
+                } else if (msgType.equals(TEXT_CARD_MSG_OVERTIME_APPLY)) {
+                    title = "加班申请审核提醒";
+                } else if (msgType.equals(TEXT_CARD_MSG_OVERTIME_DENY)) {
+                    title = "加班申请驳回提醒";
                 }
             } else {
                 jumpUrl = jumpUrl.replace("STATE", pageRouter);
@@ -1200,14 +1208,37 @@ public class WxCorpInfoServiceImpl extends ServiceImpl<WxCorpInfoMapper, WxCorpI
                     }
                     //处理曦合超导的加班补贴
                     if (corpInfo.getCompanyId() == Constant.XI_HE_CHAO_DAO_COMPANY_ID || corpInfo.getCompanyId() == Constant.XI_HE_CHAO_DAO_JIA_XING_COMPANY_ID || corpInfo.getCompanyId() == 8128) {
-                        handleAllowance(userCorpwxTime, baseMorningStart, baseMorningEnd, baseAfternoonStart, baseAfternoonEnd, restTime);
+//                        handleAllowance(userCorpwxTime, baseMorningStart, baseMorningEnd, baseAfternoonStart, baseAfternoonEnd, restTime);
                     }
                 }
             }
         }
     }
 
-    private void handleAllowance(UserCorpwxTime userCorpwxTime, String baseMorningStart, String baseMorningEnd, String baseAfternoonStart, String baseAfternoonEnd, double restTime) {
+    @Async
+    public void handleUserAllowanceByReport(List<Report> reportList) {
+        //从reportList中按照createDate和creatorId进行分组,去重,得到一个新的reportList, 里面的createDate和creatorId组合都是唯一的
+        List<Report> distinctReportList = new ArrayList<>();
+        for (Report report : reportList) {
+            if (!distinctReportList.stream().anyMatch(r -> r.getCreatorId().equals(report.getCreatorId()) && r.getCreateDate().equals(report.getCreateDate()))) {
+                distinctReportList.add(report);
+            }
+        }
+        for (Report item : distinctReportList) {
+            String userId = item.getCreatorId();
+            LocalDate date = item.getCreateDate();
+            //查询日报的合计加班时长
+            Report report = reportMapper.selectOne(new QueryWrapper<Report>().select("sum(overtime_hours) as overtime_hours").eq("creator_id", userId).eq("create_date", date));
+            double reportOvertime = report == null ? 0 : report.getOvertimeHours();
+            User user = userMapper.selectById(userId);
+            UserCorpwxTime userCorpwxTime = userCorpwxTimeMapper.selectOne(new QueryWrapper<UserCorpwxTime>().eq("corpwx_userid", user.getCorpwxUserid()).eq("create_date", date));
+            if (userCorpwxTime != null) {
+                handleAllowance(userCorpwxTime, "08:00", "12:00", "13:00", "17:00", 1.0, reportOvertime);
+            }
+        }
+    }
+
+    private void handleAllowance(UserCorpwxTime userCorpwxTime, String baseMorningStart, String baseMorningEnd, String baseAfternoonStart, String baseAfternoonEnd, double restTime, double reportOvertime) {
         //注意,为了方便开发,对于表overtime-allowance的type类型增加-1值,表示只有考勤加班但是无补贴。
         OvertimeAllowance allowance = new OvertimeAllowance();
         allowance.setCompanyId(userCorpwxTime.getCompanyId());
@@ -1217,6 +1248,7 @@ public class WxCorpInfoServiceImpl extends ServiceImpl<WxCorpInfoMapper, WxCorpI
         DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
         DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm");
         LocalDateTime startTime = LocalDateTime.parse(dateTimeFormatter.format(userCorpwxTime.getCreateDate()) + " " + userCorpwxTime.getStartTime(), df);
+        String endTimeStr = userCorpwxTime.getEndTime();
         LocalDateTime endTime = LocalDateTime.parse(dateTimeFormatter.format(userCorpwxTime.getCreateDate()) + " " + userCorpwxTime.getEndTime(), df);
         if (endTime.isBefore(startTime)) {
             endTime = endTime.plusDays(1);
@@ -1233,7 +1265,6 @@ public class WxCorpInfoServiceImpl extends ServiceImpl<WxCorpInfoMapper, WxCorpI
         BigDecimal bigDecimal = new BigDecimal(Duration.between(startTime,endTime).toMinutes());
         bigDecimal = bigDecimal.divide(BigDecimal.valueOf(60),1,BigDecimal.ROUND_HALF_UP);//按小时为单位
         double standWorkHours = 8.0;
-//        System.out.println("打卡时长(分钟):" + bigDecimal);
         double onDutyTime = bigDecimal.doubleValue();
         allowance.setOnDutyHours(onDutyTime);
         double time = onDutyTime;
@@ -1248,59 +1279,57 @@ public class WxCorpInfoServiceImpl extends ServiceImpl<WxCorpInfoMapper, WxCorpI
             time = 0;
         }
         allowance.setWorkHours(time);//实际工作时长
-        System.out.println("计算加班时长==" + (time - standWorkHours));
+        System.out.println("加班时长==" + reportOvertime);
         //是否是工作日加班
         if (WorkDayCalculateUtils.isWorkDay(userCorpwxTime.getCreateDate())) {
-            if (time - standWorkHours >= 0) {//小夜班情况下是正好8小时工作,所以等于也要进行判断
-                if (startTimeTxt.compareTo(baseMorningEnd) < 0) {
-                    //白班,正常工作上午来上班的情况,计算晚上加班的时间
-                    if (time - standWorkHours >= 3.0) {
-                        //当天加班,补贴20
-                        if (endTime.toLocalDate().compareTo(startTime.toLocalDate()) == 0) {
-                            allowance.setType(0);
-                            allowance.setOvertimeDuration(time - standWorkHours);
-                            allowance.setAllowance(20);
-                        } else {
-                            //跨天,加班超过凌晨了,补贴30
-                            allowance.setType(1);
-                            allowance.setOvertimeDuration(time - standWorkHours);
-                            allowance.setAllowance(30);
-                        }
-                    } else {
-                        //不足3小时
-//                        System.out.println("工作日加班不足3小时:"+(time - standWorkHours));
-                        allowance.setType(-1);
-                        allowance.setOvertimeDuration(time - standWorkHours);
-                        allowance.setAllowance(0);
-                    }
-                } else if (startTimeTxt.compareTo("16:00") >= 0) {
-                    //晚班,计算白班加班的时间
-                    if (time >= 12.0) {
-                        //大夜班,超过12小时了
-                        allowance.setType(3);
-                        allowance.setOvertimeDuration(time - standWorkHours);
-                        allowance.setAllowance(50);
+            if (startTimeTxt.compareTo(baseMorningEnd) < 0) {
+                //白班,正常工作上午来上班的情况,计算晚上加班的时间
+                if (reportOvertime >= 3.0) {
+                    //当天加班,补贴20
+                    if (endTime.toLocalDate().compareTo(startTime.toLocalDate()) == 0) {
+                        allowance.setType(0);
+                        allowance.setOvertimeDuration(reportOvertime);
+                        allowance.setAllowance(20);
                     } else {
                         //跨天,加班超过凌晨了,补贴30
-                        allowance.setType(2);
-                        allowance.setOvertimeDuration(time - standWorkHours);
+                        allowance.setType(1);
+                        allowance.setOvertimeDuration(reportOvertime);
                         allowance.setAllowance(30);
                     }
+                } else {
+                    //不足3小时
+//                        System.out.println("工作日加班不足3小时:"+(time - standWorkHours));
+                    allowance.setType(-1);
+                    allowance.setOvertimeDuration(reportOvertime);
+                    allowance.setAllowance(0);
+                }
+            } else if (startTimeTxt.compareTo("16:00") >= 0) {
+                //晚班,计算白班加班的时间
+                if (time >= 12.0) {
+                    //大夜班,超过12小时了
+                    allowance.setType(3);
+                    allowance.setOvertimeDuration(reportOvertime);
+                    allowance.setAllowance(50);
+                } else if (time >= standWorkHours && endTime.toLocalDate().isAfter(startTime.toLocalDate())) {//工作超过凌晨了
+                    //小夜班,补贴30
+                    allowance.setType(2);
+                    allowance.setOvertimeDuration(reportOvertime);
+                    allowance.setAllowance(30);
                 }
             }
         } else {
+            System.out.println(""+reportOvertime + ", " + standWorkHours + ", baseMorningEnd= "+baseMorningEnd + ", time=" + time + ", startTimeTxt=" + startTimeTxt + ", endTimeTxt=" + endTimeTxt);
             //非工作日,判断是否为全天加班
-            if (time - standWorkHours >= 0) {
+            if (reportOvertime >= standWorkHours) {
                 if (startTimeTxt.compareTo(baseMorningEnd) < 0) {
                     if (endTime.toLocalDate().isEqual(startTime.toLocalDate())) {
                         allowance.setType(4);
-                        allowance.setOvertimeDuration(time);
+                        allowance.setOvertimeDuration(reportOvertime);
                         allowance.setAllowance(20);
-//                            System.out.println("非工作日,加班白班全天");
                     } else {
                         //加班超过凌晨了
                         allowance.setType(1);
-                        allowance.setOvertimeDuration(time - standWorkHours);
+                        allowance.setOvertimeDuration(reportOvertime);
                         allowance.setAllowance(30);
                     }
                 } else if (startTimeTxt.compareTo("16:00") >= 0) {
@@ -1308,26 +1337,20 @@ public class WxCorpInfoServiceImpl extends ServiceImpl<WxCorpInfoMapper, WxCorpI
                     if (time >= 12.0) {
                         //大夜班,超过12小时了
                         allowance.setType(3);
-                        allowance.setOvertimeDuration(time);
+                        allowance.setOvertimeDuration(reportOvertime);
                         allowance.setAllowance(50);
-                    } else {
+                    } else if (time >= standWorkHours){
                         //跨天,加班超过凌晨了,补贴30
                         allowance.setType(2);
-                        allowance.setOvertimeDuration(time);
+                        allowance.setOvertimeDuration(reportOvertime);
                         allowance.setAllowance(30);
                     }
                 }
-            } else if (time > 0) {
-                //排除午休外的工作时长超过3小时,补20元
-                if (startTimeTxt.compareTo("12:00") <= 0 && endTimeTxt.compareTo("13:00") >= 0) {
-                    //午休
-                    time -= 1.0;
-                }
-                if (time >= 3.0) {
-                    allowance.setType(0);
-                    allowance.setOvertimeDuration(time);
-                    allowance.setAllowance(20);
-                }
+            } else if (reportOvertime >= 3.0) {
+                //加班工作时长超过3小时,补20元
+                allowance.setType(0);
+                allowance.setOvertimeDuration(reportOvertime);
+                allowance.setAllowance(20);
             }
         }
 
@@ -2137,7 +2160,7 @@ public class WxCorpInfoServiceImpl extends ServiceImpl<WxCorpInfoMapper, WxCorpI
                                 userCorpwxTimeMapper.updateById(ct);
                             }
                             if (corpInfo.getCompanyId() == Constant.XI_HE_CHAO_DAO_COMPANY_ID || corpInfo.getCompanyId() == Constant.XI_HE_CHAO_DAO_JIA_XING_COMPANY_ID || corpInfo.getCompanyId() == 8128) {
-                                handleAllowance(item, baseMorningStart, baseMorningEnd, baseAfternoonStart, baseAfternoonEnd, restTime);
+//                                handleAllowance(item, baseMorningStart, baseMorningEnd, baseAfternoonStart, baseAfternoonEnd, restTime);
                             }
                         }
                     } else {
@@ -2145,7 +2168,7 @@ public class WxCorpInfoServiceImpl extends ServiceImpl<WxCorpInfoMapper, WxCorpI
                             if (showLog) System.out.println("插入考勤记录"+curUserid+", "+localDate);
                             userCorpwxTimeMapper.insert(ct);
                             if (corpInfo.getCompanyId() == Constant.XI_HE_CHAO_DAO_COMPANY_ID || corpInfo.getCompanyId() == Constant.XI_HE_CHAO_DAO_JIA_XING_COMPANY_ID || corpInfo.getCompanyId() == 8128) {
-                                handleAllowance(ct, baseMorningStart, baseMorningEnd, baseAfternoonStart, baseAfternoonEnd, restTime);
+//                                handleAllowance(ct, baseMorningStart, baseMorningEnd, baseAfternoonStart, baseAfternoonEnd, restTime);
                             }
 
                         } else {
@@ -2907,12 +2930,6 @@ public class WxCorpInfoServiceImpl extends ServiceImpl<WxCorpInfoMapper, WxCorpI
         } else {
             userCorpwxTimeMapper.insert(userCorpWxCardTime);
         }
-        String baseMorningStart = "08:00";
-        String baseMorningEnd = "12:00";
-        String baseAfternoonStart = "13:00";
-        String baseAfternoonEnd = "17:00";
-        double restTime = 1.0;
-        handleAllowance(userCorpWxCardTime, baseMorningStart, baseMorningEnd, baseAfternoonStart, baseAfternoonEnd, restTime);
     }
 
     /**
@@ -3079,6 +3096,9 @@ public class WxCorpInfoServiceImpl extends ServiceImpl<WxCorpInfoMapper, WxCorpI
             String resp = ResponseEntity.getBody();
             System.out.println("返回加班审批单号==+ resp==" + resp);
             JSONObject jsonObject = JSONObject.parseObject(resp);
+            if (jsonObject.getInteger("errcode") != 0) {
+                throw new Exception("获取审批单号失败:" + jsonObject.toJSONString());
+            }
             JSONArray sp_no_list = jsonObject.getJSONArray("sp_no_list");
             jsonArray.addAll(sp_no_list);
             if(jsonObject.containsKey("new_next_cursor")){

+ 49 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/util/DateTimeUtil.java

@@ -93,6 +93,55 @@ public class DateTimeUtil {
         return date;
     }
 
+    public static double calculateWorkHours(String startTime, String endTime) {
+        // 简单计算工作时长(小时)
+        if (startTime.compareTo("08:00") < 0 && endTime.compareTo("08:00") < 0) {
+            //上下班都是八点半之前,忽略掉
+            return 0;
+        }
+
+        // 12:00-13:00为午休,中间来的得从下午上班时间开始算
+        if (startTime.compareTo("12:00") > 0 && startTime.compareTo("13:00") < 0) {
+            startTime = "13:00";
+        }
+        if (endTime.compareTo("12:00") > 0 && endTime.compareTo("13:00") < 0) {
+            endTime = "12:00";
+        }
+        String[] startParts = startTime.split(":");
+        boolean isEndNextDay = endTime.startsWith("次日");
+        if (endTime.startsWith("次日")) {
+            endTime = endTime.substring(3);
+            System.out.println("去掉次日后="+endTime);
+        }
+        String[] endParts = endTime.split(":");
+
+        int startHour = Integer.parseInt(startParts[0]);
+        int startMinute = Integer.parseInt(startParts[1]);
+        int endHour = Integer.parseInt(endParts[0]) + (isEndNextDay ? 24 : 0);
+        int endMinute = Integer.parseInt(endParts[1]);
+
+        double hours = (endHour - startHour) + (endMinute - startMinute) / 60.0;
+
+        // 减去午休时间(假设12:00-13:00为午休)
+        if (startHour <= 12 && endHour >= 13) {
+            hours -= 1;
+        }
+
+        double minPart = hours - (int)hours;
+
+        //按0.5小时对齐
+        if (minPart > 0 && minPart < 0.5) {
+            minPart = 0;
+        } else if (minPart > 0.5) {
+            minPart = 0.5;
+        }
+        hours = (int)hours + minPart;
+        //四舍五入到小数点后一位
+        BigDecimal bigDecimal = new BigDecimal(hours);
+        bigDecimal = bigDecimal.setScale(1, BigDecimal.ROUND_HALF_UP);
+        return bigDecimal.doubleValue();
+    }
+
     public static void main(String[] args) {
         LocalDate localDate = LocalDate.now();
         System.out.println(getLastDayOfYearMonth("2025-08"));

+ 11 - 1
fhKeeper/formulahousekeeper/timesheet/src/views/financeAudit/financeAudit.vue

@@ -28,7 +28,16 @@
                         <el-button type="text" @click="toDetail(scope.row)">{{ scope.row.reportYrmnth }}</el-button>
                     </template>
                 </el-table-column>
-                <el-table-column prop="reviewerName" :label="$t('other.reviewer')" align="center"></el-table-column>
+                <el-table-column prop="reviewerName" :label="$t('other.reviewer')" align="center">
+                    <template slot-scope="scope">
+                        <span v-if="user.userNameNeedTranslate == '1'">
+                            <TranslationOpenDataText type='userName' :openid='scope.row.reviewerName'></TranslationOpenDataText>
+                        </span>
+                        <span v-else>
+                            {{scope.row.reviewerName}}
+                        </span>
+                    </template>
+                </el-table-column>
                 <el-table-column prop="reviewTime" :label="$t('AuditTime')" align="center"></el-table-column>
                 <el-table-column prop="reviewStatus" :label="$t('state.states')" align="center">
                     <template slot-scope="scope">
@@ -60,6 +69,7 @@ export default {
     props: {},
     data() {
         return {
+            user: JSON.parse(sessionStorage.getItem("user")),
             tableForm: {
                 dates: [],
                 status: 0,

+ 45 - 4
fhKeeper/formulahousekeeper/timesheet/src/views/workReport/daily.vue

@@ -444,6 +444,7 @@
                             <span v-if="workForm.time">{{workForm.time.startTime}}-{{workForm.time.endTime}}, {{workForm.time.isOffiBusiness?'出差':(workForm.time.outdoorTime?'外出':'工作')}}{{workForm.time.workHours}}{{$t('time.hour')}}
                                 <span v-if="workForm.time.askLeaveTime">|&nbsp;{{ $t('other.AskForLeave') }}{{ workForm.time.askLeaveTime }}{{$t('time.hour')}}</span>
                                 <span v-if="workForm.time.otTime" style="color:#FFA500;">|&nbsp;加班{{ workForm.time.otTime }}{{$t('time.hour')}}</span>
+                                <span v-if="workForm.time.modifiedByAdmin == 2" style="color:#FFA500;">(补)</span>
                             </span>
                         </template>
                         <template v-if="user.companyId == 7536 && workForm.time"> <!--泓浒定制化显示-->
@@ -475,9 +476,33 @@
                         <!--针对羲和超导的异常填报功能-->
                         <template v-if="(user.companyId == 8555 || user.companyId ==5792)">
                             <span style="margin-left:70px;color:#666;">异常填报</span>
-                            <el-switch v-model="workForm.abnormalTime" :disabled="!canEdit"></el-switch>
+                            <el-switch v-model="workForm.abnormalTime" :disabled="!canEdit" @change="onAbnormalTimeChange"></el-switch>
                         </template>
                     </el-form-item>
+                    <!--异常填报打卡时间选择-->
+                    <el-form-item label="补考勤" v-if="(user.companyId == 8555 || user.companyId ==5792) && workForm.abnormalTime && !workForm.time && canEdit">
+                        <el-time-picker
+                            v-model="workForm.abnormalStartTime"
+                            :placeholder="'上班时间'"
+                            style="width:120px;"
+                            format="HH:mm"
+                            value-format="HH:mm"
+                            :disabled="!canEdit">
+                        </el-time-picker>
+                        <span style="margin-left:10px;margin-right:10px;">至</span>
+                        <el-select v-model="workForm.abnormalEndDay" style="width:80px;margin-right:6px;" :disabled="!canEdit">
+                            <el-option label="当日" value="0"></el-option>
+                            <el-option label="次日" value="1"></el-option>
+                        </el-select>
+                        <el-time-picker
+                            v-model="workForm.abnormalEndTime"
+                            :placeholder="'下班时间'"
+                            style="width:120px;"
+                            format="HH:mm"
+                            value-format="HH:mm"
+                            :disabled="!canEdit">
+                        </el-time-picker>
+                    </el-form-item>
                     <!--加班申请时长-->
                     <el-form-item label="加班时长" v-if="workForm.overtime"><span style="color:#FFA500;">{{ workForm.overtime.toFixed(1) }} h</span></el-form-item>
                     <!-- 000000 -->
@@ -2848,6 +2873,9 @@
                         auditUserList: [],
                     }],
                     showRefresh: false,
+                    abnormalStartTime: null,
+                    abnormalEndTime: null,
+                    abnormalEndDay: '0',
                 },
                 workRules: {
                     createDate: [{ required: true, message: this.$t('defaultText.pleaseselectaworkdate'), trigger: "change" }],
@@ -3133,6 +3161,13 @@
         },
         methods: {
             ...mapMutations(['upDataLoading']),
+            // 异常填报开关变化事件
+            onAbnormalTimeChange(val) {
+                if (val) {
+                    this.$set(this.workForm, 'abnormalStartTime', '08:00');
+                    this.$set(this.workForm, 'abnormalEndTime', '17:00');
+                }
+            },
             // 格式化内容,将换行符转换为HTML的<br>标签
             formatContent(content) {
                 if (!content) return '';
@@ -7439,7 +7474,8 @@
                                 time: list.time,
                                 showRefresh: list.showRefresh,
                                 abnormalTime: abnormalTime,
-                                overtime: list.overtime
+                                overtime: list.overtime,
+                                abnormalEndDay: '0'
                             }
                             if(res.data.timeType.type == 3) {
                                 const reportCalculationReportList = res.data.report || []
@@ -7475,7 +7511,8 @@
                                 userNames:null,
                                 time: this.report.time,
                                 showRefresh: list.showRefresh,
-                                overtime: list.overtime
+                                overtime: list.overtime,
+                                abnormalEndDay: '0'
                             }
                             if(res.data.timeType.type == 3) {
                                 copyWorkForm.totalDuration = res.data.timeType.allday
@@ -9503,7 +9540,7 @@
                         }
                         //针对凡己和景昱,苏州博海,泓浒(暂时),安及义实业 此处不校验考勤时长
                         if (this.user.companyId != 3918 && this.user.companyId != 5978 && this.user.companyId != 4281 && this.user.companyId != 7536 && this.user.companyId != 3511 && this.reportTimeType.type == 1 && this.workForm.time) {
-                            if (this.workForm.time.workHours && totalTime > parseFloat(this.workForm.time.workHours)) {
+                            if ((!this.workForm.abnormalTime) && this.workForm.time.workHours && totalTime > parseFloat(this.workForm.time.workHours)) {
                                 this.$message({
                                         message: this.$t('message.Fillinthesumofworkinghours')+(totalTime)+"h"+this.$t('message.Cannotexceedthetotalworkinghoursofattendance')+"("+this.workForm.time.workHours.toFixed(1)+"h)",
                                         type: "error"
@@ -9875,6 +9912,10 @@
                             if ((this.user.companyId == 8555 || this.user.companyId ==5792 )) {
                                 if (this.workForm.abnormalTime) {
                                     formData.append('abnormalTime', this.workForm.abnormalTime);
+                                    //补的考勤时间
+                                    formData.append('abnormalStartTime', this.workForm.abnormalStartTime);
+                                    formData.append('abnormalEndTime', this.workForm.abnormalEndTime);
+                                    formData.append('abnormalEndDay', this.workForm.abnormalEndDay);
                                 }
                             }
                         }

+ 66 - 6
fhKeeper/formulahousekeeper/timesheet_h5/src/views/edit/index.vue

@@ -37,7 +37,9 @@
                                         <span v-if="report.time.askLeaveTime">|&nbsp;请假{{ report.time.askLeaveTime
                                         }}h</span>
                                         <span v-if="report.time.otTime" style="color:#DAA520;">|&nbsp;加班{{ report.time.otTime
-                                        }}h</span></span>
+                                        }}h</span>
+                                        <span v-if="report.time.modifiedByAdmin == 2" style="color:#DAA520;">(补)</span>
+                                    </span>
                                 </template>
                             </template>
                             <template v-if="user.companyId == 7536">
@@ -66,7 +68,7 @@
                             v-if="substitute && fillingAgent.name && (user.timeType.syncDingding == 1 || user.timeType.syncCorpwxTime == 1)"></van-button>
                             <template v-if="user.companyId == 8555 || user.companyId == 5792">
                                 <span style="margin:0 10px;color:#DAA520;">异常填报</span>
-                                <van-switch v-model="form.abnormalTime" size="20px" :disabled="!canEdit" @change="$forceUpdate()"/>
+                                <van-switch v-model="form.abnormalTime" size="20px" :disabled="!canEdit" @change="onAbnormalTimeChange"/>
                             </template>
                         </template>
                         <template v-if="user.companyId == 7536">
@@ -83,6 +85,29 @@
                     <span v-else>{{report.time.startTime}}-{{report.time.endTime}}, {{report.time.workHours}}小时</span>
                 </div> -->
             </div>
+            <!-- 补考勤时间选择 -->
+            <van-cell-group v-if="(user.companyId == 8555 || user.companyId == 5792) && form.abnormalTime && !form.time && canEdit" title="补考勤">
+                <van-field readonly clickable label="上班时间" :value="form.abnormalStartTime" placeholder="请选择上班时间"
+                    @click="showAbnormalStartTimePicker = true" />
+                <van-popup v-model="showAbnormalStartTimePicker" position="bottom">
+                    <van-datetime-picker v-model="abnormalStartTimeVal" type="time" :min-hour="0" :max-hour="23"
+                        @confirm="confirmAbnormalStartTime" @cancel="showAbnormalStartTimePicker = false" />
+                </van-popup>
+                <van-field label="至" readonly>
+                    <template #input>
+                        <van-radio-group v-model="form.abnormalEndDay" direction="horizontal">
+                            <van-radio name="0">当日</van-radio>
+                            <van-radio name="1">次日</van-radio>
+                        </van-radio-group>
+                    </template>
+                </van-field>
+                <van-field readonly clickable label="下班时间" :value="form.abnormalEndTime" placeholder="请选择下班时间"
+                    @click="showAbnormalEndTimePicker = true" />
+                <van-popup v-model="showAbnormalEndTimePicker" position="bottom">
+                    <van-datetime-picker v-model="abnormalEndTimeVal" type="time" :min-hour="0" :max-hour="23"
+                        @confirm="confirmAbnormalEndTime" @cancel="showAbnormalEndTimePicker = false" />
+                </van-popup>
+            </van-cell-group>
             <van-popup v-model="showPicker" position="bottom">
                 <van-datetime-picker v-model="currentDate" type="date" :min-date="minDate" :max-date="maxDate"
                     @confirm="changeTime" @cancel="showPicker = false" />
@@ -841,7 +866,13 @@ export default {
                 groupList: [],
                 selectedEmployees: [],
                 currentIndex: 0
-            }
+            },
+
+            // 补考勤相关数据
+            showAbnormalStartTimePicker: false,
+            showAbnormalEndTimePicker: false,
+            abnormalStartTimeVal: '08:00',
+            abnormalEndTimeVal: '17:00',
         };
     },
 
@@ -3072,7 +3103,7 @@ export default {
                 for (var t = 0; t < this.form.domains.length; t++) {
                     totalTime += parseFloat(this.form.domains[t].workingTime);
                 }
-                if (!this.report.abnormalTime && this.report.time.workHours && totalTime > parseFloat(this.report.time.workHours)) {
+                if (!this.form.abnormalTime && this.report.time.workHours && totalTime > parseFloat(this.report.time.workHours)) {
                     this.$toast.fail("填报工时之和" + (totalTime) + "h不能超过考勤总工时(" + this.report.time.workHours.toFixed(1) + "h)");
                     return;
                 }
@@ -3319,7 +3350,7 @@ export default {
                     }
                 }
 
-                if (this.user.timeType.reportWorkflow) {
+                if (this.user.timeType.reportWorkflow && this.user.timeType.reportAuditType == 0) {
                     //校验部门节点是否有审核人
                     for (var t=0;t<this.form.domains[i].auditWorkflow.length; t++) {
                         var node = this.form.domains[i].auditWorkflow[t];
@@ -3365,6 +3396,12 @@ export default {
                     formData.append("abnormalTime", this.form.abnormalTime);
                 }
             }
+            // 补考勤时间字段(仅异常填报时提交)
+            if ((this.user.companyId == 8555 || this.user.companyId == 5792) && this.form.abnormalTime) {
+                formData.append("abnormalStartTime", this.form.abnormalStartTime || '');
+                formData.append("abnormalEndTime", this.form.abnormalEndTime || '');
+                formData.append("abnormalEndDay", this.form.abnormalEndDay || '0');
+            }
             if (!this.flgLg) {
                 return
             }
@@ -3626,7 +3663,30 @@ export default {
         // 取消选择人员
         cancelEmployeeSelection() {
             this.employeeSelector.show = false;
-        }
+        },
+
+        // 异常填报开关变化事件
+        onAbnormalTimeChange(val) {
+            if (val) {
+                this.$set(this.form, 'abnormalStartTime', '08:00');
+                this.$set(this.form, 'abnormalEndTime', '17:00');
+                this.$set(this.form, 'abnormalEndDay', '0');
+                this.abnormalStartTimeVal = '08:00';
+                this.abnormalEndTimeVal = '17:00';
+            }
+        },
+
+        // 确认补考勤上班时间
+        confirmAbnormalStartTime(val) {
+            this.$set(this.form, 'abnormalStartTime', val);
+            this.showAbnormalStartTimePicker = false;
+        },
+
+        // 确认补考勤下班时间
+        confirmAbnormalEndTime(val) {
+            this.$set(this.form, 'abnormalEndTime', val);
+            this.showAbnormalEndTimePicker = false;
+        },
     },
 
     mounted() {

+ 4 - 4
fhKeeper/formulahousekeeper/timesheet_h5/src/views/project/edit.vue

@@ -3,8 +3,8 @@
     <van-nav-bar title="编辑项目" left-text="返回" @click-left="back" fixed left-arrow />
     <div class="content">
         <van-form ref="projectSubmit">
-        <van-field v-model="projectDetail.projectCode" :label="user.companyId == '7030' ? '项目令号' : '项目编号'" :disabled="!editCodeAndName"></van-field>
-        <van-field v-model="projectDetail.projectName" label="项目名称" :disabled="!editCodeAndName"></van-field>
+        <van-field v-model="projectDetail.projectCode" label="项目编号" :disabled="!editCodeAndName"></van-field>
+        <van-field v-model="projectDetail.projectName" label="项目名称" :disabled="!editCodeAndName" required :rules="[{ required: true, message: '请填写项目名称' }]"></van-field>
         <!-- 主项目 -->
         <van-field label="主项目" :disabled="canOnlyModParticipator"  @click="!canOnlyModParticipator?mainProjectShow = true:''" readonly clickable v-if="user.timeType.mainProjectState == '1'">
             <template #input>
@@ -335,7 +335,7 @@ export default {
 
 
         submitProject(){
-            // this.$refs.projectSubmit.validate().then(()=>{
+            this.$refs.projectSubmit.validate().then(()=>{
                 let formData = new FormData();
                 formData.append("id", this.projectDetail.id);
                 formData.append("name", this.projectDetail.projectName);
@@ -377,7 +377,7 @@ export default {
                         this.$toast.fail('获取失败');
                     }
                 }).catch(err=> {this.$toast.clear();console.log(err)});
-            // }).catch(()=>{return})
+            }).catch(()=>{return})
         },
         deleteProject(){
             this.$dialog.confirm({