فهرست منبع

Merge branch 'master' of http://47.100.37.243:10191/wutt/manHourHousekeeper

QuYueTing 5 ماه پیش
والد
کامیت
ee4967474f

+ 1 - 1
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/contract/index.vue

@@ -122,7 +122,7 @@ async function importBusiness(param: UploadRequestOptions) {
 function exportContract() {
   allLoading.exportLoading = true
   post(EXPORT_CONTRACT, {}).then((res) => {
-    downloadFile('合同导出.xlsx', res.data)
+    downloadFile(res.data, '合同导出.xlsx')
   }).finally(() => {
     allLoading.exportLoading = false
   })

+ 8 - 5
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/UserFvTime.java

@@ -1,18 +1,18 @@
 package com.management.platform.entity;
 
 import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.extension.activerecord.Model;
-import java.time.LocalDate;
-import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableField;
-import java.io.Serializable;
-
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.experimental.Accessors;
 import org.springframework.format.annotation.DateTimeFormat;
 
+import java.io.Serializable;
+import java.time.LocalDate;
+
 /**
  * <p>
  * 
@@ -51,6 +51,9 @@ public class UserFvTime extends Model<UserFvTime> {
     @TableField("work_hours")
     private Float workHours;
 
+//    @TableField("overtime_hours")
+//    private Float overTimeHours;
+
     /**
      * 是否被标记排除异常范围
      */

+ 4 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/UserFvTimeMapper.java

@@ -2,6 +2,9 @@ package com.management.platform.mapper;
 
 import com.management.platform.entity.UserFvTime;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
 
 /**
  * <p>
@@ -13,4 +16,5 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  */
 public interface UserFvTimeMapper extends BaseMapper<UserFvTime> {
 
+    void batchInsert(@Param("toAddList") List<UserFvTime> toAddList);
 }

+ 172 - 55
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/FeishuInfoServiceImpl.java

@@ -8,10 +8,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.management.platform.constant.Constant;
 import com.management.platform.entity.*;
 import com.management.platform.entity.bo.*;
-import com.management.platform.mapper.FeishuInfoMapper;
-import com.management.platform.mapper.FeishuSendMapper;
-import com.management.platform.mapper.SysRoleMapper;
-import com.management.platform.mapper.UserMapper;
+import com.management.platform.mapper.*;
 import com.management.platform.service.FeishuInfoService;
 import com.management.platform.util.HttpRespMsg;
 import com.management.platform.util.MD5Util;
@@ -27,10 +24,7 @@ import javax.servlet.http.HttpServletRequest;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.text.SimpleDateFormat;
-import java.time.Instant;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.ZoneId;
+import java.time.*;
 import java.time.format.DateTimeFormatter;
 import java.util.*;
 import java.util.stream.Collectors;
@@ -82,9 +76,13 @@ public class FeishuInfoServiceImpl extends ServiceImpl<FeishuInfoMapper, FeishuI
         @Resource
         SysRoleMapper sysRoleMapper;
 
+        @Resource
+        UserFvTimeMapper userFvTimeMapper;
+
         @Autowired
         private RestTemplate restTemplate;
 
+
         @Override
         public String getAppAccessToken(FeishuInfo feishuInfo) {
                 String result="";
@@ -504,14 +502,14 @@ public class FeishuInfoServiceImpl extends ServiceImpl<FeishuInfoMapper, FeishuI
 //                Integer companyId = user.getCompanyId();
 
                 LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
-                lqw.select(User::getId,User::getJobNumber).isNotNull(User::getJobNumber)
+                lqw.select(User::getId,User::getJobNumber,User::getCompanyId).isNotNull(User::getJobNumber)
                         .in(User::getId,Arrays.asList(queryBO.getWtUserIds()));
                 List<User> users = userMapper.selectList(lqw);
                 if(CollectionUtils.isEmpty(users)){
                         msg.setError("未查询到飞书工号");
                         return msg;
                 }
-                Map<String, String> jobNumIdMap = users.stream().collect(Collectors.toMap(User::getJobNumber, User::getId));
+                Map<String, User> jobNumUserMap = users.stream().collect(Collectors.toMap(User::getJobNumber, t->t));
                 String[] feishuUserIdArr = users.stream().map(User::getJobNumber).toArray(String[]::new);
                 queryBO.setUserIds(feishuUserIdArr);
 
@@ -520,11 +518,11 @@ public class FeishuInfoServiceImpl extends ServiceImpl<FeishuInfoMapper, FeishuI
                         msg.setError("飞书获取用户考勤数据失败,请联系管理员");
                         return msg;
                 }
-                for (FeishuClockUserTaskResult userTaskResult : feishuClockData.getUser_task_results()) {
-                        for (FeishuClockTaskRecord record : userTaskResult.getRecords()) {
-                                record.setDateTime();
-                        }
-                }
+//                for (FeishuClockUserTaskResult userTaskResult : feishuClockData.getUser_task_results()) {
+//                        for (FeishuClockTaskRecord record : userTaskResult.getRecords()) {
+//                                record.setDateTime();
+//                        }
+//                }
 //                                msg.setData(userTaskResults);
 
                 //用户id、day、考勤组、班次、打卡记录list
@@ -545,81 +543,200 @@ public class FeishuInfoServiceImpl extends ServiceImpl<FeishuInfoMapper, FeishuI
                 List<Map<String,Object>> res = new ArrayList();
                 SimpleDateFormat HMFormat = new SimpleDateFormat("HH:mm");
                 SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+                List<UserFvTime> toAddFvTimeList = new ArrayList<>();
                 for (FeishuClockUserTaskResult userTaskResult : feishuClockData.getUser_task_results()) {
                         int day = userTaskResult.getDay();//日期 yyyyMMdd
-                        String dayStr = String.valueOf(day).substring(0,4)+"-"+String.valueOf(day).substring(4,6)+"-"+String.valueOf(day).substring(6,7);
+                        String dayStr = String.valueOf(day).substring(0,4)+"-"+String.valueOf(day).substring(4,6)+"-"+String.valueOf(day).substring(6,8);
+                        Map<String,Object> map = new HashMap<>();
+                        UserFvTime userFvTime = new UserFvTime();
+                        userFvTime.setUserId(jobNumUserMap.get(userTaskResult.getUser_id()).getId());
                         //获取正常上班时间段
                         Optional<FeishuClockTaskRecord> first = userTaskResult.getRecords().stream()
                                 .filter(t -> 0 == t.getTask_shift_type())
                                 .findFirst();
                         if(first.isPresent()){
-                                Map<String,Object> map = new HashMap<>();
                                 FeishuClockTaskRecord record = first.get();
-                                UserFvTime userFvTime = new UserFvTime();
                                 //计算时长 需考虑考勤--待处理
-
                                 FeishuShiftResult shiftResult = shiftResultMap.get(userTaskResult.getShift_id());
                                 //判断弹性上下班
-                                Integer flexibleMinutes = null;
+                                Integer earlyFlexibleMinutes = null; //下班最多可早走
+                                Integer lateFlexibleMinutes = null; //上班最多可晚到
                                 if(shiftResult.is_flexible()){
                                         //可以弹性上下班
-                                        flexibleMinutes = shiftResult.getFlexible_minutes();
-                                        if(null == flexibleMinutes || 0 == flexibleMinutes){
+                                        earlyFlexibleMinutes = shiftResult.getFlexible_minutes();
+                                        lateFlexibleMinutes = shiftResult.getFlexible_minutes();
+                                        if(null == shiftResult.getFlexible_minutes() || 0 == shiftResult.getFlexible_minutes()){
                                                 //从规则中获取
                                                 if(CollectionUtils.isNotEmpty(shiftResult.getFlexible_rule())){
                                                         //此处仅获取第一个作为规则
-                                                        flexibleMinutes = shiftResult.getFlexible_rule().get(0).getFlexible_early_minutes();
+                                                        earlyFlexibleMinutes = shiftResult.getFlexible_rule().get(0).getFlexible_early_minutes();
+                                                        lateFlexibleMinutes = shiftResult.getFlexible_rule().get(0).getFlexible_late_minutes();
                                                 }
                                         }
 
                                 }
-                                flexibleMinutes = null==flexibleMinutes?0:flexibleMinutes;
+                                earlyFlexibleMinutes = null==earlyFlexibleMinutes?0:earlyFlexibleMinutes;
+                                lateFlexibleMinutes = null==lateFlexibleMinutes?0:lateFlexibleMinutes;
                                 //获取打卡规则
                                 FeishuPunchTimeRule feishuPunchTimeRule = null;
                                 if(CollectionUtils.isNotEmpty(shiftResult.getPunch_time_rule())){
                                         //仅获取第一个
                                         feishuPunchTimeRule  = shiftResult.getPunch_time_rule().get(0);
                                 }
-                                /**
-                                 * 弹性时间 0 非0
-                                 * 0 仅判断是否缺卡
-                                 * 非0 先判断弹性,再判断是否缺卡
-                                 * */
-                                if(null != feishuPunchTimeRule){
-                                        LocalDateTime.parse(feishuPunchTimeRule.getOn_time(),DateTimeFormatter.ofPattern("HH:mm"));
-                                }
 
+                                map.put("feishuPunchTimeRule",feishuPunchTimeRule);
 
-                                Instant checkInInstant = Instant.ofEpochSecond(Long.parseLong(record.getCheck_in_record().getCheck_time()));
-                                LocalDateTime checkInLocalTime = LocalDateTime.ofInstant(checkInInstant, ZoneId.of("GMT+8"));
-                                Instant checkOutInstant = Instant.ofEpochSecond(Long.parseLong(record.getCheck_out_record().getCheck_time()));
-                                LocalDateTime checkOutLocalTime = LocalDateTime.ofInstant(checkOutInstant, ZoneId.of("GMT+8"));
+                                if(null != feishuPunchTimeRule){
+                                        //转换上下班规则时间
+                                        LocalDateTime onLocalDateTime = LocalDateTime.parse(dayStr + " " + feishuPunchTimeRule.getOn_time(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
+                                        LocalDateTime offLocalDateTime = LocalDateTime.parse(dayStr + " " + feishuPunchTimeRule.getOff_time(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
+                                        /**
+                                         * 弹性时间 0 非0
+                                         * 0 仅判断是否缺卡
+                                         * 非0 先判断弹性,再判断是否缺卡
+                                         * */
+//                                        if("Lack".equals(record.getCheck_in_result()) || "Todo".equals(record.getCheck_in_result())){
+//
+//                                        } else if ("Normal".equals(record.getCheck_in_result()) || "Early".equals(record.getCheck_in_result())) {
+//
+//                                        }
+                                        //上下班打卡时间
+                                        LocalDateTime checkInLocalTime = null;
+                                        LocalDateTime checkOutLocalTime = null;
+                                        if(null != record.getCheck_in_record()){
+                                                Instant checkInInstant = Instant.ofEpochSecond(Long.parseLong(record.getCheck_in_record().getCheck_time()));
+                                                checkInLocalTime = LocalDateTime.ofInstant(checkInInstant, ZoneId.of("GMT+8"));
+                                        }
+                                        if(null != record.getCheck_out_record()){
+                                                Instant checkOutInstant = Instant.ofEpochSecond(Long.parseLong(record.getCheck_out_record().getCheck_time()));
+                                                checkOutLocalTime = LocalDateTime.ofInstant(checkOutInstant, ZoneId.of("GMT+8"));
+                                        }
 
-                                System.out.println("checkInInstant=== "+checkInLocalTime+",checkOutLocalTime=== "+checkOutLocalTime);
+                                        String startTime = null;
+                                        String endTime = null;
+                                        long workSeconds = 0l;
+                                        if(null == checkInLocalTime || null==checkOutLocalTime){
+                                                //记录为缺卡,工时为0
+                                                startTime = null == record.getCheck_in_record()?null:
+                                                        checkInLocalTime.format(DateTimeFormatter.ofPattern("HH:mm"));
+                                                endTime = null == record.getCheck_out_record()?null:
+                                                        checkOutLocalTime.format(DateTimeFormatter.ofPattern("HH:mm"));
+                                        }else{
+                                                startTime = checkInLocalTime.format(DateTimeFormatter.ofPattern("HH:mm"));
+                                                endTime = checkOutLocalTime.format(DateTimeFormatter.ofPattern("HH:mm"));
+
+                                                if((checkInLocalTime.isBefore(onLocalDateTime) || checkInLocalTime.isEqual(onLocalDateTime))
+                                                        && (checkOutLocalTime.isAfter(offLocalDateTime) || checkOutLocalTime.isEqual(offLocalDateTime))){
+                                                        //正常上下班
+                                                        long offStamp = offLocalDateTime.toEpochSecond(ZoneOffset.of("+8"));
+                                                        long onStamp = onLocalDateTime.toEpochSecond(ZoneOffset.of("+8"));
+                                                        workSeconds = offStamp-onStamp;
+                                                }else{
+
+                                                        //判断上班是否满足缺卡条件
+                                                        if(checkInLocalTime.isAfter(onLocalDateTime.plusMinutes(feishuPunchTimeRule.getLate_minutes_as_lack()))){
+                                                                workSeconds = 0;
+                                                        } else if (checkOutLocalTime.isBefore(offLocalDateTime.plusMinutes(feishuPunchTimeRule.getEarly_minutes_as_lack()))) {
+                                                                workSeconds = 0;
+                                                        }else {
+                                                                //判断弹性时间
+                                                                if(checkInLocalTime.isAfter(onLocalDateTime)){ //上班时间 在规定时间之后,查看上班是否在弹性,下班是否在弹性
+                                                                        long offStamp = checkOutLocalTime.toEpochSecond(ZoneOffset.of("+8"));
+                                                                        long onStamp = checkInLocalTime.toEpochSecond(ZoneOffset.of("+8"));
+                                                                        workSeconds = offStamp-onStamp;
+                                                                        //判断上班是否在弹性
+                                                                        boolean checkInFlag = checkInLocalTime.isBefore(onLocalDateTime.plusMinutes(lateFlexibleMinutes))
+                                                                                || checkInLocalTime.isEqual(onLocalDateTime.plusMinutes(lateFlexibleMinutes));
+                                                                        if(checkInFlag){
+                                                                                //在弹性上班范围内,判断下班
+                                                                                if(checkOutLocalTime.isAfter(offLocalDateTime.plusMinutes(lateFlexibleMinutes))
+                                                                                        ||checkOutLocalTime.isEqual(offLocalDateTime.plusMinutes(lateFlexibleMinutes))){
+                                                                                        offStamp = offLocalDateTime.toEpochSecond(ZoneOffset.of("+8"));
+                                                                                        onStamp = onLocalDateTime.toEpochSecond(ZoneOffset.of("+8"));
+                                                                                        workSeconds = offStamp-onStamp;
+                                                                                }
+                                                                        }
+                                                                }
+
+                                                                if(checkOutLocalTime.isBefore(offLocalDateTime)){ //下班时间 在规定时间之前,查看下班是否在弹性,上班是否在弹性
+                                                                        long offStamp = checkOutLocalTime.toEpochSecond(ZoneOffset.of("+8"));
+                                                                        long onStamp = checkInLocalTime.toEpochSecond(ZoneOffset.of("+8"));
+                                                                        workSeconds = offStamp-onStamp;
+                                                                        //判断下班是否在弹性
+                                                                        boolean checkOutFlag = checkOutLocalTime.isAfter(offLocalDateTime.minusMinutes(earlyFlexibleMinutes))
+                                                                                || checkOutLocalTime.isEqual(offLocalDateTime.minusMinutes(earlyFlexibleMinutes));
+                                                                        if(checkOutFlag){
+                                                                                //在弹性下班范围内,判断上班
+                                                                                if(checkInLocalTime.isBefore(onLocalDateTime.minusMinutes(earlyFlexibleMinutes))
+                                                                                        ||checkInLocalTime.isEqual(onLocalDateTime.minusMinutes(earlyFlexibleMinutes))){
+                                                                                        offStamp = offLocalDateTime.toEpochSecond(ZoneOffset.of("+8"));
+                                                                                        onStamp = onLocalDateTime.toEpochSecond(ZoneOffset.of("+8"));
+                                                                                        workSeconds = offStamp-onStamp;
+                                                                                }
+                                                                        }
+                                                                }
+                                                        }
 
+                                                }
+                                        }
 
+//                                        userFvTime.setStartTime(startTime);
+//                                        userFvTime.setEndTime(endTime);
+                                        userFvTime.setWorkDate(LocalDate.parse(String.valueOf(day),DateTimeFormatter.ofPattern("yyyyMMdd")));
+                                        userFvTime.setCompanyId(jobNumUserMap.get(userTaskResult.getUser_id()).getCompanyId());
+//                                        userFvTime.setWorkHours(workHours);
+
+                                        //计算休息时长
+                                        int sumRestSecond = 0;
+                                        List<FeishuRestTimeRule> restTimeRule = null == shiftResult.getRest_time_rule()?new ArrayList<>():shiftResult.getRest_time_rule();
+                                        for (FeishuRestTimeRule feishuRestTimeRule : restTimeRule) {
+                                                LocalTime tmpBeginTime = LocalTime.parse(feishuRestTimeRule.getRest_begin_time(), DateTimeFormatter.ofPattern("HH:mm"));
+                                                LocalTime tmpEndTime = LocalTime.parse(feishuRestTimeRule.getRest_end_time(), DateTimeFormatter.ofPattern("HH:mm"));
+                                                sumRestSecond = tmpEndTime.toSecondOfDay() - tmpBeginTime.toSecondOfDay();
+                                        }
 
+                                        //获取加班时间段
+                                        //TODO 先不从班次规则里获取,直接类型为加班的记录相减
+                                        List<FeishuClockTaskRecord> overTimeList = userTaskResult.getRecords().stream().filter(t -> 1 == t.getTask_shift_type())
+                                                .collect(Collectors.toList());
+                                        long sumOverTimeSeconds = 0;
+                                        if(CollectionUtils.isNotEmpty(overTimeList)){
+                                                for (FeishuClockTaskRecord feishuClockTaskRecord : overTimeList) {
+                                                        long startOver = Long.parseLong(feishuClockTaskRecord.getCheck_in_record().getCheck_time());
+                                                        long endOver = Long.parseLong(feishuClockTaskRecord.getCheck_in_record().getCheck_time());
+                                                        sumOverTimeSeconds = endOver-startOver;
+                                                }
+                                        }
+//                                        float overTimeHours = BigDecimal.valueOf(sumOverTimeSeconds/ (60 * 60f)).setScale(2, RoundingMode.HALF_UP).floatValue();
+//                                        userFvTime.setOverTimeHours(overTimeHours);
+
+                                        float workHours = BigDecimal.valueOf((workSeconds - sumRestSecond + sumOverTimeSeconds) / (60 * 60f))
+                                                .setScale(2, RoundingMode.HALF_UP).floatValue();
+
+                                        userFvTime.setWorkHours(workHours);
+                                        userFvTime.setWorkDate(LocalDate.parse(String.valueOf(userTaskResult.getDay()), DateTimeFormatter.ofPattern("yyyyMMdd")));
+                                        //需要关联user表job_number
+                                        userFvTime.setUserId(jobNumUserMap.get(userTaskResult.getUser_id()).getId());
+                                        Date checkInTime = new Date(Long.parseLong(record.getCheck_in_record().getCheck_time()) * 1000);
+                                        Date checkOutTime = new Date(Long.parseLong(record.getCheck_out_record().getCheck_time()) * 1000);
+                                        userFvTime.setStartTime(HMFormat.format(checkInTime));
+                                        userFvTime.setEndTime(HMFormat.format(checkOutTime));
+
+                                        map.put("data",userFvTime);
+                                        map.put("startDateTime",format.format(checkInTime));
+                                        map.put("endDateTime",format.format(checkOutTime));
+                                        res.add(map);
+                                }
+                        }
 
-                                long secondCost = Long.parseLong(record.getCheck_out_record().getCheck_time())
-                                        -Long.parseLong(record.getCheck_in_record().getCheck_time());
-//                                                long hourCost = BigDecimal.valueOf(secondCost / (60 * 60))
-//                                                        .setScale(0, RoundingMode.UP).longValue();
-                                float hourCost = BigDecimal.valueOf(secondCost / (60 * 60f)).setScale(2, RoundingMode.HALF_UP).floatValue();
-                                userFvTime.setWorkHours(hourCost);
-                                userFvTime.setWorkDate(LocalDate.parse(String.valueOf(userTaskResult.getDay()), DateTimeFormatter.ofPattern("yyyyMMdd")));
-                                //需要关联user表job_number
-                                userFvTime.setUserId(jobNumIdMap.get(userTaskResult.getUser_id()));
-                                Date checkInTime = new Date(Long.parseLong(record.getCheck_in_record().getCheck_time()) * 1000);
-                                Date checkOutTime = new Date(Long.parseLong(record.getCheck_out_record().getCheck_time()) * 1000);
-                                userFvTime.setStartTime(HMFormat.format(checkInTime));
-                                userFvTime.setStartTime(HMFormat.format(checkOutTime));
+                        toAddFvTimeList.add(userFvTime);
+                }
 
-                                map.put("data",userFvTime);
-                                map.put("startDateTime",format.format(checkInTime));
-                                map.put("endDateTime",format.format(checkOutTime));
-                                res.add(map);
-                        }
+                if(CollectionUtils.isNotEmpty(toAddFvTimeList)){
+                        userFvTimeMapper.batchInsert(toAddFvTimeList);
                 }
+
+
                 msg.setData(res);
                 return msg;
         }

+ 11 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ProjectServiceImpl.java

@@ -2045,6 +2045,17 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                                 .eq("group_audit_state", 1)//任务分组已审核,当前是项目经理审核
                                 .eq("project_id", id));
                     }
+                } else if (timeType.getReportAuditType() == 10) {
+                    if (inchargerChanged) {
+                        //项目经理变更,待审核的转移到新的项目经理身上
+                        Report updateItem = new Report();
+                        updateItem.setProjectAuditorId(inchargerId);
+                        reportMapper.update(updateItem, new QueryWrapper<Report>()
+                                .eq("company_id", companyId)
+                                .eq("project_auditor_id", oldInchargerId)
+                                .eq("state", 0)
+                                .eq("project_id", id));
+                    }
                 } else {
                     //其他审核情况,提取变化的部分
                     List<ProjectAuditor> oldAuditorList = projectAuditorMapper.selectList(new QueryWrapper<ProjectAuditor>().eq("project_id", id));

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

@@ -5957,7 +5957,7 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                 //titles.add("工作事项");
                 titles.add(MessageUtils.message("excel.workItems"));
             }
-            if(stateKey==1){
+            if(stateKey==1 || stateKey==0 || stateKey==2){
                 //titles.add("审核状态");
                 titles.add(MessageUtils.message("excel.auditStatus"));
             }
@@ -6443,7 +6443,7 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                 if (exportType==0) {
                     item.add((String) map.get("content"));
                 }
-                if(stateKey==1){
+                if(stateKey==1 || stateKey ==0 || stateKey==2){
                     Integer state = (Integer) map.get("state");
                     switch (state){
                         //case 0:row.createCell(index).setCellValue("待审核");

+ 3 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/resources/application.yml

@@ -66,6 +66,8 @@ spring:
     base:
       dcFirst: yurk
       dcSecond: cn
+#  profiles:
+#    active: dev
 ##########日志配置
 logging:
   level:
@@ -162,7 +164,7 @@ providerSecret: wlwGIUXskWKsNtCfKUsAfJ6ueba55rZnqZvcC-rUM6nQ-LnRDyYgISQ2BO-UlL_A
 configEnv:
   isDev: true
   # 是否是私有化部署,企业内部应用
-  isPrivateDeploy: false
+  isPrivateDeploy: true
 
 privateDeployURL:
   pcUrl: http://dev.huoshishanxin.com/#/

+ 8 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/UserFvTimeMapper.xml

@@ -19,4 +19,12 @@
         id, work_date, user_id, company_id, start_time, end_time, work_hours, cancel_normal
     </sql>
 
+    <insert id="batchInsert">
+        insert into user_fv_time(work_date, user_id, company_id, start_time, end_time, work_hours, overtime_hours)
+        values
+            <foreach collection="toAddList" item="toAdd" separator=",">
+            (#{toAdd.workDate},#{toAdd.userId},#{toAdd.companyId},#{toAdd.startTime},#{toAdd.endTime},#{toAdd.workHours},#{toAdd.overTimeHours})
+            </foreach>
+    </insert>
+
 </mapper>

+ 132 - 100
fhKeeper/formulahousekeeper/timesheet/src/views/project/costReportExport.vue

@@ -3,129 +3,144 @@
     :before-close="handleClose">
     <el-form ref="exportFormRef" :model="exportParam">
       <!-- 头部 -->
-      <div style="text-align: center;margin-bottom: 20px">
+      <div style="text-align: center;margin-bottom: 20px" v-if="singleChoiceType != '设备'">
         <el-radio-group size="medium" v-model="exportParam.reportType">
           <el-radio-button :label="0">常规报表</el-radio-button>
           <el-radio-button :label="1">月度报表</el-radio-button>
         </el-radio-group>
       </div>
-      <!-- 常规报表 -->
-      <template v-if="exportParam.reportType == 0">
 
-        <el-form-item prop="projectCategoryId" :label="$t('projectclassification')"
-          v-if="singleChoiceType == $t('projectclassification') || singleChoiceType == $t('other.project')">
-          <el-select v-model="exportParam.projectCategoryId" :placeholder="$t('classificationitems')" clearable
-            style="width:350px;" filterable="true" @change="filterCategory">
-            <el-option v-for="item in categoryList" :key="item.id" :label="item.name" :value="item.id">
-            </el-option>
-          </el-select>
-        </el-form-item>
+      <template v-if="singleChoiceType != '设备'">
+        <!-- 常规报表 -->
+        <template v-if="exportParam.reportType == 0">
 
-        <el-form-item prop="projectId" :label="'选择项目'" v-if="!['人员', '项目分类', '部门', '主项目'].includes(singleChoiceType)">
-          <select-project v-model="exportParam.projectId" :size="'medium'" :placeholder="'全部项目'" width="350px"
-            clearable></select-project>
-        </el-form-item>
+          <el-form-item prop="projectCategoryId" :label="$t('projectclassification')"
+            v-if="singleChoiceType == $t('projectclassification') || singleChoiceType == $t('other.project')">
+            <el-select v-model="exportParam.projectCategoryId" :placeholder="$t('classificationitems')" clearable
+              style="width:350px;" filterable="true" @change="filterCategory">
+              <el-option v-for="item in categoryList" :key="item.id" :label="item.name" :value="item.id">
+              </el-option>
+            </el-select>
+          </el-form-item>
 
-        <el-form-item prop="exportContent" :label="$t('daoChuNeiRon')"
-          v-if="permissions.countCost && permissions.countHours && (['项目', '项目分类'].includes(singleChoiceType))">
-          <el-select v-model="exportParam.exportContent" style="width:350px;" filterable="true"
-            popper-class="projectSelectPopperClass">
-            <el-option :label="$t('gongShiHeChengBen')" value="hoursAndCost"></el-option>
-            <el-option :label="$t('jingGongShi')" value="hours"></el-option>
-            <el-option :label="$t('jingChenBen')" value="cost"></el-option>
-          </el-select>
-        </el-form-item>
+          <el-form-item prop="projectId" :label="'选择项目'" v-if="!['人员', '项目分类', '部门', '主项目'].includes(singleChoiceType)">
+            <select-project v-model="exportParam.projectId" :size="'medium'" :placeholder="'全部项目'" width="350px"
+              clearable></select-project>
+          </el-form-item>
 
-        <el-form-item :label="$t('departmentchoice')" v-if="singleChoiceType == $t('other.project')">
-          <el-cascader v-if="user.userNameNeedTranslate != 1" v-model="exportParam.deptId" :options="departmentList"
-            :placeholder="$t('defaultText.pleaseChoose')" :props="{ checkStrictly: true, expandTrigger: 'hover' }"
-            clearable filterable style="width:350px;"></el-cascader>
+          <el-form-item prop="exportContent" :label="$t('daoChuNeiRon')"
+            v-if="permissions.countCost && permissions.countHours && (['项目', '项目分类'].includes(singleChoiceType))">
+            <el-select v-model="exportParam.exportContent" style="width:350px;" filterable="true"
+              popper-class="projectSelectPopperClass">
+              <el-option :label="$t('gongShiHeChengBen')" value="hoursAndCost"></el-option>
+              <el-option :label="$t('jingGongShi')" value="hours"></el-option>
+              <el-option :label="$t('jingChenBen')" value="cost"></el-option>
+            </el-select>
+          </el-form-item>
 
-          <vueCascader :size="'medium'" :widthStr="'350'" :clearable="true" :subject="departmentList" :radios="true"
-            :distinction="'1'" @vueCasader="vueCasader" v-if="user.userNameNeedTranslate == 1"></vueCascader>
-        </el-form-item>
+          <el-form-item :label="$t('departmentchoice')" v-if="singleChoiceType == $t('other.project')">
+            <el-cascader v-if="user.userNameNeedTranslate != 1" v-model="exportParam.deptId" :options="departmentList"
+              :placeholder="$t('defaultText.pleaseChoose')" :props="{ checkStrictly: true, expandTrigger: 'hover' }"
+              clearable filterable style="width:350px;"></el-cascader>
 
-        <el-form-item prop="userIds" :label="$t('screening.selectPeople')" v-if="singleChoiceType == $t('ren-yuan')">
-          <el-select v-if="user.userNameNeedTranslate != '1'" v-model="exportParam.userIds"
-            :placeholder="$t('lable.allStaff')" multiple="true" clearable style="width:350px;" filterable="true">
-            <el-option v-for="item in hasReportUserList" :key="item.id" :label="item.name" :value="item.id"></el-option>
-          </el-select>
+            <vueCascader :size="'medium'" :widthStr="'350'" :clearable="true" :subject="departmentList" :radios="true"
+              :distinction="'1'" @vueCasader="vueCasader" v-if="user.userNameNeedTranslate == 1"></vueCascader>
+          </el-form-item>
 
-          <selectCat v-if="user.userNameNeedTranslate == '1'" :size="'medium'" :widthStr="'350'" :filterable="true"
-            :subject="hasReportUserList" :clearable="true" :multiSelect="true" @selectCal="selectCal"
-            :distinction="'1'"></selectCat>
-        </el-form-item>
+          <el-form-item prop="userIds" :label="$t('screening.selectPeople')" v-if="singleChoiceType == $t('ren-yuan')">
+            <el-select v-if="user.userNameNeedTranslate != '1'" v-model="exportParam.userIds"
+              :placeholder="$t('lable.allStaff')" multiple="true" clearable style="width:350px;" filterable="true">
+              <el-option v-for="item in hasReportUserList" :key="item.id" :label="item.name" :value="item.id"></el-option>
+            </el-select>
 
-        <el-form-item prop="userIds" :label="$t('screening.selectPeople')"
-          v-if="['项目', '项目分类'].includes(singleChoiceType)">
-          <el-select v-if="user.userNameNeedTranslate != '1'" v-model="exportParam.userIds"
-            :placeholder="$t('lable.allStaff')" multiple="true" clearable style="width:350px;" filterable="true">
-            <el-option v-for="item in users" :key="item.id" :label="item.name" :value="item.id"></el-option>
-          </el-select>
+            <selectCat v-if="user.userNameNeedTranslate == '1'" :size="'medium'" :widthStr="'350'" :filterable="true"
+              :subject="hasReportUserList" :clearable="true" :multiSelect="true" @selectCal="selectCal"
+              :distinction="'1'"></selectCat>
+          </el-form-item>
 
-          <selectCat v-if="user.userNameNeedTranslate == '1'" :size="'medium'" :widthStr="'350'" :filterable="true"
-            :subject="users" :clearable="true" :multiSelect="true" @selectCal="selectCal" :distinction="'1'">
-          </selectCat>
-        </el-form-item>
+          <el-form-item prop="userIds" :label="$t('screening.selectPeople')"
+            v-if="['项目', '项目分类'].includes(singleChoiceType)">
+            <el-select v-if="user.userNameNeedTranslate != '1'" v-model="exportParam.userIds"
+              :placeholder="$t('lable.allStaff')" multiple="true" clearable style="width:350px;" filterable="true">
+              <el-option v-for="item in users" :key="item.id" :label="item.name" :value="item.id"></el-option>
+            </el-select>
 
-        <el-form-item prop="projectId"
-          :label="user.timeType.fixMonthcost == 0 ? $t('time.dateRange') : $t('Selectmonth')">
-          <el-date-picker v-show="user.timeType.fixMonthcost == 0" v-model="exportParam.dateRange" :editable="false"
-            format="yyyy-MM-dd" value-format="yyyy-MM-dd" :clearable="false" :range-separator="$t('other.to')"
-            type="daterange" :start-placeholder="$t('time.startDate')"
-            :end-placeholder="$t('time.endDate')"></el-date-picker>
+            <selectCat v-if="user.userNameNeedTranslate == '1'" :size="'medium'" :widthStr="'350'" :filterable="true"
+              :subject="users" :clearable="true" :multiSelect="true" @selectCal="selectCal" :distinction="'1'">
+            </selectCat>
+          </el-form-item>
 
+          <el-form-item prop="projectId"
+            :label="user.timeType.fixMonthcost == 0 ? $t('time.dateRange') : $t('Selectmonth')">
+            <el-date-picker v-show="user.timeType.fixMonthcost == 0" v-model="exportParam.dateRange" :editable="false"
+              format="yyyy-MM-dd" value-format="yyyy-MM-dd" :clearable="false" :range-separator="$t('other.to')"
+              type="daterange" :start-placeholder="$t('time.startDate')"
+              :end-placeholder="$t('time.endDate')"></el-date-picker>
 
-          <el-date-picker v-show="user.timeType.fixMonthcost == 1" v-model="dateRange" :editable="false"
-            format="yyyy-MM" value-format="yyyy-MM" @change="getEchart" :clearable="true" type="month"></el-date-picker>
-        </el-form-item>
 
-        <el-form-item :label="$t('screening.selectPeople')" v-if="false">
-          <el-select v-if="user.userNameNeedTranslate != '1'" v-model="exportParam.userId"
-            :placeholder="$t('lable.allStaff')" style="width: 350px" filterable="true" clearable="true">
-            <span v-for="(item, index) in users" :key="index">
-              <el-option :label="item.name" :value="item.id"></el-option>
-            </span>
-          </el-select>
+            <el-date-picker v-show="user.timeType.fixMonthcost == 1" v-model="dateRange" :editable="false"
+              format="yyyy-MM" value-format="yyyy-MM" @change="getEchart" :clearable="true" type="month"></el-date-picker>
+          </el-form-item>
 
-          <selectCat v-if="user.userNameNeedTranslate == '1'" :size="'medium'" :distinction="'4'" :widthStr="'350'"
-            :subject="users" :clearable="true" @selectCal="selectCal"></selectCat>
-        </el-form-item>
+          <el-form-item :label="$t('screening.selectPeople')" v-if="false">
+            <el-select v-if="user.userNameNeedTranslate != '1'" v-model="exportParam.userId"
+              :placeholder="$t('lable.allStaff')" style="width: 350px" filterable="true" clearable="true">
+              <span v-for="(item, index) in users" :key="index">
+                <el-option :label="item.name" :value="item.id"></el-option>
+              </span>
+            </el-select>
 
-        <el-form-item prop="type" :label="$t('choosethestyle')" v-if="['项目', '项目分类'].includes(singleChoiceType)">
-          <el-select v-model="exportParam.type" :placeholder="$t('choosethestyle')" style="width:350px;">
-            <el-option
-              :label="singleChoiceType == $t('projectclassification') ? $t('classifiedontheline') : $t('Itemontheline')"
-              value="0"></el-option>
-            <el-option
-              :label="singleChoiceType == $t('projectclassification') ? $t('classifiedcolumns') : $t('itemisonthecolumn')"
-              value="1"></el-option>
-          </el-select>
-          <div class="prompt">
-            <el-popover placement="top" width="1200" trigger="hover">
-              <img src="../../assets/image/hanglie.png" alt="" width="100%"
-                v-if="this.singleChoiceType != $t('projectclassification')">
-              <img src="../../assets/image/hanglie_corp.png" alt="" width="100%" v-else>
-              <i class="el-icon-question" slot="reference" />
-            </el-popover>
-          </div>
-        </el-form-item>
+            <selectCat v-if="user.userNameNeedTranslate == '1'" :size="'medium'" :distinction="'4'" :widthStr="'350'"
+              :subject="users" :clearable="true" @selectCal="selectCal"></selectCat>
+          </el-form-item>
 
-        <el-form-item
-          v-if="exportParam.type == 1 && permissions.countHours && (singleChoiceType == $t('other.project'))">
-          <el-checkbox v-model="exportParam.withPercent">{{ $t('gongHhiZhanbiXmu') }}</el-checkbox>
-        </el-form-item>
+          <el-form-item prop="type" :label="$t('choosethestyle')" v-if="['项目', '项目分类'].includes(singleChoiceType)">
+            <el-select v-model="exportParam.type" :placeholder="$t('choosethestyle')" style="width:350px;">
+              <el-option
+                :label="singleChoiceType == $t('projectclassification') ? $t('classifiedontheline') : $t('Itemontheline')"
+                value="0"></el-option>
+              <el-option
+                :label="singleChoiceType == $t('projectclassification') ? $t('classifiedcolumns') : $t('itemisonthecolumn')"
+                value="1"></el-option>
+            </el-select>
+            <div class="prompt">
+              <el-popover placement="top" width="1200" trigger="hover">
+                <img src="../../assets/image/hanglie.png" alt="" width="100%"
+                  v-if="this.singleChoiceType != $t('projectclassification')">
+                <img src="../../assets/image/hanglie_corp.png" alt="" width="100%" v-else>
+                <i class="el-icon-question" slot="reference" />
+              </el-popover>
+            </div>
+          </el-form-item>
 
-        <el-form-item v-if="['项目', '项目分类', '主项目'].includes(singleChoiceType) && exportParam.type == '0'">
-          <el-checkbox v-model="exportParam.projectSum">{{ $t('individualprojectdata') }}</el-checkbox>
-        </el-form-item>
+          <el-form-item
+            v-if="exportParam.type == 1 && permissions.countHours && (singleChoiceType == $t('other.project'))">
+            <el-checkbox v-model="exportParam.withPercent">{{ $t('gongHhiZhanbiXmu') }}</el-checkbox>
+          </el-form-item>
 
-        <el-form-item v-if="singleChoiceType == $t('ren-yuan') && user.timeType.mainProjectState == 1">
-          <el-checkbox v-model="exportParam.mainProjectColumn">{{ $t('hanZhuXiangMu') }}</el-checkbox>
-        </el-form-item>
+          <el-form-item v-if="['项目', '项目分类', '主项目'].includes(singleChoiceType) && exportParam.type == '0'">
+            <el-checkbox v-model="exportParam.projectSum">{{ $t('individualprojectdata') }}</el-checkbox>
+          </el-form-item>
+
+          <el-form-item v-if="singleChoiceType == $t('ren-yuan') && user.timeType.mainProjectState == 1">
+            <el-checkbox v-model="exportParam.mainProjectColumn">{{ $t('hanZhuXiangMu') }}</el-checkbox>
+          </el-form-item>
+        </template>
+        <!-- 月度报表 -->
+        <template v-if="exportParam.reportType == 1">
+          <el-form-item prop="date" :label="this.$t('Selectmonth')">
+            <el-date-picker size="small" v-model="exportParam.date" :editable="false" format="yyyy-MM"
+              value-format="yyyy-MM" :clearable="false" type="month" :placeholder="$t('Selectmonth')"
+              style="margin-right: 20px"></el-date-picker>
+          </el-form-item>
+        </template>
       </template>
-      <!-- 月度报表 -->
-      <template v-if="exportParam.reportType == 1">
+      
+      <template v-if="singleChoiceType == '设备'">
+        <el-form-item prop="projectId" :label="'选择项目'">
+          <select-project v-model="exportParam.projectId" :size="'medium'" :placeholder="'全部项目'" width="350px"
+            clearable></select-project>
+        </el-form-item>
         <el-form-item prop="date" :label="this.$t('Selectmonth')">
           <el-date-picker size="small" v-model="exportParam.date" :editable="false" format="yyyy-MM"
             value-format="yyyy-MM" :clearable="false" type="month" :placeholder="$t('Selectmonth')"
@@ -137,7 +152,9 @@
     <!-- 导出按钮 -->
     <div slot="footer" class="dialog-footer">
       <el-button type="primary" @click="exportParam.reportType == 0 ? exportProjectData() : exportMonthlyProjectData()"
-        style="width:100%;" :loading="exporting">{{ $t('export.export') }}</el-button>
+        style="width:100%;" :loading="exporting" v-if="singleChoiceType != '设备'">{{ $t('export.export') }}</el-button>
+      <el-button type="primary" @click="deviceExport()"
+        style="width:100%;" :loading="exporting" v-if="singleChoiceType == '设备'">{{ $t('export.export') }}</el-button>
     </div>
   </el-dialog>
 </template>
@@ -200,6 +217,21 @@ export default {
     }
   },
   methods: {
+    deviceExport() {
+      var url = '/device-log/exportDeviceTimeCostByMonth';
+      var fileName = this.exportParam.date + '设备月度统计表.xlsx';
+      const { projectId, date } = this.exportParam
+      this.exporting = true;
+      this.postData(url, { projectId, date }).then((res) => {
+        const aTag = document.createElement('a');
+        aTag.download = fileName;
+        aTag.href = res.data;
+        aTag.click()
+      }).finally(() => {
+        this.exporting = false
+        this.updateValue()
+      })
+    },
     exportMonthlyProjectData() {
       var url = '/project/exportTimeByProjectAndEmployee';
       var fileName = this.exportParam.date + '月度工时统计表.xlsx';