Przeglądaj źródła

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

# Conflicts:
#	fhKeeper/formulahousekeeper/timesheet/src/views/settings/timetype.vue
yusm 1 tydzień temu
rodzic
commit
044114fcc1

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

@@ -292,10 +292,11 @@ public class OvertimeController {
             QueryWrapper<Overtime> queryWrapper = new QueryWrapper<>();
             queryWrapper.eq("company_id", currentUser.getCompanyId());
             queryWrapper.eq("user_id", currentUser.getId());
-            queryWrapper.and(wrapper -> wrapper.between("start_time", overtime.getStartTime(), overtime.getEndTime()).or().between("end_time", overtime.getStartTime(), overtime.getEndTime()));
+            queryWrapper.eq("date", overtime.getDate());
+            queryWrapper.ne("status", 4).ne("status", -1);
             int count = overtimeService.count(queryWrapper);
             if (count > 0) {
-                msg.setError("已存在交叉的开始结束时间的加班单");
+                msg.setError("当日已存在有效加班单,不可重复提交");
                 return msg;
             }
         }
@@ -342,11 +343,12 @@ public class OvertimeController {
         if (!overtime.getForceCancelOthers()) {
             QueryWrapper<Overtime> queryWrapper = new QueryWrapper<>();
             queryWrapper.eq("company_id", currentUser.getCompanyId());
-            queryWrapper.eq("user_id", currentUser.getId()).ne("id", overtime.getId());
-            queryWrapper.and(wrapper -> wrapper.between("start_time", overtime.getStartTime(), overtime.getEndTime()).or().between("end_time", overtime.getStartTime(), overtime.getEndTime()));
+            queryWrapper.eq("user_id", currentUser.getId()).ne("id", overtime.getId())
+                    .eq("date", overtime.getDate())
+                    .ne("status", 4).ne("status", -1);
             int count = overtimeService.count(queryWrapper);
             if (count > 0) {
-                msg.setError("已存在交叉的开始结束时间的加班单");
+                msg.setError("当日已存在有效加班单,不可重复提交");
                 return msg;
             }
         }

+ 23 - 12
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ReportController.java

@@ -58,6 +58,8 @@ public class ReportController {
     @Resource
     private UserRecentReportService userRecentReportService;
     @Resource
+    private AbnormalItemService abnormalItemService;
+    @Resource
     private ConstructionStageService constructionStageService;
     @Resource
     private ProjectConstructionStageService projectConstructionStageService;
@@ -507,6 +509,7 @@ public class ReportController {
                                   String[] extraField4,
                                   String[] extraField5,
                                   @RequestParam (required = false, defaultValue = "false") Boolean abnormalTime,
+                                  Integer abnormalItemId,
                                   String[] constructionStagesStr, //柘中定制的施工进度
                                   String abnormalStartTime,//补考勤上班时间
                                   String abnormalEndTime, //补考勤下班时间
@@ -630,13 +633,6 @@ public class ReportController {
         }
         if (extraField1 == null) {
             extraField1 = new Integer[projectId.length];
-            for(int i=0;i<extraField1.length; i++) {
-                if (abnormalTime != null && abnormalTime) {
-                    extraField1[i] = 1;//标记为异常工时
-                } else {
-                    extraField1[i] = null;
-                }
-            }
         }
         for (int i=0;i<extraField1.length; i++) {
             if (extraField1[i] != null && extraField1[i] == -1) {
@@ -647,6 +643,20 @@ public class ReportController {
         if (extraField2 == null) {
             extraField2 = new Integer[projectId.length];
         }
+        if (company.getId() == Constant.XI_HE_CHAO_DAO_COMPANY_ID || company.getId() == Constant.XI_HE_CHAO_DAO_JIA_XING_COMPANY_ID) {
+            for(int i=0;i<extraField1.length; i++) {
+                if (abnormalTime != null && abnormalTime) {
+                    extraField1[i] = 1;//标记为异常工时
+                } else {
+                    extraField1[i] = null;
+                }
+            }
+            for(int i=0;i<extraField2.length; i++) {
+                if (abnormalItemId != null) {
+                    extraField2[i] = abnormalItemId;//用于存储异常类型
+                }
+            }
+        }
         if (extraField3 == null) {
             extraField3 = new Integer[projectId.length];
         }
@@ -1579,7 +1589,7 @@ public class ReportController {
                                         return httpRespMsg;
                                     } else {
                                         double applyOvertime = 1.0*overtime.getDuration()/3600;//转化为小时
-                                        if (Math.abs(overTimeSum - applyOvertime) > 0.001) {
+                                        if (overTimeSum - applyOvertime > 0.001) {
                                             httpRespMsg.setError("填报加班时长不得超过加班申请时长("+applyOvertime+"h)");
                                             return httpRespMsg;
                                         }
@@ -1588,8 +1598,8 @@ public class ReportController {
                                     if (userCorpwxTime == null || userCorpwxTime.getOtTime() == 0) {
                                         httpRespMsg.setError("未同步到企微加班时长,请先补填加班申请");
                                         return httpRespMsg;
-                                    } else if (Math.abs(overTimeSum - userCorpwxTime.getOtTime()) > 0.001) {
-                                        httpRespMsg.setError("填报加班时长不得超过考勤加班时长("+userCorpwxTime.getOtTime()+"h)");
+                                    } else if (overTimeSum - userCorpwxTime.getOtTime() > 0.001) {
+                                        httpRespMsg.setError("填报加班时长("+overTimeSum+"h)不得超过考勤加班时长("+userCorpwxTime.getOtTime()+"h)");
                                         return httpRespMsg;
                                     }
                                 }
@@ -2486,8 +2496,9 @@ public class ReportController {
         }
         //校验补的考勤
         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) {
+            AbnormalItem abnormalItem = abnormalItemService.getById(abnormalItemId);
+            if (abnormalTime != null && abnormalTime && abnormalItem != null && abnormalItem.getRequireCardtime()) {
+                if (abnormalStartTime == null || abnormalEndTime == null || abnormalEndDay == null || "undefined".equals(abnormalStartTime) || "undefined".equals(abnormalEndTime) || "undefined".equals(abnormalEndTime)) {
                     HttpRespMsg msg = new HttpRespMsg();
                     msg.setError("补考勤上班时间、下班时间、下班是否为次日不能为空");
                     return msg;

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

@@ -2198,6 +2198,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                 for (String userId : userIds) {
                     Participation p = new Participation();
                     p.setProjectId(id);
+                    System.out.println("userId==="+userId);
                     p.setUserId(userId);
                     pList.add(p);
                 }
@@ -10596,11 +10597,11 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
         StringBuilder sb=new StringBuilder("批量删除项目:");
         Integer companyId = projectMapper.selectById(integer).getCompanyId();
         List<Project> projectList = projectMapper.selectList(new QueryWrapper<Project>().in("id", array));
-        if (companyId.intValue() != user.getCompanyId().intValue() || !user.getRoleName().equals("超级管理员")) {
+        boolean manageAllProject = sysFunctionService.hasPriviledge(user.getRoleId(), "管理全部项目");
+        if (companyId.intValue() != user.getCompanyId().intValue() || !manageAllProject) {
             httpRespMsg.setError(MessageUtils.message("access.operationError"));
         } else {
             for (Integer id : array) {
-                System.out.println("删除项目id=="+id);
                 deleteProData(id);
                 Optional<Project> first = projectList.stream().filter(pl -> pl.getId().equals(id)).findFirst();
                 if(first.isPresent()){

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

@@ -105,6 +105,8 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
     @Resource
     private OvertimeMapper overtimeMapper;
     @Resource
+    private AbnormalItemMapper abnormalItemMapper;
+    @Resource
     private ReportDeleteService reportDeleteService;
     @Resource
     private UserFvTimeMapper userFvTimeMapper;
@@ -520,7 +522,7 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                     setConstructionStageList(reportList, stageList);
                 }
             }
-            if (timeType.getEnableNewWeeklyfill() == 1) {
+            if (timeType.getEnableNewWeeklyfill() == 1 || timeType.getEnableNewWeeklyfill() == 2) {
                 //新版按周填报有周总结
                 List<Integer> batchIds = new ArrayList<>();
                 for (Map map : nameList) {
@@ -690,7 +692,10 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
             reports.forEach(r->{
                 //设置项目名称
                 if(r.getDeptId()!=0){
-                    r.setUserReportDeptName(departmentList.stream().filter(f->f.getDepartmentId().equals(r.getDeptId())).findFirst().get().getDepartmentName());
+                    Department curDept = departmentList.stream().filter(f->f.getDepartmentId().equals(r.getDeptId())).findFirst().orElse(null);
+                    if (curDept != null) {
+                        r.setUserReportDeptName(curDept.getDepartmentName());
+                    }
                 }
                 r.setProjectName(allProjectList.stream().filter(p->p.getId().equals(r.getProjectId())).findFirst().get().getProjectName());
                 r.setSubProjectList(subProjectList.stream().filter(s->s.getProjectId().equals(r.getProjectId())).collect(Collectors.toList()));
@@ -1003,7 +1008,8 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                 //有加班申请模块
                 Overtime overtime = overtimeMapper.selectOne(new QueryWrapper<Overtime>()
                         //撤回,驳回,作废的不算
-                        .select("user_id, sum(duration) as duration").eq("user_id", userId).eq("date", date).ne("status", -1).ne("status", 3).ne("status", 4));
+                        .select("user_id, sum(duration) as duration").eq("user_id", userId)
+                        .eq("date", date).eq("status", 2));
                 if (overtime != null) {
                     //将秒转化为小时显示
                     resultMap.put("overtime", DateTimeUtil.getHoursFromSeconds(overtime.getDuration()));
@@ -1756,7 +1762,7 @@ 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) {
+            if (abnormalStartTime != null && abnormalEndTime != null && abnormalEndDay != null && !"undefined".equals(abnormalStartTime) && !"undefined".equals(abnormalEndTime)) {
                 //保存手动添加的考勤记录,添加到企微考勤表
                 LocalDate createDate = LocalDate.parse(date);
                 UserCorpwxTime userCorpwxTime = new UserCorpwxTime();
@@ -2521,6 +2527,7 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
         try {
             User curUser = userMapper.selectById(request.getHeader("Token"));
             Integer companyId = curUser.getCompanyId();
+            Company company = companyMapper.selectById(companyId);
             TimeType timeType = timeTypeMapper.selectById(companyId);
             Integer isParallel = timeType.getReportAuditType() == 7? 1 : 0;
             Integer isEngeering = companyMapper.selectById(companyId).getPackageEngineering();
@@ -2547,6 +2554,8 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                     }
                 }
             }
+            List<AbnormalItem> abnormalItemList = (companyId == Constant.XI_HE_CHAO_DAO_COMPANY_ID || companyId == Constant.XI_HE_CHAO_DAO_JIA_XING_COMPANY_ID) ?
+                    abnormalItemMapper.selectList(new QueryWrapper<AbnormalItem>().eq("company_id", companyId)) : new ArrayList<>();
 
             //抽取姓名,进行分组
             List<Map<String, Object>> nameList = new ArrayList<Map<String, Object>>();
@@ -2564,11 +2573,28 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                 if (lastName == null || !(lastName.get("name").equals(name) && lastName.get("dateStr").equals(createDate))) {
                     lastName = new HashMap<String, Object>();
                     lastName.put("dateStr", createDate);
+                    //是否为休息日
+                    boolean isWorkDay = WorkDayCalculateUtils.isWorkDay(LocalDate.parse(createDate));
+                    lastName.put("isWorkDay", isWorkDay);
                     lastName.put("name", name);
                     lastName.put("userId", uid);
                     lastName.put("corpwxUserid", corpwxUserid);
                     lastName.put("fillUserName", fillUserName);
                     lastName.put("abnormalTime", abnormalTime);
+                    //获取异常类型
+                    String abnormalName = "特殊填报";
+                    if (abnormalTime) {
+                        Integer abnormalType = (Integer)a.get("extraField2");
+                        if (abnormalType != null) {
+                            Optional<AbnormalItem> first = abnormalItemList.stream().filter(ai -> ai.getId().equals(abnormalType)).findFirst();
+                            if (first.isPresent()) {
+                                abnormalName = first.get().getName();
+                            }
+                        }
+                    } else {
+                        abnormalName = "正常填报";
+                    }
+                    lastName.put("abnormalName", abnormalName);
                     nameList.add(lastName);
                     userDailyReportList = new ArrayList<>();
                     lastName.put("data", userDailyReportList);
@@ -2614,6 +2640,13 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                 map2.put("deptAuditorName", list2.get(0).get("deptAuditorName"));
                 //增加填报人所属部门
                 map2.put("departmentName", list2.get(0).get("departmentName"));
+                //是否为异常填报
+                if (companyId == Constant.XI_HE_CHAO_DAO_JIA_XING_COMPANY_ID || companyId == Constant.XI_HE_CHAO_DAO_COMPANY_ID) {
+                    Integer extraField1 = (Integer)list2.get(0).get("extraField1");
+                    if (extraField1 != null && extraField1 == 1) {
+                        map2.put("abnormalTime", true);
+                    }
+                }
             }
             //设置照片显示
             for (Map map : nameList) {
@@ -2687,11 +2720,14 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                     //获取日期范围
                     userCorpwxTimeQueryWrapper.between("create_date", minDate, maxDate).eq("company_id", companyId);
                     List<UserCorpwxTime> timeList = userCorpwxTimeMapper.selectList(userCorpwxTimeQueryWrapper);
+                    List<Overtime> overtimeList = company.getPackageOvertime() == 1 ? overtimeMapper.selectList(
+                            new QueryWrapper<Overtime>().eq("company_id", companyId).between("date", minDate, maxDate).eq("status", 2)) : null;
                     //过滤匹配当前的数据
                     for (Map map : nameList) {
                         String corpwxUserid = (String)map.get("corpwxUserid");
                         String name = (String)map.get("name");
                         String dateStr = (String)map.get("dateStr");
+                        String currentUserId = (String) map.get("userId");
                         Optional<UserCorpwxTime> first = timeList.stream().filter(time -> ((time.getCorpwxUserid() != null && time.getCorpwxUserid().equals(corpwxUserid)) || (time.getCorpwxUserid() == null && name != null && name.equals(time.getName()))) && dtf.format(time.getCreateDate()).equals(dateStr)).findFirst();
                         if (first.isPresent()) {
                             double wh = first.get().getWorkHours();
@@ -2699,7 +2735,15 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                             map.put("cardHours", wh);
                             map.put("startTime", first.get().getStartTime());
                             map.put("endTime", first.get().getEndTime());
-                            map.put("overtime", first.get().getOtTime());//加班申请时长
+                            if (company.getPackageOvertime() == 1) {
+                                //赋值加班时长
+                                Optional<Overtime> first2 = overtimeList.stream().filter(o->o.getUserId().equals(currentUserId) && dtf.format(o.getDate()).equals(dateStr)).findFirst();
+                                if (first2.isPresent()) {
+                                    map.put("overtime", first2.get().getDuration()/3600.0);//加班申请时长
+                                }
+                            } else {
+                                map.put("overtime", first.get().getOtTime());//加班申请时长
+                            }
                             map.put("askLeaveTime", first.get().getAskLeaveTime());//请假时长
                         }
                     }
@@ -5282,6 +5326,10 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
         HttpRespMsg msg = new HttpRespMsg();
         User user = userMapper.selectById(userId);
         List<Integer> ids = ListUtil.convertIntegerIdsArrayToList(reportIds);
+        if (ids.isEmpty()) {
+            msg.setError("当前无日报可撤回");
+            return msg;
+        }
         int cnt = 0;
         List<SysRichFunction> functionList = sysFunctionMapper.getRoleFunctions(user.getRoleId(), "审核全员日报");
         List<Report> reportList = reportMapper.selectList(new QueryWrapper<Report>().in("id", ids));
@@ -10055,10 +10103,13 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
 
 
             List<Integer> collect = reportList.stream().map(Report::getProjectId).collect(Collectors.toList());
+            final List<ReportExtraDegree> degreeList = reportExtraDegreeMapper.selectList(new QueryWrapper<ReportExtraDegree>().eq("company_id", user.getCompanyId()));
+
             //加载这段时间内已填报过的项目
             List<Project> projectList = new ArrayList<>();
             if (collect.size() > 0) {
                 projectList = projectMapper.selectList(new QueryWrapper<Project>().in("id", collect));
+                final List<Project> finalProjectList = projectList;
                 //获取项目的任务分组列表
                 //需要是他参与的任务分组
                 List<GroupParticipator> groupParticipatorList = groupParticipatorMapper.selectList(new QueryWrapper<GroupParticipator>().eq("user_id", userId));
@@ -10099,6 +10150,41 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                                 }
                             }
                         }
+                        //设置项目名称
+                        Optional<Project> optional = finalProjectList.stream().filter(p->p.getId().equals(r.getProjectId())).findFirst();
+                        if (optional.isPresent()) {
+                            r.setProjectName(optional.get().getProjectName());
+                        }
+                        //设置自定义维度
+                        if (timeType.getCustomDegreeActive() == 1) {
+                            if (timeType.getCustomDegreeWithPro() == 1) {
+                                String associateDegrees = optional.get().getAssociateDegrees();
+                                List<HashMap> degreeMapList = new ArrayList<>();
+                                if (associateDegrees != null) {
+                                    String[] split = associateDegrees.split("\\,");
+                                    for (int i=0;i<split.length; i++) {
+                                        HashMap map = new HashMap();
+                                        if (!StringUtils.isEmpty(split[i])) {
+                                            Integer id = Integer.parseInt(split[i]);
+                                            map.put("id", id);
+                                            map.put("name", degreeList.stream().filter(d->d.getId().equals(id)).findFirst().get().getName());
+                                            degreeMapList.add(map);
+                                        }
+                                    }
+                                }
+                                r.setDegreeList(degreeMapList);
+                            } else {
+                                //把degreeList改成HashMap结构
+                                List<HashMap> mapDegreeList = new ArrayList<>();
+                                for (ReportExtraDegree degree : degreeList) {
+                                    HashMap map = new HashMap();
+                                    map.put("id", degree.getId());
+                                    map.put("name", degree.getName());
+                                    mapDegreeList.add(map);
+                                }
+                                r.setDegreeList(mapDegreeList);
+                            }
+                        }
                     });
                 }
             }

+ 103 - 105
fhKeeper/formulahousekeeper/timesheet/src/views/overtime/overtime_list.vue

@@ -37,8 +37,7 @@
                             placeholder="请选择加班日期"
                             value-format="yyyy-MM-dd"
                             v-model="addform.date"
-                            style="width:100%"
-                            @change="onOvertimeDateChange">
+                            style="width:100%">
                         </el-date-picker>
                     </el-form-item>
                     <!-- 对应班次 -->
@@ -52,7 +51,7 @@
                         </el-select>
                     </el-form-item>
                     <!-- 开始时间 & 结束时间 -->
-                    <el-form-item label="开始时间" prop="startTime" style="width:730px;display:block">
+                    <!-- <el-form-item label="开始时间" prop="startTime" style="width:730px;display:block">
                         <el-date-picker
                             type="datetime"
                             placeholder="请选择开始时间"
@@ -74,7 +73,7 @@
                             :time-arrow-control="true"
                             @change="calcDuration">
                         </el-date-picker>
-                    </el-form-item>
+                    </el-form-item> -->
                     <!-- 申请加班时长 -->
                     <el-form-item label="申请加班时长" prop="durationDisplay" style="width:350px;display:inline-block;margin-right:30px">
                         <el-input v-model="addform.durationDisplay" placeholder="根据时间自动计算" style="width:100%" @change="syncDurationFromDisplay">
@@ -184,8 +183,8 @@
                             <span v-else>白班 8:00-17:00</span>
                         </template>
                     </el-table-column>
-                    <el-table-column prop="startTime" label="开始时间" width="160" align="center"></el-table-column>
-                    <el-table-column prop="endTime" label="结束时间" width="160" align="center"></el-table-column>
+                    <!-- <el-table-column prop="startTime" label="开始时间" width="160" align="center"></el-table-column>
+                    <el-table-column prop="endTime" label="结束时间" width="160" align="center"></el-table-column> -->
                     <el-table-column label="加班时长" width="120" align="center">
                         <template slot-scope="scope">
                             <span v-if="scope.row.duration != null">
@@ -290,8 +289,7 @@
                     placeholder="请选择加班日期"
                     value-format="yyyy-MM-dd"
                     v-model="editItemForm.date"
-                    style="width:100%"
-                    @change="onEditOvertimeDateChange">
+                    style="width:100%">
                 </el-date-picker>
             </el-form-item>
             <!-- 对应班次 -->
@@ -305,7 +303,7 @@
                 </el-select>
             </el-form-item>
             <!-- 开始时间 & 结束时间 -->
-            <el-form-item label="开始时间" prop="startTime" style="width:100%;display:block">
+            <!-- <el-form-item label="开始时间" prop="startTime" style="width:100%;display:block">
                 <el-date-picker
                     type="datetime"
                     placeholder="请选择开始时间"
@@ -327,10 +325,10 @@
                     :time-arrow-control="true"
                     @change="calcEditDuration">
                 </el-date-picker>
-            </el-form-item>
+            </el-form-item> -->
             <!-- 申请加班时长 -->
             <el-form-item label="申请加班时长" prop="durationDisplay" style="width:300px;display:inline-block;margin-right:30px">
-                <el-input v-model="editItemForm.durationDisplay" placeholder="根据时间自动计算,可手动修改" style="width:100%" @change="syncEditDurationFromDisplay">
+                <el-input v-model="editItemForm.durationDisplay" placeholder="请填写加班时长" style="width:100%" @change="syncEditDurationFromDisplay">
                     <template slot="append">小时</template>
                 </el-input>
             </el-form-item>
@@ -662,99 +660,99 @@ export default {
         },
 
         // 加班日期变化时,自动将开始时间和结束时间的日期部分更新为加班日期(新增表单)
-        onOvertimeDateChange(val) {
-            if (val) {
-                // 更新开始时间日期部分
-                const startTimePart = this.addform.startTime ? this.addform.startTime.substring(10) : ' 00:00:00';
-                this.addform.startTime = val + startTimePart;
-                // 更新结束时间日期部分
-                const endTimePart = this.addform.endTime ? this.addform.endTime.substring(10) : ' 00:00:00';
-                this.addform.endTime = val + endTimePart;
-                this.calcDuration();
-            }
-        },
-
-        // 加班日期变化时,自动将开始时间的日期部分更新为加班日期(编辑表单)
-        onEditOvertimeDateChange(val) {
-            if (val && this.editItemForm.startTime) {
-                const timePart = this.editItemForm.startTime.substring(10);
-                this.$set(this.editItemForm, 'startTime', val + timePart);
-                this.calcEditDuration();
-            }
-        },
-
-        // 校验开始时间的日期是否不早于加班日期
-        validateStartTimeDate(date, startTime) {
-            if (!date || !startTime) return true;
-            const startDate = startTime.substring(0, 10);
-            return startDate >= date;
-        },
-
-        // 新增表单开始时间变化:将分钟和秒清零后再计算时长
-        onAddStartTimeChange(val) {
-            if (val) {
-                // 将分钟和秒清零,只保留到小时
-                const hourOnly = val.substring(0, 13) + ':00:00';
-                this.addform.startTime = hourOnly;
-            }
-            this.calcDuration();
-        },
-
-        // 编辑表单开始时间变化:将分钟和秒清零后再计算时长
-        onEditStartTimeChange(val) {
-            if (val) {
-                const hourOnly = val.substring(0, 13) + ':00:00';
-                this.$set(this.editItemForm, 'startTime', hourOnly);
-            }
-            this.calcEditDuration();
-        },
+        // onOvertimeDateChange(val) {
+        //     if (val) {
+        //         // 更新开始时间日期部分
+        //         const startTimePart = this.addform.startTime ? this.addform.startTime.substring(10) : ' 00:00:00';
+        //         this.addform.startTime = val + startTimePart;
+        //         // 更新结束时间日期部分
+        //         const endTimePart = this.addform.endTime ? this.addform.endTime.substring(10) : ' 00:00:00';
+        //         this.addform.endTime = val + endTimePart;
+        //         this.calcDuration();
+        //     }
+        // },
+
+        // // 加班日期变化时,自动将开始时间的日期部分更新为加班日期(编辑表单)
+        // onEditOvertimeDateChange(val) {
+        //     if (val && this.editItemForm.startTime) {
+        //         const timePart = this.editItemForm.startTime.substring(10);
+        //         this.$set(this.editItemForm, 'startTime', val + timePart);
+        //         this.calcEditDuration();
+        //     }
+        // },
+
+        // // 校验开始时间的日期是否不早于加班日期
+        // validateStartTimeDate(date, startTime) {
+        //     if (!date || !startTime) return true;
+        //     const startDate = startTime.substring(0, 10);
+        //     return startDate >= date;
+        // },
+
+        // // 新增表单开始时间变化:将分钟和秒清零后再计算时长
+        // onAddStartTimeChange(val) {
+        //     if (val) {
+        //         // 将分钟和秒清零,只保留到小时
+        //         const hourOnly = val.substring(0, 13) + ':00:00';
+        //         this.addform.startTime = hourOnly;
+        //     }
+        //     this.calcDuration();
+        // },
+
+        // // 编辑表单开始时间变化:将分钟和秒清零后再计算时长
+        // onEditStartTimeChange(val) {
+        //     if (val) {
+        //         const hourOnly = val.substring(0, 13) + ':00:00';
+        //         this.$set(this.editItemForm, 'startTime', hourOnly);
+        //     }
+        //     this.calcEditDuration();
+        // },
 
         // 计算需要扣除的午休时长(小时)
         // 规则:午休时段为 12:00-13:00,若开始时间在12点前且结束时间在12点后,
         // 则扣除实际落在午休时段内的时长(最多1小时)
         // 例如:结束时间为12:30,则只扣除0.5小时;结束时间>=13:00,则扣除1小时
-        calcLunchDeduction(startTimeStr, endTimeStr) {
-            const start = new Date(startTimeStr.replace(/-/g, '/'));
-            const end = new Date(endTimeStr.replace(/-/g, '/'));
-            // 构造当天12:00和13:00的时间点
-            const lunchStart = new Date(start);
-            lunchStart.setHours(12, 0, 0, 0);
-            const lunchEnd = new Date(start);
-            lunchEnd.setHours(13, 0, 0, 0);
-            // 只有开始时间在12点前且结束时间在12点后才需要扣除
-            if (start < lunchStart && end > lunchStart) {
-                // 实际重叠时段:[lunchStart, min(end, lunchEnd)]
-                const overlapEnd = end < lunchEnd ? end : lunchEnd;
-                const deductMs = overlapEnd - lunchStart;
-                return deductMs / (1000 * 60 * 60);
-            }
-            return 0;
-        },
+        // calcLunchDeduction(startTimeStr, endTimeStr) {
+        //     const start = new Date(startTimeStr.replace(/-/g, '/'));
+        //     const end = new Date(endTimeStr.replace(/-/g, '/'));
+        //     // 构造当天12:00和13:00的时间点
+        //     const lunchStart = new Date(start);
+        //     lunchStart.setHours(12, 0, 0, 0);
+        //     const lunchEnd = new Date(start);
+        //     lunchEnd.setHours(13, 0, 0, 0);
+        //     // 只有开始时间在12点前且结束时间在12点后才需要扣除
+        //     if (start < lunchStart && end > lunchStart) {
+        //         // 实际重叠时段:[lunchStart, min(end, lunchEnd)]
+        //         const overlapEnd = end < lunchEnd ? end : lunchEnd;
+        //         const deductMs = overlapEnd - lunchStart;
+        //         return deductMs / (1000 * 60 * 60);
+        //     }
+        //     return 0;
+        // },
 
         // 计算加班时长(新增表单)
-        calcDuration() {
-            if (this.addform.startTime && this.addform.endTime) {
-                const start = new Date(this.addform.startTime.replace(/-/g, '/'));
-                const end = new Date(this.addform.endTime.replace(/-/g, '/'));
-                const diffMs = end - start;
-                if (diffMs > 0) {
-                    let diffHours = diffMs / (1000 * 60 * 60);
-                    // 扣除午休时长
-                    const lunchDeduct = this.calcLunchDeduction(this.addform.startTime, this.addform.endTime);
-                    if (lunchDeduct > 0) {
-                        diffHours = diffHours - lunchDeduct;
-                        if (diffHours < 0) diffHours = 0;
-                    }
-                    const diffSeconds = Math.round(diffHours * 3600);
-                    this.addform.duration = diffSeconds;
-                    this.addform.durationDisplay = diffHours.toFixed(2);
-                } else {
-                    this.addform.duration = null;
-                    this.addform.durationDisplay = null;
-                    this.$message({ message: '结束时间不能早于开始时间', type: 'warning' });
-                }
-            }
-        },
+        // calcDuration() {
+        //     if (this.addform.startTime && this.addform.endTime) {
+        //         const start = new Date(this.addform.startTime.replace(/-/g, '/'));
+        //         const end = new Date(this.addform.endTime.replace(/-/g, '/'));
+        //         const diffMs = end - start;
+        //         if (diffMs > 0) {
+        //             let diffHours = diffMs / (1000 * 60 * 60);
+        //             // 扣除午休时长
+        //             const lunchDeduct = this.calcLunchDeduction(this.addform.startTime, this.addform.endTime);
+        //             if (lunchDeduct > 0) {
+        //                 diffHours = diffHours - lunchDeduct;
+        //                 if (diffHours < 0) diffHours = 0;
+        //             }
+        //             const diffSeconds = Math.round(diffHours * 3600);
+        //             this.addform.duration = diffSeconds;
+        //             this.addform.durationDisplay = diffHours.toFixed(2);
+        //         } else {
+        //             this.addform.duration = null;
+        //             this.addform.durationDisplay = null;
+        //             this.$message({ message: '结束时间不能早于开始时间', type: 'warning' });
+        //         }
+        //     }
+        // },
 
         // 手动修改时长显示后同步到 duration(新增表单)
         syncDurationFromDisplay(val) {
@@ -892,10 +890,10 @@ export default {
             this.$refs.addformOT.validate(valid => {
                 if (valid) {
                     // 校验开始时间的日期是否不早于加班日期
-                    if (this.addform.startTime && !this.validateStartTimeDate(this.addform.date, this.addform.startTime)) {
-                        this.$message({ message: '开始时间不能早于加班日期', type: 'warning' });
-                        return;
-                    }
+                    // if (this.addform.startTime && !this.validateStartTimeDate(this.addform.date, this.addform.startTime)) {
+                    //     this.$message({ message: '开始时间不能早于加班日期', type: 'warning' });
+                    //     return;
+                    // }
                     this.formloading = true;
                     // 根据班次设置isNightShift
                     const submitData = Object.assign({}, this.addform);
@@ -985,10 +983,10 @@ export default {
             this.$refs.editItemForm.validate(valid => {
                 if (valid) {
                     // 校验开始时间的日期是否不早于加班日期
-                    if (this.editItemForm.startTime && !this.validateStartTimeDate(this.editItemForm.date, this.editItemForm.startTime)) {
-                        this.$message({ message: '开始时间不能早于加班日期', type: 'warning' });
-                        return;
-                    }
+                    // if (this.editItemForm.startTime && !this.validateStartTimeDate(this.editItemForm.date, this.editItemForm.startTime)) {
+                    //     this.$message({ message: '开始时间不能早于加班日期', type: 'warning' });
+                    //     return;
+                    // }
                     const submitData = Object.assign({}, this.editItemForm);
                     submitData.isNightShift = submitData.shiftType !== 'day';
                     delete submitData.shiftType;

Plik diff jest za duży
+ 1291 - 0
fhKeeper/formulahousekeeper/timesheet/src/views/settings/timetype.vue


+ 79 - 24
fhKeeper/formulahousekeeper/timesheet/src/views/workReport/daily.vue

@@ -228,7 +228,7 @@
                                                                 <!-- {{($t('other.await') +' '+ item2.auditDeptName +' '+ $t('other.audit'))}} -->
                                                                 ({{$t('other.await')}}
                                                                 <TranslationOpenData :configurationItems="{ openType: 'departmentName', openId: user.timeType.reportAuditType==4?item2.buDepartmentName:item2.auditDeptName, renderIndex: 0 }" />
-                                                                {{$t('other.audit')}})
+                                                                (<TranslationOpenData :configurationItems="{ openType: 'userName', openId: item2.deptAuditorName, renderIndex: 0 }" />){{$t('other.audit')}})
                                                             </span>
                                                         </span>
                                                         ]</span> 
@@ -473,14 +473,20 @@
                         
                         <span v-if="user.companyId==5978" style="margin-left:5px;" class="themeFontColor"><i class="el-icon-warning"></i>{{$t('other.kaoqingTimeTip')}}</span>
 
-                        <!--针对羲和超导的异常填报功能-->
+                        <!--针对羲和超导的特殊填报功能-->
                         <template v-if="(user.companyId == 8555 || user.companyId ==5792)">
-                            <span style="margin-left:70px;color:#666;">异常填报</span>
+                            <span style="margin-left:70px;color:#666;">特殊填报</span>
                             <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 && canEdit" :rules="{ required: true, message: '请选择异常类型', trigger: 'blur' }">
+                        <el-select v-model="workForm.abnormalItemId" placeholder="请选择异常类型" style="width:200px;" :disabled="!canEdit" @change="onAbnormalItemChange">
+                            <el-option v-for="item in abnormalItemList" :key="item.id" :label="item.name" :value="item.id"></el-option>
+                        </el-select>
+                    </el-form-item>
                     <!--异常填报打卡时间选择-->
-                    <el-form-item label="补考勤" v-if="(user.companyId == 8555 || user.companyId ==5792) && workForm.abnormalTime && !workForm.time && canEdit">
+                    <el-form-item label="补考勤" v-if="(user.companyId == 8555 || user.companyId ==5792) && workForm.abnormalTime && canEdit && selectedAbnormalItem && selectedAbnormalItem.requireCardtime">
                         <el-time-picker
                             v-model="workForm.abnormalStartTime"
                             :placeholder="'上班时间'"
@@ -504,7 +510,7 @@
                         </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>
+                    <el-form-item label="已通过加班申请" v-if="workForm.overtime"><span style="color:#FFA500;">{{ workForm.overtime.toFixed(1) }} h</span></el-form-item>
                     <!-- 000000 -->
                     <div v-for="(domain, index) in workForm.domains" :key="domain.id" :style="index>0?'padding-top:25px;':''" >
                         <div v-if="reportTimeType.multiWorktime==0">
@@ -878,8 +884,8 @@
                         </el-form-item>
 
                         <!-- 拍照上传 -->
-                        <el-form-item :label="$t('tuPianShangChuan')" v-if="user.timeType.choseFromAlbum == 1 || ((user.companyId == 8555 || user.companyId ==5792 ) && workForm.abnormalTime)" :prop="'domains.' + index + '.imgListUrl'" 
-                        :rules="isCustomization(user, reportPictureRequired) ? { required: true, message: $t('pleaseselectpictures'), trigger: 'blur' } : null">
+                        <el-form-item :label="$t('tuPianShangChuan')" v-if="user.timeType.choseFromAlbum == 1 || ((user.companyId == 8555 || user.companyId ==5792 ) &&workForm.abnormalTime && selectedAbnormalItem && selectedAbnormalItem.requirePicture)" :prop="'domains.' + index + '.imgListUrl'" 
+                        :rules="isCustomization(user, reportPictureRequired) ? { required: true, message: '请上传凭证照片', trigger: 'blur' } : null">
                             <div class="photos">
                                 <div>
                                     <el-upload
@@ -1245,7 +1251,7 @@
         </el-dialog>
 
         <!-- enableNewWeeklyfill==2 -->
-        <el-dialog :title="$t('textLink.fillInAWeek')" class="fillWeekCustom" :visible.sync="fillWeekDialogVisiCustomTwo" width="1400px" :before-close="handleClose" top="7.5vh">
+        <el-dialog :title="$t('textLink.fillInAWeek')" class="fillWeekCustom" :visible.sync="fillWeekDialogVisiCustomTwo" width="1500px" :before-close="handleClose" top="7.5vh">
             <div class="fillWeekDialogVisiCustom">
                 <NewWeeklyCustomization @weekClose="fillWeekCustomClneTwo" @weekSubmit="fillWeekCustomSubmit" :key="weekIndex" :weekParentData="weekParentData"></NewWeeklyCustomization>
             </div>
@@ -3049,6 +3055,9 @@
                         name: '陕西柘中建设工程有限公司' 
                     }
                 ],
+                // 异常列表相关数据
+                abnormalItemList: [],
+                selectedAbnormalItem: null,
                 pushWorkTimeLogDig:false,
                 pushWorkTimeLogData:[],
 
@@ -3143,6 +3152,9 @@
             if (this.user.timeType.minReportTime) {
                 this.timeRange = this.timeRange.filter(item => {return item >= this.user.timeType.minReportTime})
             }
+            if (this.user.companyId == 8555 || this.user.companyId == 5792) {
+                this.loadAbnormalItemList();
+            }
 
             const that = this
             if(this.user.userNameNeedTranslate == 1) {
@@ -3166,6 +3178,31 @@
                 if (val) {
                     this.$set(this.workForm, 'abnormalStartTime', '08:00');
                     this.$set(this.workForm, 'abnormalEndTime', '17:00');
+                    this.$set(this.workForm, 'abnormalItemId', null);
+                    this.selectedAbnormalItem = null;
+                } else {
+                    this.$set(this.workForm, 'abnormalItemId', null);
+                    this.selectedAbnormalItem = null;
+                }
+            },
+            // 加载异常类型列表
+            loadAbnormalItemList() {
+                this.http.post('/abnormal-item/list', {}, res => {
+                    if (res.code == 'ok') {
+                        this.abnormalItemList = res.data || [];
+                    } else {
+                        this.$message({ message: res.msg, type: 'error' });
+                    }
+                }, err => {
+                    this.$message({ message: err, type: 'error' });
+                });
+            },
+            // 异常类型选择变化事件
+            onAbnormalItemChange(val) {
+                if (val) {
+                    this.selectedAbnormalItem = this.abnormalItemList.find(item => item.id === val) || null;
+                } else {
+                    this.selectedAbnormalItem = null;
                 }
             },
             // 格式化内容,将换行符转换为HTML的<br>标签
@@ -3773,6 +3810,8 @@
                         }
                         this.workForm.domains[index].imgList.push(res.data)
                         this.workForm.domains[index].imgListUrl.push({ name: '990' ,url: '/upload/' + res.data})
+                        // 上传图片后清除该字段的校验错误提示
+                        this.$refs.workForm.clearValidate('domains.' + index + '.imgListUrl');
                     } else {
                         this.$message({message: res.msg,type: "error"});
                     }
@@ -7358,12 +7397,16 @@
                             let candelete = true
                             const { reportExtraField4Name, reportExtraField5Name } = this.user.timeType
                             var abnormalTime = false;
+                            var abnormalItemId = null;
                             for(var i in list.report) {
                                 var flg = null
                                 if ((this.user.companyId == 8555 || this.user.companyId ==5792 )) {
                                     if (list.report[i].extraField1) {
                                         abnormalTime = true;
                                     }
+                                    if (list.report[i].extraField2) {
+                                        abnormalItemId = list.report[i].extraField2;
+                                    }
                                 }
                                 list.report[i].isOvertime == 1 ? flg = true : flg = false
                                 var targetP = this.fillProjectList.filter(p=>p.id == list.report[i].projectId);
@@ -7474,9 +7517,13 @@
                                 time: list.time,
                                 showRefresh: list.showRefresh,
                                 abnormalTime: abnormalTime,
+                                abnormalItemId: abnormalItemId,
                                 overtime: list.overtime,
                                 abnormalEndDay: '0'
                             }
+                            if (abnormalItemId) {
+                                this.selectedAbnormalItem = this.abnormalItemList.filter(a=>a.id == abnormalItemId)[0];
+                            }
                             if(res.data.timeType.type == 3) {
                                 const reportCalculationReportList = res.data.report || []
                                 copyWorkForm.totalDuration = reportCalculationReportList.reduce((accumulator, current) => {
@@ -9505,20 +9552,22 @@
                         
                         if (!this.isBatch) {
                             if ((this.user.companyId == 8555 || this.user.companyId ==5792 ) && this.workForm.abnormalTime) {
-                                //异常上报情况,需要上传图片
-                                var findImg = false;
-                                for (var t=0;t<this.workForm.domains.length; t++) {
-                                    if(this.workForm.domains[t].imgList != null && this.workForm.domains[t].imgList.length > 0) {
-                                        findImg = true;
-                                        break;
+                                if (this.selectedAbnormalItem && this.selectedAbnormalItem.requirePicture) {
+                                    //异常上报情况,需要上传图片
+                                    var findImg = false;
+                                    for (var t=0;t<this.workForm.domains.length; t++) {
+                                        if(this.workForm.domains[t].imgList != null && this.workForm.domains[t].imgList.length > 0) {
+                                            findImg = true;
+                                            break;
+                                        }
+                                    }
+                                    if (!findImg) {
+                                        this.$message({
+                                            message: '异常上报需上传凭证截图',
+                                            type: 'error'
+                                        })
+                                        return
                                     }
-                                }
-                                if (!findImg) {
-                                    this.$message({
-                                        message: '异常上报需上传凭证截图',
-                                        type: 'error'
-                                    })
-                                    return
                                 }
                             } else if(this.user.timeType.notAllowedNoAttendance == 1 && this.isDraft == 0 && !(this.isSubstitude && this.user.timeType.notCheckCardtime)){
                                 if (this.workForm.time){
@@ -9912,9 +9961,15 @@
                             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('abnormalItemId', this.workForm.abnormalItemId);
+                                    if (this.workForm.abnormalStartTime) {
+                                        //补的考勤时间
+                                        formData.append('abnormalStartTime', this.workForm.abnormalStartTime);
+                                    }
+                                    if (this.workForm.abnormalEndTime) {
+                                        formData.append('abnormalEndTime', this.workForm.abnormalEndTime);
+                                    }
+                                    
                                     formData.append('abnormalEndDay', this.workForm.abnormalEndDay);
                                 }
                             }

+ 60 - 1
fhKeeper/formulahousekeeper/timesheet/src/views/workReport/dailyReportReview.vue

@@ -84,6 +84,7 @@
           <el-table :data="list" ref="multipleTable" v-if="showTable" :height="reviewTableHeight" :key="reviewTableHeightKey" highlight-current-row v-loading="listLoading" style="width: 100%;"
               @selection-change="handleSelectionChange" :default-expand-all="defaultExpandAllFlg" @expand-change="expandChange">
               <el-table-column type="selection" width="55"></el-table-column>
+
               <el-table-column type="expand" :label="''" v-if="user.companyId != 469">
                   <template slot="header">
                       <i :class="defaultExpandAllFlg ? 'el-icon-arrow-down' : 'el-icon-arrow-right'" style="cursor: pointer;" @click="defaultExpandAllFlgCli()"></i>
@@ -232,12 +233,20 @@
                   </template>
               </el-table-column>
               <el-table-column prop="dateStr" :label="$t('weekDay.date')" sortable>
+                <template slot-scope="scope">
+                    {{scope.row.dateStr}} &nbsp; &nbsp; <el-tag v-if="!scope.row.isWorkDay">休</el-tag>
+                </template>
               </el-table-column>
               <el-table-column prop="reportTime" :label="$t('screening.workTime') + '(h)'" v-if="user.companyId != 469">
                   <template slot-scope="scope">
                       {{scope.row.reportTime | amounts}}
                   </template>
               </el-table-column>
+              <el-table-column prop="abnormalName" label="特殊填报" v-if="user.companyId == 8555 || user.companyId == 5792">
+                  <template slot-scope="scope">
+                      <span :style="scope.row.abnormalTime?'color:red':''">{{scope.row.abnormalName}}</span>
+                  </template>
+              </el-table-column>
               <el-table-column width="320" prop="cardHours" :label="$t('workAttendance') + '(h)'" v-if="user.timeType.showCorpwxCardtime==1||user.timeType.showDdCardtime==1 || user.timeType.syncFanwei==1">
                   <template slot-scope="scope">
                     <div style="display: flex;align-items: center;">
@@ -525,6 +534,18 @@
           </div>
       </el-dialog>
 
+      <!-- 特殊填报人工复核确认弹窗 -->
+      <el-dialog title="特殊填报审核提示" :visible.sync="abnormalConfirmDialog" :close-on-click-modal="false" width="500px">
+          <div style="padding: 10px 0;">
+              <i class="el-icon-warning" style="color:#E6A23C;font-size:20px;margin-right:8px;"></i>
+              <span style="font-size:14px;">该工时申请为特殊填报,请人工复确认证明附件及手工录入考勤及对应加班申请。</span>
+          </div>
+          <div slot="footer" class="dialog-footer">
+              <el-button @click="abnormalConfirmDialog = false">返回检查</el-button>
+              <el-button type="primary" @click="abnormalConfirmApprove()">已完成检查同意</el-button>
+          </div>
+      </el-dialog>
+
       <!-- 审核通过评价 -->
       <el-dialog :title="$t('enterapassrating')" v-if="approveinDialog" :visible.sync="approveinDialog" :close-on-click-modal="false" customClass="customWidth" width="500px">
           <div>
@@ -557,6 +578,7 @@
       },
       data() {
           return {
+              abnormalItemList: [],
               allConstructionStages:[],
               exportLoading: false,
               yuzhongCompId: 3385,
@@ -632,7 +654,9 @@
                   reason: ''
               },
               undoBathFormLoading: false,
-              refreshAttendanceLoading: false
+              refreshAttendanceLoading: false,
+              abnormalConfirmDialog: false,
+              abnormalConfirmData: null,
           };
       },
       filters: {
@@ -719,6 +743,18 @@
                   });
               });
           },
+            // 加载异常类型列表
+            loadAbnormalItemList() {
+                this.http.post('/abnormal-item/list', {}, res => {
+                    if (res.code == 'ok') {
+                        this.abnormalItemList = res.data || [];
+                    } else {
+                        this.$message({ message: res.msg, type: 'error' });
+                    }
+                }, err => {
+                    this.$message({ message: err, type: 'error' });
+                });
+            },
           clickBathCancel() {
               this.undoBathFormLoading = true
               this.http.post('/report/batchDenyHisReport', this.undoBathForm,
@@ -1121,6 +1157,26 @@
               this.approveinData = {
                   reportIds: ids
               }
+
+              // 如果是特殊填报,先弹窗提示人工复核
+              if (item.abnormalTime) {
+                  this.abnormalConfirmData = { reportIds: ids };
+                  this.abnormalConfirmDialog = true;
+                  return;
+              }
+
+              if(this.user.timeType.needEvaluate == 1){
+                  this.$set(this.approveinData,'evaluate','')
+                  this.approveinDialog = true
+              }else{
+                  this.logining = true;
+                  this.approveinfun()
+              }
+          },
+          // 特殊填报确认同意后执行审核通过
+          abnormalConfirmApprove() {
+              this.abnormalConfirmDialog = false;
+              this.approveinData = { reportIds: this.abnormalConfirmData.reportIds };
               if(this.user.timeType.needEvaluate == 1){
                   this.$set(this.approveinData,'evaluate','')
                   this.approveinDialog = true
@@ -1349,6 +1405,9 @@
           if (this.user.companyId == 4811) {
             this.getConstructionStageList();
           }
+          if (this.user.companyId == 8555 || this.user.companyId == 5792) {
+            this.loadAbnormalItemList();
+          }
       }
   };
 </script>

+ 293 - 53
fhKeeper/formulahousekeeper/timesheet/src/views/workReport/newWeeklyCustomization.vue

@@ -4,6 +4,7 @@
             <el-button @click="getCurrentWeek(-7)" size="small">&lt;&lt;</el-button>
             <el-button @click="getCurrentWeek(0)" size="small">{{ $t('time.thisWeek') }}</el-button>
             <el-button @click="getCurrentWeek(7)" size="small">&gt;&gt;</el-button>
+            <el-button @click="refreshCardTime()" size="small" style="margin-left:20px;" :loading="isRefreshing">刷新考勤</el-button>
         </div>
         <div class="weekcen flexColumn" v-loading="submitLoading">
             <div class="flexColumnAuto flex1">
@@ -12,26 +13,48 @@
                         <template slot-scope="scope">
                             <span>{{ scope.row.dateTime }}</span>
                             (<span>{{ scope.row.weekDayTxt }}</span>)
+                            <span v-if="scope.row.time && scope.row.time.askLeaveTime > 0" style="color:green;">请假{{scope.row.time.askLeaveTime}}h</span>
                         </template>
                     </el-table-column>
-                    <el-table-column :label="$t('other.project')" width="220">
+                    <el-table-column :label="$t('other.project')" >
                         <template slot-scope="scope">
                             <el-select v-model="scope.row.projectId" size="small" :placeholder="$t('defaultText.pleaseSelectSnItem')" clearable
                                 @change="changeProject(scope.row.projectId, scope.$index)" filterable
                                 :disabled="scope.row.state == 1 || scope.row.state == 0 || !scope.row.canFill">
-                                <el-option v-for="item in projectList" :key="item.id" :label="item.projectName + '\u3000' + item.projectCode"
+                                <el-option v-for="item in projectList" :key="item.id" :label="item.projectName"
                                     :value="item.id">
-                                    <span style="float: left; color: #8492a6; font-size: 13px;">{{ item.projectCode }}</span>
-                                    <span style="float: right;padding-left: 10px">{{ item.projectName }}</span>
                                 </el-option>
                             </el-select>
                         </template>
                     </el-table-column>
-                    <el-table-column prop="content" :label="$t('gongZuoNeiRong')">
+                    <el-table-column label="研发工时" >
                         <template slot-scope="scope">
-                            <el-input size="small" type="textarea" :rows="2" v-model="scope.row.content"
-                                :disabled="scope.row.state == 1 || scope.row.state == 0 || !scope.row.canFill"
-                                resize="none"></el-input>
+                            <el-select v-model="scope.row.degreeId" size="small" placeholder="请选择" filterable
+                                :disabled="scope.row.state == 1 || scope.row.state == 0 || !scope.row.canFill">
+                                <el-option v-for="item in scope.row.wuduList" :key="item.id" :label="item.name"
+                                    :value="item.id">
+                                </el-option>
+                            </el-select>
+                        </template>
+                    </el-table-column>
+                    <el-table-column :label="$t('fenZu')" v-if="!user.timeType.hideGroup">
+                        <template slot-scope="scope">
+                            <el-select v-model="scope.row.groupId" size="small" :placeholder="$t('selectagroup')"
+                                :disabled="scope.row.state == 1 || scope.row.state == 0 || !scope.row.canFill">
+                                <el-option v-for="item in scope.row.taskGroups" :key="item.id" :label="item.name"
+                                    :value="item.id">
+                                </el-option>
+                            </el-select>
+                        </template>
+                    </el-table-column>
+                    <el-table-column prop="content" label="工作内容" width="300">
+                        <template slot-scope="scope">
+                            <div>
+                                <el-input size="small" type="textarea" :rows="2" v-model="scope.row.content"
+                                    :disabled="scope.row.state == 1 || scope.row.state == 0 || !scope.row.canFill"
+                                    resize="none" :maxlength="user.companyId == wuqiId && 30" :show-word-limit="user.companyId == wuqiId" :placeholder="user.companyId == wuqiId ? '所在项目负责哪一模块(可重复填写),无需涉及技术细节。' : '' ">                                
+                            </el-input>
+                            </div>
                         </template>
                     </el-table-column>
                     <el-table-column prop="workingTime" :label="$t('shiJianXiaoShi')" width="160">
@@ -40,7 +63,15 @@
                                 :disabled="scope.row.state == 1 || scope.row.state == 0 || !scope.row.canFill"></el-input-number>
                         </template>
                     </el-table-column>
-                    <el-table-column prop="state" :label="$t('state.states')" width="140" fixed="right">
+                    <!-- <el-table-column prop="projectAuditorId" :label="$t('approver')" width="160">
+                        <template slot-scope="scope">
+                            <span v-if="user.userNameNeedTranslate != '1'">{{ auditorNameFun(scope.row) }}</span>
+                            <span v-if="user.userNameNeedTranslate == '1'">
+                                <TranslationOpenDataText type='userName' :openid='auditorNameFun(scope.row)'></TranslationOpenDataText>
+                            </span>
+                        </template>
+                    </el-table-column> -->
+                    <el-table-column prop="state" label="状态" width="140" fixed="right">
                         <template slot-scope="scope">
                             <div class="controls">
                                 <el-tag v-if="scope.row.state == 0" type="warning">{{ $t('daiShen') }}</el-tag>
@@ -57,6 +88,28 @@
                     </el-table-column>
                 </el-table>
             </div>
+            <div class="weeklySummary">
+                <div class="weekly"><span style="font: size 14px;">周报</span>
+                    <br/>
+                <el-upload
+                class="upload-demo"
+                :on-preview="handlePreview"
+                :on-remove="handleRemove"
+                :before-remove="beforeRemove"
+                :http-request="uploadFile"
+                multiple
+                :limit="5"
+                :on-exceed="handleExceed"
+                :file-list="fileList">
+                <el-button size="small" type="primary" :loading="upLoading">上传附件</el-button>
+                <div slot="tip" class="el-upload__tip">附件大小不超过10M</div>
+                </el-upload>
+                </div>
+                <el-input type="textarea" :autosize="{ minRows: 4, maxRows: 6}" maxlength="1000" show-word-limit
+                    :placeholder="'本周主要工作回顾、遗留事宜的初步处理方案和预计完成时间、下周工作的计划,尽可能详细。'"
+                    v-model="summaryContent" style="flex: 1;">
+                    </el-input>
+            </div>
             <div class="weeklyCustomization_btn">
                 <el-button @click="handleClose()">{{ $t('quXiao') }}</el-button>
                 <el-button @click="submitWeekData(1)">{{ $t('zanCun') }}</el-button>
@@ -81,6 +134,10 @@ export default {
     },
     data() {
         return {
+            isRefreshing: false,
+            serverFileList:[],
+            upLoading: false,
+            fileList:[],
             summaryContent: null,
             weekTableData: [],
             projectList: [],
@@ -88,6 +145,7 @@ export default {
             submitLoading: false,
             permissions: JSON.parse(sessionStorage.getItem("permissions")),
             user: JSON.parse(sessionStorage.getItem("user")),
+            wuqiId: '1071'
         }
     },
     computed: {},
@@ -99,23 +157,100 @@ export default {
         this.getProjectList()
     },
     methods: {
+        async refreshCardTime() {
+            this.isRefreshing = true;
+            var dateArray = this.weekTableData.map(item=>item.dateTime);
+            console.log(dateArray);
+            let { data } = await this.getData('/user-corpwx-time/refreshWeeklyCardTime',  {dateArray: JSON.stringify(dateArray)})
+            this.isRefreshing = false;
+            for (var i=0;i<this.weekTableData.length; i++) {
+                for (var j=0;j<data.length; j++) {
+                    if (data[j].createDate == this.weekTableData[i].dateTime) {
+                        this.weekTableData[i].time = data[j]
+                    }
+                }
+            }
+        },
+        handleRemove(file, fileList) {
+            console.log(file, fileList);
+            console.log('删除的文件名=='+file.name);
+            console.log('服务器文件数组=='+this.serverFileList);
+            for (var i=0;i<this.serverFileList.length; i++) {
+                if (this.serverFileList[i].originName == file.name) {
+                    this.serverFileList.splice(i,1);
+                    break;
+                }
+            }
+        },
+        handlePreview(file) {
+            console.log(file);
+        },
+        handleExceed(files, fileList) {
+            this.$message.warning(`最多上传5个文件`);
+        },
+        beforeRemove(file, fileList) {
+            return this.$confirm(`确定移除 ${ file.name }?`);
+        },
+        //上传
+        uploadFile(params) {
+            this.upLoading = true;
+            var fileObj = params.file;
+            var form = new FormData();
+            form.append("multipartFile", fileObj);
+            this.http.uploadFile('/common/uploadFile', form , res => {
+                this.upLoading = false;
+                if (res.code == "ok") {
+                    this.$message({
+                        message: this.$t('uploadedsuccessfully'),
+                        type: 'success'
+                    });
+                    this.serverFileList.push({'originName':fileObj.name,'serverName':res.data});
+                } else {
+                    this.$message({
+                        message: res.msg,
+                        type: 'error'
+                    });
+                }
+                console.log(this.fileList);
+            }, error => {
+                this.upLoading = false;
+                this.$message({
+                    message: error,
+                    type: 'error'
+                });
+            })
+        },
+
+        //下载
+        dowloadFile(row) {
+            this.http.post(this.port.project.dowloadFile, {
+                id: row.id
+            } , res => {
+                this.getOperList();
+            }, error => {
+            })
+        },
         // 提交与暂存
         submitWeekData(draft) { // draft 暂存(1)提交(0)
             const newWeekData = cloneDeep(this.weekTableData)
-
+            console.log('总文件数=='+this.serverFileList.length);
+            console.log(this.serverFileList);
             let strArr = this.judgmentData(newWeekData)
             const { allday } = this.user.timeType // 系统设置的每日工作时间
-            // if (strArr.length > 0) {
-            //     this.$message({
-            //         message: `【${strArr.join('、')}】`+this.$t('tianXieGongShiHeJiFei')+` ${allday}`+ this.$t('time.hour'),
-            //         type: "error"
-            //     });
-            //     return
-            // }
+            if (strArr.length > 0) {
+                this.$message({
+                    message: `【${strArr.join('、')}】`+'每日填写工时合计不可超过'+` ${allday}`+ this.$t('time.hour'),
+                    type: "error"
+                });
+                return
+            }
 
             let formData = new FormData();
             formData.append("draft", draft);
             formData.append('summary', this.summaryContent);
+            if (this.serverFileList.length > 0) {
+                formData.append('weeklyAttachment', JSON.stringify(this.serverFileList));
+            }
             let fixation = {
                 id: -1,
                 projectId: '',
@@ -126,14 +261,18 @@ export default {
                 multiWorktime: 0,
                 content: '',
                 isOvertime: 0,
+                // professionProgress: [],
+                groupId: '',
+                stage: '',
                 createDate: '',
+                projectAuditorId: '',
                 basecostId: 0,
                 degreeId: -1,
                 customData: 0,
                 customText: '-',
             }
 
-            let arr = newWeekData
+            const arr = newWeekData
                 .filter(data => data.projectId)
                 .map(data => ({
                     ...fixation,
@@ -144,18 +283,35 @@ export default {
                     workingTime: data.workingTime,
                     groupId: data.groupId,
                     id: data.id || -1,
+                    degreeId: data.degreeId || -1
                 }));
-
-            arr.forEach(item => { 
-                delete item.groupId
-            })
-                
+            let flag = false
             arr.forEach(item => {
+                if(item.projectId && !item.content && this.user.companyId == this.wuqiId) {
+                    this.$message({
+                        type: 'warning',
+                        message: `${item.createDate} 日报请填写完整`,
+                    })
+                    flag = true
+                    return
+                } else {
+                    flag = false
+                }
                 Object.entries(item).forEach(([key, value]) => {
                     formData.append(key, value);
                 });
             });
-
+            const hasProjectIdValue = arr.some(obj => obj.projectId && obj.projectId !== '');
+            if(hasProjectIdValue && !this.summaryContent && this.user.companyId == this.wuqiId) {
+                this.$message({
+                    type: 'warning',
+                    message: `请填写周报`,
+                })
+                return
+            }
+            if(flag) {
+                return
+            }
             this.submitLoading = true
             this.http.uploadFile(this.port.report.editPort, formData,
                 res => {
@@ -185,7 +341,6 @@ export default {
         // 判断是否小于系统设置的每日工作时间
         judgmentData(data) {
             const { allday } = this.user.timeType // 系统设置的每日工作时间
-            console.log(allday, '<======= 填写日报时长allday')
             const result = [];
             data.forEach((item) => {
                 const date = item.dateTime;
@@ -201,7 +356,7 @@ export default {
             const strArr = result
                 .filter((arr) => arr[0].projectId)
                 .filter(
-                    (arr) => arr.reduce((sum, item) => sum + (+item.workingTime || 0), 0) != allday
+                    (arr) => arr.reduce((sum, item) => sum + (+item.workingTime || 0), 0) > allday
                 )
                 .map((arr) => arr[0].dateTime);
 
@@ -212,9 +367,18 @@ export default {
             this.$set(this.weekTableData[index], 'projectAuditorId', '')
             this.$set(this.weekTableData[index], 'projectAuditorName', '')
             this.$set(this.weekTableData[index], 'groupId', '')
-            // if (projectId) {
-            //     this.getProjectGroup(projectId, index)
-            // }
+            this.$set(this.weekTableData[index], 'projectName', '')
+            if (projectId) {
+                var pName = this.projectList.filter(p=>p.id == projectId)[0].projectName + '-';
+                this.$set(this.weekTableData[index], 'projectName', pName)
+                this.getTaskGroups(projectId, index);
+                // 获取项目相关的维度
+                // domain.degreeId = null
+                this.$set(this.weekTableData[index],'degreeId',null)
+                this.$set(this.weekTableData[index],'multiDegrIdArray',null)
+                this.dimension(projectId, index);
+                
+            }
         },
         // 分组切换事件
         changeGroup(groupId, groupList, index) {
@@ -239,6 +403,16 @@ export default {
             let { data } = await this.getData('/report/getWeeklyFillReportData', { targetDate: this.nowTime })
             console.log(JSON.parse(JSON.stringify(data)), '<===== 处理之前的')
             this.summaryContent = data.summary;
+            this.serverFileList = data.weeklyAttachment?JSON.parse(data.weeklyAttachment):[];
+            //重置文件列表
+            this.fileList = [];
+            if (this.serverFileList) {
+                for (var i=0;i<this.serverFileList.length; i++) {
+                    var item = this.serverFileList[i];
+                    this.fileList.push({name:item.originName, url:this.serverFileList[i].serverName});
+                }
+            }
+            
             data.dateList.forEach(dateItem => {
                 const reportList = dateItem.reportList;
                 reportList.forEach(report => {
@@ -253,14 +427,19 @@ export default {
                         taskGroups[0].inchargerId = report.projectAuditorId;
                         taskGroups[0].inchargerName = report.projectAuditorName;
                     }
+                    if (report.degreeId == -1) {
+                        report.degreeId = null;
+                    }
+                    report.wuduList = report.degreeList;
                 });
             });
             console.log(data, '<===== 处理之后的')
             const { dateList, projectList, sumTimeList, cardTimeList } = data;
             const weekTableData = dateList.flatMap(date => {
-                const { weekDayTxt, date: dateTime, reportList, canFill } = date;
-                const reports = reportList.map(report => ({ ...report, weekDayTxt, dateTime, canFill }));
-                return reports.length > 0 ? reports : [{ weekDayTxt, dateTime, canFill }];
+                const { weekDayTxt, date: dateTime, reportList, canFill, time } = date;
+                const reports = reportList.map(report => ({ ...report, weekDayTxt, dateTime,time, canFill,projectName:projectList.filter(p=>p.id == report.projectId)[0].projectName }));
+
+                return reports.length > 0 ? reports : [{ weekDayTxt, dateTime,time, canFill }];
             });
             let sumSet = new Set();
             weekTableData.forEach(obj => {
@@ -276,27 +455,73 @@ export default {
             this.projectList = data
         },
         // 获取项目下的分组
-        // async getProjectGroup(projectId, index) {
-        //     const { isSubstitude } = this.weekParentData;
-        //     let { data } = await this.getData('/task-group/listProjectGroupAndAuditor', { projectId, isSubstitude: isSubstitude ? 1 : 0 })
-        //     if (data.length == 0) {
-        //         this.$message({
-        //             message: this.$t('fenZuWeiSheZhiQingLianXiGaiXiangMuGuanLiRenYuan'),
-        //             type: "error"
-        //         });
-        //     } else if (data.length == 1) {
-        //         this.$set(this.weekTableData[index], 'groupId', data[0].id)
-        //         this.$set(this.weekTableData[index], 'projectAuditorId', data[0].inchargerId)
-        //         this.$set(this.weekTableData[index], 'projectAuditorName', data[0].inchargerName)
-        //         if (!data[0].inchargerId) {
-        //             this.$message({
-        //                 message: `【${data[0].name}】`+this.$t('fenZuWeiSheZhiShenPiRenQingLianXiGaiXiangMuGuanLiRenYuan'),
-        //                 type: "error"
-        //             });
-        //         }
-        //     }
-        //     this.$set(this.weekTableData[index], 'taskGroups', data)
-        // },
+        async getProjectGroup(projectId, index) {
+            const { isSubstitude } = this.weekParentData;
+            let { data } = await this.getData('/task-group/listProjectGroupAndAuditor', { projectId, isSubstitude: isSubstitude ? 1 : 0 })
+            if (data.length == 0) {
+                this.$message({
+                    message: this.$t('fenZuWeiSheZhiQingLianXiGaiXiangMuGuanLiRenYuan'),
+                    type: "error"
+                });
+            } else if (data.length == 1) {
+                this.$set(this.weekTableData[index], 'groupId', data[0].id)
+                this.$set(this.weekTableData[index], 'projectAuditorId', data[0].inchargerId)
+                this.$set(this.weekTableData[index], 'projectAuditorName', data[0].inchargerName)
+                if (!data[0].inchargerId) {
+                    this.$message({
+                        message: `【${data[0].name}】`+this.$t('fenZuWeiSheZhiShenPiRenQingLianXiGaiXiangMuGuanLiRenYuan'),
+                        type: "error"
+                    });
+                }
+            }
+            this.$set(this.weekTableData[index], 'taskGroups', data)
+        },
+        async getTaskGroups(projectId, index) {
+            const { isSubstitude } = this.weekParentData;
+            let { data } = await this.getData('/task-group/listMyJoinGroup', { projectId, isSubstitude: isSubstitude ? 1 : 0 })
+            if (data.length == 1) {
+                this.$set(this.weekTableData[index], 'groupId', data[0].id)
+            }
+            this.$set(this.weekTableData[index], 'taskGroups', data)
+        },
+        async dimension(projectId, index) {
+            const { isSubstitude } = this.weekParentData;
+            // let { data } = await this.getData('/task-group/listMyJoinGroup', { projectId, isSubstitude: isSubstitude ? 1 : 0 })
+            // if (data.length == 1) {
+            //     this.$set(this.weekTableData[index], 'groupId', data[0].id)
+            // }
+            // this.$set(this.weekTableData[index], 'taskGroups', data);
+
+            if(projectId == '') {
+                return
+            }
+            var param = { 
+                projectId: projectId,
+            };
+            // if (isSubstitude) {
+            //     if (this.weekParentData.userId.length > 0) {
+            //         param.targetUserId = this.weekParentData.userId[0];
+            //     } else {
+            //         this.weekParentData[index].wuduList = [];
+            //         return;//暂未选择代填人,不获取数据
+            //     }
+            // }
+            this.http.post('/project/getDegreeList',param,
+            res => {
+                if (res.code == "ok") {
+                    // console.log("维度数据",res.data);
+                    // this.workForm.domains[index].wuduList = res.data
+                    this.$set(this.weekTableData[index], 'wuduList', res.data);
+                } 
+            },
+            error => {
+                this.$message({
+                    message: error,
+                    type: "error"
+                });
+                }
+            );
+        },
         // 插入一行
         insertRow(index) {
             this.weekTableData.splice(index + 1, 0, {
@@ -380,6 +605,21 @@ export default {
 }
 </script>
 <style scoped lang='scss'>
+.weeklySummary {
+    width: 100%;
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    border: 1px solid #EBEEF5;
+    border-top: 0px;
+    padding: 10px 20px;
+    box-sizing: border-box;
+    .weekly {
+        padding: 0 20px;
+        font-size: 20px;
+        color: #909399;
+    }
+}
 .flexColumn {
     display: flex;
     flex-direction: column;

+ 73 - 16
fhKeeper/formulahousekeeper/timesheet_h5/src/views/edit/index.vue

@@ -67,7 +67,7 @@
                             @click.stop.native="cardtimeRefresh(form.createDate, (fillingAgent.id || ''))"
                             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>
+                                <span style="margin:0 10px;color:#DAA520;">特殊填报</span>
                                 <van-switch v-model="form.abnormalTime" size="20px" :disabled="!canEdit" @change="onAbnormalTimeChange"/>
                             </template>
                         </template>
@@ -79,14 +79,22 @@
                         </template>
                     </template>
                 </van-cell>
-                <!-- <div v-if="report.time" class="attendanceRecord">
-                    <i class="iconfont firerock-icondakajilu" style="font-size:0.35rem;margin-right:0.12rem"></i>
-                    <span v-if="user.timeType.syncDingding==1&&!report.time">暂无考勤记录</span>
-                    <span v-else>{{report.time.startTime}}-{{report.time.endTime}}, {{report.time.workHours}}小时</span>
-                </div> -->
+                <van-cell v-if="report.overtime" title="已通过加班申请" :value="report.overtime.toFixed(1)">
+                </van-cell>
             </div>
+            <!-- 异常类型选择 -->
+            <van-field v-if="(user.companyId == 8555 || user.companyId == 5792) && form.abnormalTime"
+                readonly clickable label="异常类型" :value="form.abnormalItemName"
+                placeholder="请选择异常类型" right-icon="arrow"
+                :rules="[{ required: true, message: '请选择异常类型' }]"
+                @click="canEdit && (showAbnormalItemPicker = true)" />
+            <van-popup v-model="showAbnormalItemPicker" position="bottom">
+                <van-picker show-toolbar :columns="abnormalItemList" value-key="name"
+                    @confirm="onAbnormalItemConfirm"
+                    @cancel="showAbnormalItemPicker = false" />
+            </van-popup>
             <!-- 补考勤时间选择 -->
-            <van-cell-group v-if="(user.companyId == 8555 || user.companyId == 5792) && form.abnormalTime && !form.time && canEdit" title="补考勤">
+            <van-cell-group v-if="(user.companyId == 8555 || user.companyId == 5792) && form.abnormalTime && selectedAbnormalItem && selectedAbnormalItem.requireCardtime == 1 && !form.time && canEdit" title="补考勤">
                 <van-field readonly clickable label="上班时间" :value="form.abnormalStartTime" placeholder="请选择上班时间"
                     @click="showAbnormalStartTimePicker = true" />
                 <van-popup v-model="showAbnormalStartTimePicker" position="bottom">
@@ -871,8 +879,13 @@ export default {
             // 补考勤相关数据
             showAbnormalStartTimePicker: false,
             showAbnormalEndTimePicker: false,
-            abnormalStartTimeVal: '08:00',
-            abnormalEndTimeVal: '17:00',
+            abnormalStartTimeVal: null,
+            abnormalEndTimeVal: null,
+
+            // 异常类型相关数据
+            abnormalItemList: [],
+            selectedAbnormalItem: null,
+            showAbnormalItemPicker: false,
         };
     },
 
@@ -2064,11 +2077,15 @@ export default {
                             this.canDeleteReport = true
                             let array = [];
                             var abnormalTime = false;
+                            var abnormalItemId = null;
                             for (var i in list) {
                                 if (this.user.companyId == 8555 || this.user.companyId == 5792) {
                                     if (list[i].extraField1) {
                                         abnormalTime = true;
                                     }
+                                    if (list[i].extraField2) {
+                                        abnormalItemId = list[i].extraField2;
+                                    }
                                 }
                                 
                                 var projectName = list[i].projectName;
@@ -2263,6 +2280,12 @@ export default {
                                 }
                             }
                             this.form.abnormalTime = abnormalTime;
+                            this.form.abnormalItemId = abnormalItemId;
+                            if (abnormalItemId != null) {
+                                this.selectedAbnormalItem = this.abnormalItemList.filter(a=>a.id == abnormalItemId)[0];
+                                this.form.abnormalItemName = this.selectedAbnormalItem.name;
+                            }
+                            
                             this.form.domains = array;
                             this.setTotalReportHours()
                         } else {
@@ -3081,7 +3104,7 @@ export default {
                             break;
                         }
                     }
-                    if (!findImg) {
+                    if (!findImg && this.selectedAbnormalItem && this.selectedAbnormalItem.requirePicture == 1) {
                         this.$toast.fail('异常上报需上传凭证截图')
                         return
                     }
@@ -3398,8 +3421,12 @@ export default {
             }
             // 补考勤时间字段(仅异常填报时提交)
             if ((this.user.companyId == 8555 || this.user.companyId == 5792) && this.form.abnormalTime) {
-                formData.append("abnormalStartTime", this.form.abnormalStartTime || '');
-                formData.append("abnormalEndTime", this.form.abnormalEndTime || '');
+                if (this.form.abnormalStartTime) {
+                    formData.append("abnormalStartTime", this.form.abnormalStartTime || '');
+                }
+                if (this.form.abnormalEndTime) {
+                    formData.append("abnormalEndTime", this.form.abnormalEndTime || '');
+                }
                 formData.append("abnormalEndDay", this.form.abnormalEndDay || '0');
             }
             if (!this.flgLg) {
@@ -3665,14 +3692,41 @@ export default {
             this.employeeSelector.show = false;
         },
 
+        // 获取异常类型列表
+        getAbnormalItemList() {
+            this.$axios.post('/abnormal-item/list', {})
+                .then(res => {
+                    if (res.code == 'ok') {
+                        this.abnormalItemList = res.data || [];
+                    }
+                }).catch(err => { this.$toast.clear(); });
+        },
+
+        // 选择异常类型确认
+        onAbnormalItemConfirm(value) {
+            if (value) {
+                this.selectedAbnormalItem = value;
+                this.$set(this.form, 'abnormalItemId', value.id);
+                this.$set(this.form, 'abnormalItemName', value.name);
+            }
+            this.showAbnormalItemPicker = false;
+        },
+
         // 异常填报开关变化事件
         onAbnormalTimeChange(val) {
             if (val) {
-                this.$set(this.form, 'abnormalStartTime', '08:00');
-                this.$set(this.form, 'abnormalEndTime', '17:00');
+                this.$set(this.form, 'abnormalStartTime', null);
+                this.$set(this.form, 'abnormalEndTime', null);
                 this.$set(this.form, 'abnormalEndDay', '0');
-                this.abnormalStartTimeVal = '08:00';
-                this.abnormalEndTimeVal = '17:00';
+                this.$set(this.form, 'abnormalItemId', null);
+                this.$set(this.form, 'abnormalItemName', '');
+                this.selectedAbnormalItem = null;
+                this.abnormalStartTimeVal = null;
+                this.abnormalEndTimeVal = null;
+            } else {
+                this.selectedAbnormalItem = null;
+                this.$set(this.form, 'abnormalItemId', null);
+                this.$set(this.form, 'abnormalItemName', '');
             }
         },
 
@@ -3769,6 +3823,9 @@ export default {
         if (this.user.companyId == 4811) {
             this.getConstructionStageList();
         }
+        if (this.user.companyId == 8555 || this.user.companyId == 5792) {
+            this.getAbnormalItemList();
+        }
     },
     beforeDestroy() {
         localStorage.removeItem('formVal')

+ 14 - 14
fhKeeper/formulahousekeeper/timesheet_h5/src/views/exaLeave/overtime.vue

@@ -45,7 +45,7 @@
             </van-popup>
 
             <!-- 开始时间 -->
-            <van-field
+            <!-- <van-field
                 v-model="addForm.startTime"
                 label="开始时间"
                 readonly
@@ -65,10 +65,10 @@
                     :filter="datetimeFilter"
                     @confirm="onStartTimeConfirm"
                     @cancel="showStartTimePicker = false" />
-            </van-popup>
+            </van-popup> -->
 
             <!-- 结束时间 -->
-            <van-field
+            <!-- <van-field
                 v-model="addForm.endTime"
                 label="结束时间"
                 readonly
@@ -88,14 +88,14 @@
                     :filter="datetimeFilter"
                     @confirm="onEndTimeConfirm"
                     @cancel="showEndTimePicker = false" />
-            </van-popup>
+            </van-popup> -->
 
             <!-- 申请加班时长 -->
             <van-field
                 v-model="addForm.durationDisplay"
                 label="加班时长(小时)"
                 type="number"
-                placeholder="根据时间自动计算"
+                placeholder="请填写加班时长"
                 required
                 :rules="[{ required: true, message: '请填写加班时长' }, { validator: validateDuration, message: '加班时长必须大于0' }]"
                 @blur="syncDurationFromDisplay">
@@ -157,8 +157,8 @@
                 </template>
                 <div class="wrapper">
                     <div><span>对应班次:</span><span>{{ shiftTypeLabel(item.shiftType, item.isNightShift) }}</span></div>
-                    <div><span>开始时间:</span><span>{{ item.startTime }}</span></div>
-                    <div><span>结束时间:</span><span>{{ item.endTime }}</span></div>
+                    <!-- <div><span>开始时间:</span><span>{{ item.startTime }}</span></div>
+                    <div><span>结束时间:</span><span>{{ item.endTime }}</span></div> -->
                     <div><span>加班时长:</span><span>{{ formatDuration(item.duration) }}</span></div>
                     <div><span>加班事由:</span><span>{{ item.reason }}</span></div>
                     <div v-if="item.status === 3"><span>驳回原因:</span><span style="color:#ee0a24">{{ item.denyReason }}</span></div>
@@ -218,8 +218,8 @@
                 </template>
                 <div class="wrapper">
                     <div><span>对应班次:</span><span>{{ shiftTypeLabel(item.shiftType, item.isNightShift) }}</span></div>
-                    <div><span>开始时间:</span><span>{{ item.startTime }}</span></div>
-                    <div><span>结束时间:</span><span>{{ item.endTime }}</span></div>
+                    <!-- <div><span>开始时间:</span><span>{{ item.startTime }}</span></div>
+                    <div><span>结束时间:</span><span>{{ item.endTime }}</span></div> -->
                     <div><span>加班时长:</span><span>{{ formatDuration(item.duration) }}</span></div>
                     <div><span>加班事由:</span><span>{{ item.reason }}</span></div>
                     <div v-if="item.file">
@@ -286,7 +286,7 @@
             </van-popup>
 
             <!-- 开始时间 -->
-            <van-field
+            <!-- <van-field
                 v-model="editItemForm.startTime"
                 label="开始时间"
                 readonly
@@ -306,10 +306,10 @@
                     :filter="datetimeFilter"
                     @confirm="onEditStartTimeConfirm"
                     @cancel="showEditStartTimePicker = false" />
-            </van-popup>
+            </van-popup> -->
 
             <!-- 结束时间 -->
-            <van-field
+            <!-- <van-field
                 v-model="editItemForm.endTime"
                 label="结束时间"
                 readonly
@@ -329,14 +329,14 @@
                     :filter="datetimeFilter"
                     @confirm="onEditEndTimeConfirm"
                     @cancel="showEditEndTimePicker = false" />
-            </van-popup>
+            </van-popup> -->
 
             <!-- 申请加班时长 -->
             <van-field
                 v-model="editItemForm.durationDisplay"
                 label="加班时长(小时)"
                 type="number"
-                placeholder="根据时间自动计算"
+                placeholder="请填写加班时长"
                 required
                 :rules="[{ required: true, message: '请填写加班时长' }, { validator: validateDuration, message: '加班时长必须大于0' }]"
                 @blur="syncEditDurationFromDisplay">

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

@@ -1,12 +1,12 @@
 <template>
   <div>
-    <van-nav-bar title="编辑项目" left-text="返回" @click-left="back" fixed left-arrow />
+    <van-nav-bar :title="isAddMode ? '新增项目' : '编辑项目'" left-text="返回" @click-left="back" fixed left-arrow />
     <div class="content">
         <van-form ref="projectSubmit">
-        <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 v-model="projectDetail.projectCode" label="项目编号" :disabled="!isAddMode && !editCodeAndName"></van-field>
+        <van-field v-model="projectDetail.projectName" label="项目名称" :disabled="!isAddMode && !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'">
+        <van-field label="主项目" :disabled="!isAddMode && canOnlyModParticipator"  @click="(!isAddMode && !canOnlyModParticipator) || isAddMode ? mainProjectShow = true:''" readonly clickable v-if="user.timeType.mainProjectState == '1'">
             <template #input>
                 <span>{{projectDetail.projectMainName}}</span>
             </template>
@@ -21,7 +21,7 @@
                 ></van-picker>
             </van-popup>
         <!-- 项目分类 -->
-        <van-field label="项目分类" :disabled="canOnlyModParticipator" @click="!canOnlyModParticipator?categoryShow = true:''" readonly clickable v-if="user.timeType.mainProjectState != '1'">
+        <van-field label="项目分类" :disabled="!isAddMode && canOnlyModParticipator" @click="(!isAddMode && !canOnlyModParticipator) || isAddMode ? categoryShow = true:''" readonly clickable v-if="user.timeType.mainProjectState != '1'">
             <template #input>
                 <span>{{projectDetail.categoryName}}</span>
             </template>
@@ -36,9 +36,9 @@
                 ></van-picker>
             </van-popup>
         <!-- 项目描述 -->
-        <van-field v-model="projectDetail.projectDesc" :disabled="canOnlyModParticipator" label="项目描述"></van-field>
+        <van-field v-model="projectDetail.projectDesc" :disabled="!isAddMode && canOnlyModParticipator" label="项目描述"></van-field>
         <!-- 项目类型 -->
-        <van-field label="项目类型" :disabled="canOnlyModParticipator" @click="!canOnlyModParticipator?publicShow = true:''" readonly clickable>
+        <van-field label="项目类型" :disabled="!isAddMode && canOnlyModParticipator" @click="(!isAddMode && !canOnlyModParticipator) || isAddMode ? publicShow = true:''" readonly clickable>
             <template #input>
                 <span>{{publicList[projectDetail.isPublic]}}</span>
             </template>
@@ -52,7 +52,7 @@
                 ></van-picker>
             </van-popup>
         <!-- 项目级别 -->
-        <van-field label="项目级别" :disabled="canOnlyModParticipator" @click="!canOnlyModParticipator?levelShow = true:''" readonly clickable>
+        <van-field label="项目级别" :disabled="!isAddMode && canOnlyModParticipator" @click="(!isAddMode && !canOnlyModParticipator) || isAddMode ? levelShow = true:''" readonly clickable>
             <template #input>
                 <span>{{projectDetail.levelLabel}}</span>
             </template>
@@ -66,33 +66,8 @@
                 @cancel="levelShow = false"
                 ></van-picker>
             </van-popup>
-        <!-- 日报审核人 -->
-        <van-field label="日报审核人" :disabled="canOnlyModParticipator"  readonly clickable @click="!canOnlyModParticipator?dailyReviewFlg = true:''" v-if="user.timeType.reportAuditType == 0 || user.timeType.reportAuditType == 4">
-            <template #input>
-                <span v-if="projectDetail.auditorList.length > 0">
-                    <span v-for="(items, indexs) in projectDetail.auditorList" :key="indexs">
-                        <span v-if="user.userNameNeedTranslate != '1'">{{items.auditorName}}</span>
-                        <span v-if="user.userNameNeedTranslate == '1'"><TranslationOpenDataText type='userName' :openid='items.auditorName'></TranslationOpenDataText></span>
-                        <span v-if="projectDetail.auditorList.length - 1 > indexs">,</span>
-                    </span>
-                </span>
-                <span v-else>-</span>
-            </template>
-        </van-field>
-            <van-popup v-model="dailyReviewFlg" position="bottom" :style="{ height: '80%' }">
-                <van-search v-model="userName" placeholder="输入员工姓名搜索" @search="onSearch" v-if="user.userNameNeedTranslate != '1'"></van-search>
-                <div style="minHeight:300px;">
-                <template v-if="user.userNameNeedTranslate == '1'">
-                    <van-checkbox class="userCheckbox" v-for="(item) in dailyUserList" :key="item.id" v-model="item.isChecked" ><TranslationOpenDataText type='userName' :openid='item.name'></TranslationOpenDataText></van-checkbox>
-                </template>
-                <template v-else>
-                    <van-checkbox class="userCheckbox" v-for="(item) in dailyUserList" :key="item.id" v-model="item.isChecked" >{{item.name}}</van-checkbox>
-                </template>
-                <van-button style="width:100%;position: -webkit-sticky;position: sticky;bottom: 0;" @click="auditorNameConfirm(),dailyReviewFlg=false">确定</van-button>
-                </div>
-            </van-popup>
+        
         <!-- 参与人 -->
-        <!-- <van-button @click="test">test</van-button> -->
         <van-field label="全部参与人" @click="userNamesShow = true" readonly clickable v-show="projectDetail.isPublic == 0">
             <template #input>
                 <span v-if="!projectDetail.userNames"></span>
@@ -118,7 +93,7 @@
                 </div>
             </van-popup>
         <!-- 项目经理 -->
-        <van-field label="项目经理" @click="(editProjectMan&& !canOnlyModParticipator) ? inchargerShow = true : ''" readonly clickable :disabled="!editProjectMan || canOnlyModParticipator">
+        <van-field label="项目经理" @click="(isAddMode || (editProjectMan && !canOnlyModParticipator)) ? inchargerShow = true : ''" readonly clickable :disabled="!isAddMode && (!editProjectMan || canOnlyModParticipator)">
             <template #input>
                 <span v-if="user.userNameNeedTranslate == '1'"><TranslationOpenDataText type='userName' :openid='projectDetail.inchargerName'></TranslationOpenDataText></span>
                 <span v-else>{{projectDetail.inchargerName}}</span>
@@ -138,8 +113,33 @@
                 </template>
                 </van-picker>
             </van-popup>
+        <!-- 日报审核人 -->
+        <van-field label="日报审核人" :disabled="!isAddMode && canOnlyModParticipator"  readonly clickable @click="(!isAddMode && !canOnlyModParticipator) || isAddMode ? dailyReviewFlg = true:''" v-if="user.timeType.reportAuditType == 0 || user.timeType.reportAuditType == 4">
+            <template #input>
+                <span v-if="projectDetail.auditorList && projectDetail.auditorList.length > 0">
+                    <span v-for="(items, indexs) in projectDetail.auditorList" :key="indexs">
+                        <span v-if="user.userNameNeedTranslate != '1'">{{items.auditorName}}</span>
+                        <span v-if="user.userNameNeedTranslate == '1'"><TranslationOpenDataText type='userName' :openid='items.auditorName'></TranslationOpenDataText></span>
+                        <span v-if="projectDetail.auditorList.length - 1 > indexs">,</span>
+                    </span>
+                </span>
+                <span v-else>-</span>
+            </template>
+        </van-field>
+            <van-popup v-model="dailyReviewFlg" position="bottom" :style="{ height: '80%' }">
+                <van-search v-model="userName" placeholder="输入员工姓名搜索" @search="onSearch" v-if="user.userNameNeedTranslate != '1'"></van-search>
+                <div style="minHeight:300px;">
+                <template v-if="user.userNameNeedTranslate == '1'">
+                    <van-checkbox class="userCheckbox" v-for="(item) in dailyUserList" :key="item.id" v-model="item.isChecked" ><TranslationOpenDataText type='userName' :openid='item.name'></TranslationOpenDataText></van-checkbox>
+                </template>
+                <template v-else>
+                    <van-checkbox class="userCheckbox" v-for="(item) in dailyUserList" :key="item.id" v-model="item.isChecked" >{{item.name}}</van-checkbox>
+                </template>
+                <van-button style="width:100%;position: -webkit-sticky;position: sticky;bottom: 0;" @click="auditorNameConfirm(),dailyReviewFlg=false">确定</van-button>
+                </div>
+            </van-popup>
         <!-- 开始日期 -->
-        <van-field label="计划开始日期" @click="!canOnlyModParticipator?startDateShow = true:''" readonly clickable :disabled="canOnlyModParticipator">
+        <van-field label="计划开始日期" @click="(isAddMode || !canOnlyModParticipator) ? startDateShow = true:''" readonly clickable :disabled="!isAddMode && canOnlyModParticipator">
             <template #input>
                 <span>{{projectDetail.planStartDate}}</span>
             </template>
@@ -156,7 +156,7 @@
                 />
             </van-popup>
         <!-- 结束日期 -->
-        <van-field label="计划结束日期" @click="!canOnlyModParticipator?endDateShow = true:''" readonly clickable :disabled="canOnlyModParticipator">
+        <van-field label="计划结束日期" @click="(isAddMode || !canOnlyModParticipator) ? endDateShow = true:''" readonly clickable :disabled="!isAddMode && canOnlyModParticipator">
             <template #input>
                 <span>{{projectDetail.planEndDate}}</span>
             </template>
@@ -176,9 +176,9 @@
 
 
         <div class="form_btn" style="position: fixed; bottom: 0px; width: 100%">
-            <div style="padding-bottom: 10px">
-                <van-button square block type="info" :disabled="canOnlyModParticipator" @click="deleteProject()" style="width: 50%; float: left">删除</van-button>
-                <van-button square block type="danger" @click="submitProject" style="width: 50%; float: left">保存</van-button>
+            <div style="padding: 0 0 10px 0; background: #fff;">
+                <van-button square block type="info" @click="submitProject" style="width: 100%">保存</van-button>
+                <van-button v-if="!isAddMode" square block type="danger" :disabled="canOnlyModParticipator" @click="deleteProject()" style="width: 100%; margin-top: 8px">删除</van-button>
             </div>
         </div>
     </div>
@@ -190,11 +190,29 @@ export default {
     data() {
         return {
             user: JSON.parse(localStorage.userInfo),
-            projectId: JSON.parse(sessionStorage.projectId),
+            isAddMode: this.$route.query.mode === 'add',
+            projectId: this.$route.query.mode === 'add' ? null : JSON.parse(sessionStorage.projectId),
             minDate: new Date(2023,0,1),
             maxDate: new Date(2029,11,31),
             projectDetail: {
-                auditorList: []
+                projectCode: '',
+                projectName: '',
+                projectDesc: '',
+                isPublic: 0,
+                userNames: '',
+                userId: [],
+                inchargerName: '',
+                inchargerId: null,
+                planStartDate: '',
+                planEndDate: '',
+                auditorList: [],
+                auditUserIds: [],
+                category: null,
+                categoryName: '',
+                projectMainId: null,
+                projectMainName: '',
+                level: null,
+                levelLabel: '',
             },
             editCodeAndName: false,
 
@@ -223,11 +241,34 @@ export default {
         }
     },
     mounted() {
-        this.getProjectDetail()
-        if(this.user.timeType.mainProjectState == '1'){
-            this.getMainProjectList()
-        }else{
-            this.getCategoryList()
+        if (this.isAddMode) {
+            // 新增模式:初始化数据,直接获取用户列表等基础数据
+            this.editCodeAndName = true
+            this.editProjectMan = true
+            this.getUserList()
+            if(this.user.timeType.mainProjectState == '1'){
+                this.getMainProjectList()
+            }else{
+                this.getCategoryList()
+            }
+            if(this.user.timeType.projectLevelState == 1){
+                this.getLevelList()
+            }else{
+                this.levelList = [
+                    {label: '正常' ,id: 1},
+                    {label: '紧急' ,id: 2},
+                    {label: '重要' ,id: 3},
+                    {label: '重要且紧急' ,id: 4},
+                ]
+            }
+        } else {
+            // 编辑模式:获取项目详情
+            this.getProjectDetail()
+            if(this.user.timeType.mainProjectState == '1'){
+                this.getMainProjectList()
+            }else{
+                this.getCategoryList()
+            }
         }
     },
     methods: {
@@ -245,7 +286,7 @@ export default {
         mainProjectConfirm(value,key){
             this.projectDetail.projectMainId = value.id
             this.projectDetail.projectMainName = value.name
-            this.categoryShow = false
+            this.mainProjectShow = false
         },
         categoryConfirm(value,key){
             this.projectDetail.category = value.id
@@ -324,7 +365,6 @@ export default {
         startDateConfirm(value){
             this.currentStartDate = value
             this.$set(this.projectDetail, 'planStartDate', this.formatDate(value));
-            console.log('333', this.projectDetail.planStartDate);
             this.startDateShow = false
         },
         endDateConfirm(value){
@@ -337,18 +377,20 @@ export default {
         submitProject(){
             this.$refs.projectSubmit.validate().then(()=>{
                 let formData = new FormData();
-                formData.append("id", this.projectDetail.id);
+                if (!this.isAddMode) {
+                    formData.append("id", this.projectDetail.id);
+                }
                 formData.append("name", this.projectDetail.projectName);
                 formData.append("code", this.projectDetail.projectCode ? this.projectDetail.projectCode : '');
                 if(this.projectDetail.projectMainId && this.user.timeType.mainProjectState == '1') {
-                    formData.append("projectMainId", this.addForm.projectMainId);
+                    formData.append("projectMainId", this.projectDetail.projectMainId);
                 }
                 if(this.projectDetail.category) {
                     formData.append("category", this.projectDetail.category);
                 }
                 formData.append("projectDesc", this.projectDetail.projectDesc ? this.projectDetail.projectDesc : '');
-                formData.append("isPublic", this.projectDetail.isPublic);
-                if(this.projectDetail.userId.length != 0 && this.projectDetail.isPublic == 0) {
+                formData.append("isPublic", this.projectDetail.isPublic != null ? this.projectDetail.isPublic : 0);
+                if(this.projectDetail.userId && this.projectDetail.userId.length != 0 && this.projectDetail.isPublic == 0) {
                     for(let i in this.projectDetail.userId) {
                         formData.append("userId", this.projectDetail.userId[i]);
                     }
@@ -362,19 +404,17 @@ export default {
                 if(this.projectDetail.planEndDate) {
                     formData.append("planEndDate", this.projectDetail.planEndDate);
                 }
-                if (this.projectDetail.auditUserIds) {
+                if (this.projectDetail.auditUserIds && this.projectDetail.auditUserIds.length > 0) {
                     formData.append("auditUserIds", JSON.stringify(this.projectDetail.auditUserIds));
                 }
                 
-                // console.log(this.projectDetail)
-                // return
                 this.$axios.post("/project/editProject", formData)
                 .then(res => {
                     if(res.code == "ok") {
-                        this.$toast.success('修改成功')
+                        this.$toast.success(this.isAddMode ? '新增成功' : '修改成功')
                         this.back()
                     } else {
-                        this.$toast.fail('获取失败');
+                        this.$toast.fail(res.msg || '操作失败');
                     }
                 }).catch(err=> {this.$toast.clear();console.log(err)});
             }).catch(()=>{return})
@@ -435,6 +475,9 @@ export default {
                 if(res.code == "ok") {
                     console.log('成功')
                     this.projectDetail = res.data
+                    if (!this.projectDetail.auditorList) {
+                        this.projectDetail.auditorList = []
+                    }
                     let userNames = ''
                     let userId = []
                     for(let i in this.user.functionList){
@@ -471,7 +514,7 @@ export default {
                             {label: '重要' ,id: 3},
                             {label: '重要且紧急' ,id: 4},
                         ]
-                        this.projectDetail.levelLabel = this.levelList[this.projectDetail.level - 1].label
+                        this.projectDetail.levelLabel = this.levelList[this.projectDetail.level - 1] ? this.levelList[this.projectDetail.level - 1].label : ''
                     }
 
                     if(this.user.id == res.data.creatorId){
@@ -508,8 +551,10 @@ export default {
             .then(res => {
                 if(res.code == "ok") {
                     this.levelList = res.data
-                    let list = this.levelList.filter(u => u.id == this.projectDetail.level)
-                    this.projectDetail.levelLabel = list.length != 0 ? list[0].label : ''
+                    if (!this.isAddMode) {
+                        let list = this.levelList.filter(u => u.id == this.projectDetail.level)
+                        this.projectDetail.levelLabel = list.length != 0 ? list[0].label : ''
+                    }
                 } else {
                     this.$toast.fail('获取失败');
                 }
@@ -521,15 +566,23 @@ export default {
                 if(res.code == "ok") {
                     let list = res.data.records
                     for (let i in list) {
-                        let length = this.projectDetail.participationList.filter(u => u.id == list[i].id).length
-                        if(length){
-                            list[i].isChecked = true
-                        }else{
+                        if (this.isAddMode) {
                             list[i].isChecked = false
+                        } else {
+                            let length = this.projectDetail.participationList.filter(u => u.id == list[i].id).length
+                            if(length){
+                                list[i].isChecked = true
+                            }else{
+                                list[i].isChecked = false
+                            }
                         }
                     }
                     this.allUserList = list;
                     this.userList = list;
+                    // 新增模式下初始化 inchargerList 为全部用户
+                    if (this.isAddMode) {
+                        this.inchargerList = list;
+                    }
                     this.integrationreAuidType()
                 } else {
                     this.$toast.fail('获取失败');
@@ -548,4 +601,4 @@ export default {
         padding: 10px;
     }
 }
-</style>
+</style>

+ 8 - 12
fhKeeper/formulahousekeeper/timesheet_h5/src/views/project/index.vue

@@ -401,18 +401,9 @@
             // 新增、编辑项目
             openDialog(i) {
                 if(i == -1) {
-                    this.title = "新增项目";
-                    this.form = {
-                        id: null,
-                        projectName: "",
-                        projectCode:null,
-                        inchargerName:null,
-                        inchargerId:null,
-                        userId:null,
-                        userNames:'',
-                        associateDegreeNames: null,
-                        associateDegrees: null
-                    }
+                    // 跳转到新增项目页面
+                    this.$router.push('/editProject?mode=add');
+                    return;
                 } else {
                     this.title = "修改项目";
                     var arrs
@@ -452,6 +443,11 @@
 
             chargeBtn(action, done) {
                 if (action === 'confirm') {
+                    if (!this.form.projectName || !this.form.projectName.trim()) {
+                        this.$toast.fail('请填写项目名称');
+                        done(false);
+                        return;
+                    }
                     this.show = false;
                     const toast = this.$toast.loading({
                         forbidClick: true,

+ 25 - 2
fhKeeper/formulahousekeeper/timesheet_h5/src/views/review/index.vue

@@ -84,6 +84,16 @@
                         </span>
                         <!-- <span>系统智能统计:{{item.calculateTime}}h</span> -->
                     </div>
+                    <div class="form_text" v-if="user.timeType.showCorpwxCardtime==1 || user.timeType.showDdCardtime==1 || user.timeType.syncFanwei==1">
+                        <span style="margin-left:5px;">考勤时长:</span>
+                        <span v-if="item.cardHours" :style="item.cardHours != item.reportTime ? 'color:red' : ''">
+                            <span>{{ item.startTime }} ~ {{ item.endTime }}</span>
+                            <span v-if="item.cardHours"> 共 {{ item.cardHours.toFixed(1) }} 小时</span>
+                            <span v-if="item.overtime" style="color:#20a0ff;"> 加班申请 {{ item.overtime.toFixed(1) }} 小时</span>
+                            <span v-if="item.askLeaveTime" style="color:#20a0ff;"> 请假 {{ item.askLeaveTime.toFixed(1) }} 小时</span>
+                        </span>
+                        <span v-else>-</span>
+                    </div>
                     <div v-for="(item1,index1) in item.data" :key="index1" class="one_report_data">
                         <div class="project_title">项目:{{item1.project}}
                             [
@@ -199,6 +209,7 @@
                 <van-button style="width:100%;" type="info" @click="batchApproveinfun()" v-if="isbatch">提交</van-button>
                 <van-button style="width:100%;" type="info" @click="approveinfun()" v-else>提交</van-button>
             </van-popup>
+
         </div>
     </div>
 </template>
@@ -348,8 +359,12 @@
             },
             batchAgree(bol){
                 let ids = ''
+                let hasAbnormal = false
                 for(let i in this.report){
                     if(this.report[i].checked){
+                        if(this.report[i].abnormalTime == true){
+                            hasAbnormal = true
+                        }
                         for(let m in this.report[i].data){
                             ids += this.report[i].data[m].id + ','
                         }
@@ -359,8 +374,12 @@
                     ids = ids.substring(0, ids.length-1);
                 }
                 if(bol){
+                    const message = hasAbnormal
+                        ? `该工时申请为特殊填报,请人工复确认证明附件及手工录入考勤及对应加班申请。`
+                        : `确认批量通过这些的日报吗?`;
                     Dialog.confirm({
-                        message: `确认批量通过这些的日报吗?`
+                        message: message,
+                        confirmButtonText: '已完成检查同意'
                     })
                     .then(() => {
                         this.isbatch = true
@@ -475,8 +494,12 @@
             },
 
             approve(id, item) {
+                const message = item.abnormalTime == true
+                    ? `该工时申请为特殊填报,请人工复确认证明附件及手工录入考勤及对应加班申请。`
+                    : `确认通过${item.dateStr}的日报吗?`;
                 Dialog.confirm({
-                    message: `确认通过${item.dateStr}的日报吗?`
+                    message: message,
+                    confirmButtonText: '已完成检查同意'
                 })
                 .then(() => {
                     var ids = '';