瀏覽代碼

Merge remote-tracking branch 'origin/master'

yusm 1 月之前
父節點
當前提交
62eca04432

+ 17 - 2
fhKeeper/formulahousekeeper/management-platform-mld/src/main/java/com/management/platform/controller/ParticipationController.java

@@ -1,12 +1,16 @@
 package com.management.platform.controller;
 
 
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.management.platform.entity.User;
 import com.management.platform.mapper.ParticipationMapper;
+import com.management.platform.mapper.UserMapper;
 import com.management.platform.util.HttpRespMsg;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
 import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
 
 /**
  * <p>
@@ -23,10 +27,21 @@ public class ParticipationController {
     @Resource
     private ParticipationMapper participationMapper;
 
+    @Resource
+    private UserMapper userMapper;
+
     @RequestMapping("/getByProjectId")
-    public HttpRespMsg getByProjectId(Integer projectId) {
+    public HttpRespMsg getByProjectId(Integer projectId, HttpServletRequest request) {
         HttpRespMsg msg = new HttpRespMsg();
-        msg.data = participationMapper.getParticipator(projectId);
+        if (projectId == null) {
+            String token = request.getHeader("TOKEN");
+            User user = userMapper.selectById(token);
+            //未指定项目时加载全部在职人员
+            msg.data = userMapper.selectList(new QueryWrapper<User>().select("id, job_number, name").eq("is_active", 1).eq("company_id", user.getCompanyId()));
+        } else {
+            msg.data = participationMapper.getParticipator(projectId);
+        }
+
         return msg;
     }
 }

+ 7 - 4
fhKeeper/formulahousekeeper/management-platform-mld/src/main/java/com/management/platform/controller/TaskController.java

@@ -529,6 +529,13 @@ public class TaskController {
             if (needReOrderList.size() > 0) {
                 taskService.updateBatchById(needReOrderList);
             }
+            List<TaskExecutor> exeList = taskExecutorService.list(new QueryWrapper<TaskExecutor>().eq("task_id", task.getId()));
+            List<String> retIds = new ArrayList<>();
+            for (TaskExecutor exe : exeList) {
+                retIds.add(MessageUtils.message("excel.task") + "_"+task.getId() +"_"+ exe.getId());
+            }
+            //给新建的计划返回甘特图id
+            msg.data = retIds;
         }
 
         TaskComment comment = new TaskComment();
@@ -540,10 +547,6 @@ public class TaskController {
         comment.setContent(user.getName()+(isNew?MessageUtils.message("entry.create"):MessageUtils.message("entry.editedTask"))+MessageUtils.message("entry.task")+(isNew?"":taskCommentString.toString()));
         taskCommentMapper.insert(comment);
 
-        //需要重新计算项目进度
-//        if (needRecalculateProgress) {
-//            updateProjectProgress(task.getProjectId());
-//        }
         if (msgRecepientList.size() > 0) {
             //发消息通知执行人, 带项目id
             msgRecepientList.forEach(msgRecepient->{

+ 1 - 10
fhKeeper/formulahousekeeper/management-platform-mld/src/main/java/com/management/platform/controller/UserCorpwxTimeController.java

@@ -228,17 +228,8 @@ public class UserCorpwxTimeController {
         String token = request.getHeader("TOKEN");
         User user = userMapper.selectById(token);
         List<Map> list = new ArrayList<Map>();
-        list = userCorpwxTimeMapper.getUserDataList(user.getCompanyId(), startDate, endDate, null, user.getId());
+        list = userCorpwxTimeMapper.getUserDataList(user.getCompanyId(), startDate, endDate, null, user.getRoleName().contains("管理员")?null:user.getId());
         //工作日处理,排除常规周末和法定节假日
-        DateTimeFormatter dtf =  DateTimeFormatter.ofPattern("yyyy/MM/dd");
-//        list = list.stream().filter(time->{
-//            String date = (String)time.get("createDate");
-//            if (WorkDayCalculateUtils.isWorkDay(LocalDate.parse(date, dtf))) {
-//                return true;
-//            } else {
-//                return false;
-//            }
-//        }).collect(Collectors.toList());
         DateTimeFormatter standFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
         HashMap item = new HashMap();
         item.put("list", list);

+ 1 - 1
fhKeeper/formulahousekeeper/management-platform-mld/src/main/java/com/management/platform/mapper/ProjectMapper.java

@@ -73,7 +73,7 @@ public interface ProjectMapper extends BaseMapper<Project> {
 
     List<Map> getTaskPlanByProject(@Param("projectIds") List<Integer> projectIds, @Param("startDate") String startDate,
                                 @Param("endDate") String endDate, @Param("companyId") Integer companyId,@Param("groupName")String groupName,@Param("taskType")Integer taskType,
-                                   @Param("creatorId") String creatorId);
+                                   @Param("userIds") List<String> userIds);
     List<Map> getTaskPlanWithLeave(@Param("userIds") List<String> userIds, @Param("startDate") String startDate,
                                    @Param("endDate") String endDate, @Param("companyId") Integer companyId,@Param("creatorId") String creatorId,@Param("targetUserId") String targetUserId);
 

+ 8 - 40
fhKeeper/formulahousekeeper/management-platform-mld/src/main/java/com/management/platform/service/impl/ProjectServiceImpl.java

@@ -4806,7 +4806,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
         List<SysRichFunction> functionList = sysFunctionMapper.getRoleFunctions(user.getRoleId(), "查看全部项目");
         List<Department> departmentList = departmentMapper.selectList(new QueryWrapper<Department>().eq("company_id", user.getCompanyId()));
         List<User> AllUser = userMapper.selectList(new QueryWrapper<User>().eq("company_id", user.getCompanyId()));
-        List<Integer> relatedProjectIds = new ArrayList<>();
+        List<Integer> projectIds = null;
         if (functionList.size() == 0) {
             //担任部门主要负责人
             if (user.getManageDeptId() != null && user.getManageDeptId() != 0) {
@@ -4840,7 +4840,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
         HttpRespMsg msg = new HttpRespMsg();
         List<GanttDataItem> itemList = new ArrayList<>();
 
-        List<Integer> projectIds = null;
+
         if (targetProjectId != null) {
             projectIds = new ArrayList<>();
             projectIds.add(targetProjectId);
@@ -4973,9 +4973,9 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                         }
                     }
                 }
+                List<Project> allProjectList = projectMapper.selectList(new QueryWrapper<Project>().eq("company_id", user.getCompanyId()));
                 if (taskType!=null) {
-                    List<Project> projectList = projectMapper.selectList(new QueryWrapper<Project>().eq("company_id", user.getCompanyId()));
-                    List<Integer> collect = projectList.stream().map(Project::getId).collect(Collectors.toList());
+                    List<Integer> collect = allProjectList.stream().map(Project::getId).collect(Collectors.toList());
                     List<Task> tasks = taskMapper.selectList(new QueryWrapper<Task>().eq("task_plan_type", taskType).in("project_id", collect));
                     List filterPids = tasks.stream().map(Task::getProjectId).collect(Collectors.toList());
                     if (projectIds == null) {
@@ -4985,38 +4985,8 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                         }
                     }
                 }
-                ganttData = projectMapper.getTaskPlanByProject(projectIds, startDate ,endDate, user.getCompanyId(),groupName,taskType,user.getId());
-//                System.out.println("ganttData1:"+ganttData.size());
-//                List<ProjectLeader> leaderList = projectLeaderService.list(new QueryWrapper<ProjectLeader>().eq("leader_id", user.getId()).eq("company_id", user.getCompanyId()));
-//                //是小组长
-//                if (!leaderList.isEmpty()){
-//                    List<Integer> projectIdList = leaderList.stream().map(ProjectLeader::getProjectId).collect(Collectors.toList());
-//                    projectIdList.add(-1);
-//                    List<Map> taskPlanByGeneralMemb = projectMapper.getTaskPlanByProjectGeneralMemb(projectIdList,startDate ,endDate, user.getCompanyId(),user.getId(),groupName,taskType,targetProjectId);
-//                    System.out.println("ganttData2:"+taskPlanByGeneralMemb.size());
-//                    ganttData.addAll(taskPlanByGeneralMemb);
-//                }
-//                //找到自己担任项目经理的项目,: is_task_plan==1 ,checkFirstId=自己的id 并且 task_status=3
-//                List<Project> projectList = projectMapper.selectList(new QueryWrapper<Project>().eq("incharger_id", user.getId()));
-//                if (!projectList.isEmpty()){
-//                    List<Integer> projectIdList = projectList.stream().map(Project::getId).collect(Collectors.toList());
-//                    projectIdList.add(-1);
-//                    List<Map> taskPlanByProjectManager = projectMapper.getTaskPlanByProjectManager(projectIdList,startDate ,endDate, user.getCompanyId(),user.getId(),groupName,taskType,targetProjectId);
-//                    System.out.println("ganttData2:"+taskPlanByProjectManager.size());
-//                    ganttData.addAll(taskPlanByProjectManager);
-//                }
-//
-//                if (user.getRoleName().equals("区域经理&PM")){
-//                    List<Task> taskList = taskService.list(new QueryWrapper<Task>().eq("check_second_id", user.getId()));
-//                    List<Integer> taskIdList = taskList.stream().map(Task::getId).collect(Collectors.toList());
-//                    taskIdList.add(-1);
-//                    List<TaskExecutor> executorList = taskExecutorService.list(new QueryWrapper<TaskExecutor>().in("task_id", taskIdList).isNotNull("executor_id"));
-//                    List<Integer> projectIdList = executorList.stream().distinct().map(TaskExecutor::getProjectId).collect(Collectors.toList());
-//                    projectIdList.add(-1);
-//                    List<Map> taskPlanByProjectAreaManager = projectMapper.getTaskPlanByProjectAreaManager(projectIdList, startDate, endDate, user.getCompanyId(),user.getId(),groupName,taskType,targetProjectId);
-//                    System.out.println("ganttData2:"+taskPlanByProjectAreaManager.size());
-//                    ganttData.addAll(taskPlanByProjectAreaManager);
-//                }
+                System.out.println("按项目查看,项目size="+projectIds.size());
+                ganttData = projectMapper.getTaskPlanByProject(projectIds, startDate ,endDate, user.getCompanyId(),groupName,taskType,userIds);
                 QueryWrapper<BusinessTrip> btQueryWrapper =new QueryWrapper<>();
                 QueryWrapper<BustripProject> bpQueryWrapper =new QueryWrapper<>();
                 btQueryWrapper.in("owner_id", userIds);
@@ -5035,7 +5005,6 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                     }
                 }
                 List<BustripProject> bustripProjectList = bustripProjectMapper.selectList(bpQueryWrapper);
-                List<Project> allProjectList = projectMapper.selectList(new QueryWrapper<Project>().eq("company_id", user.getCompanyId()));
                 for(BusinessTrip businessTrip:businessTripList){
                     List<BustripProject> collect = bustripProjectList.stream().filter(bp -> bp.getBustripId().equals(businessTrip.getId())).collect(Collectors.toList());
                     for(BustripProject bustripProject:collect){
@@ -5114,8 +5083,6 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                     curItem.id = exeId;
                     curItem.userId = (String) map.get("user_id");
                     curItem.text = (String) map.get("project_name")+"/"+(String)map.get("task_name");
-//                    curItem.setCheckFirstId(map.get("checkFirstId")==null?null:(String) map.get("checkFirstId"));
-//                    curItem.setCheckSecondId(map.get("checkSecondId")==null?null:(String) map.get("checkSecondId"));
                     curItem.start_date = start_date;
 
                     curItem.setTaskPlanType(map.get("taskPlanType")==null?null:(Integer)map.get("taskPlanType"));
@@ -8701,6 +8668,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
             }
 
             userList = userMapper.selectList(queryWrapper);
+
         }
         List<User> finalUserList = new ArrayList<>();
         userList.forEach(u->{
@@ -12853,7 +12821,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                         }
                     }
                 }
-                ganttData = projectMapper.getTaskPlanByProject(projectIds, startDate ,endDate, user.getCompanyId(),null,null,user.getId());
+                ganttData = projectMapper.getTaskPlanByProject(projectIds, startDate ,endDate, user.getCompanyId(),null,null,userIds);
                 QueryWrapper<BusinessTrip> btQueryWrapper =new QueryWrapper<>();
                 QueryWrapper<BustripProject> bpQueryWrapper =new QueryWrapper<>();
                 btQueryWrapper.in("owner_id", userIds);

+ 12 - 1
fhKeeper/formulahousekeeper/management-platform-mld/src/main/java/com/management/platform/service/impl/TaskServiceImpl.java

@@ -1198,7 +1198,6 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
     public HttpRespMsg cancelByManager(Integer id, HttpServletRequest request) {
         HttpRespMsg msg = new HttpRespMsg();
         String token = request.getHeader("TOKEN");
-        User user = userMapper.selectById(token);
         Task task = taskMapper.selectById(id);
         if (task.getTaskStatus() == TaskController.STATUS_DOING) {
             task.setTaskStatus(TaskController.STATUS_CANCEL);
@@ -1211,6 +1210,18 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
             information.setUserId(owner.getId());
             information.setTime(LocalDateTime.now());
             informationMapper.insert(information);
+
+            //给执行人发消息
+            List<TaskExecutor> executorList = taskExecutorMapper.selectList(new QueryWrapper<TaskExecutor>().eq("task_id", id));
+            executorList.forEach(e->{
+                User executor = userMapper.selectById(e.getExecutorId());
+                Information exeInformation = new Information();
+                exeInformation.setMsg("您有工作计划被取消");
+                exeInformation.setType(11);
+                exeInformation.setUserId(executor.getId());
+                exeInformation.setTime(LocalDateTime.now());
+                informationMapper.insert(exeInformation);
+            });
         }
         return msg;
     }

+ 4 - 0
fhKeeper/formulahousekeeper/management-platform-mld/src/main/resources/mapper/ProjectMapper.xml

@@ -782,6 +782,10 @@
         <if test="taskType !=null  ">
             and task.task_plan_type = #{taskType}
         </if>
+        <if test="userIds != null">
+            and exists(select 1 from task_executor where task.id=task_executor.task_id
+                         and task_executor.executor_id in <foreach collection="userIds" close=")" open="(" separator="," index="" item="item">#{item}</foreach>)
+        </if>
         and ((IFNULL(task.start_date , task.end_date) between #{startDate} and #{endDate}) or (task.end_date between #{startDate} and #{endDate}))
         and task.end_date is not null
         AND project.`status` = 1

+ 153 - 8
fhKeeper/formulahousekeeper/timesheet/src/views/corpreport/list.vue

@@ -52,6 +52,7 @@
                   <el-menu-item index="1-30" v-if="permissions.taskPlanCost" @click="ssl(29)"><p>{{ $t('taskPlanCostReport') }}</p></el-menu-item>
                   <el-menu-item index="1-31" v-if="permissions.reportFTEPlanAll || permissions.reportFTEPlanPart" @click="ssl(30)"><p>FTE计划报表</p></el-menu-item>
                   <el-menu-item index="1-32" v-if="permissions.reportMonthlyFinancialWorkSchedule" @click="ssl(31)"><p>月度财务工时表</p></el-menu-item>
+                  <el-menu-item index="1-33" v-if="permissions.reportAllTimelyTaskHours || permissions.reportRartTimelyTaskHours" @click="ssl(32)"><p>任务工时填报及时表</p></el-menu-item>
                 </el-submenu>
               </el-menu>
           </el-col>
@@ -70,7 +71,15 @@
     <div class="headine headConCon" ref="headine" :style="'width:'+(windowWidth - 400)+'px'">
       <h3 ref="headHe" style="padding-left: 10px;float:left;width:15%">{{shuz[ins]}}</h3>
       <div class="headScreen" :style="ins == 9 || ins == 21 ? 'width:60%' : 'width:72%'">
-      <!-- 客户项目利润表的筛选 -->  
+        <!-- 任务工时填报及时表的筛选 -->
+        <template v-if="ins == 32"> 
+          <el-radio-group v-model="timelyTaskHoursRadio" size="small" @change="projectChange()">
+            <el-radio-button label="按任务查看"></el-radio-button>
+            <el-radio-button label="按人员查看"></el-radio-button>
+          </el-radio-group>
+        </template>
+
+        <!-- 客户项目利润表的筛选 -->  
         <template v-if="ins == 4">
           <el-select v-model="customerId" :placeholder="$t('pleaseelectcustomers')" clearable filterable size="small" @change="selcts(4)" style="margin-right:20px">
             <el-option v-for="(item) in customerList" :key="item.id" :label="item.customerName" :value="item.id">
@@ -137,7 +146,7 @@
             <el-option v-for="(item) in projectMainIdList" :key="item.id" :label="item.name" :value="item.id"></el-option>
           </el-select>
   
-          <el-select v-if="!screeningCondition.project.includes(ins)" v-model="proJuctId" :placeholder="$t('defaultText.pleaseSelectSnItem')" clearable filterable size="small" @change="projectChange()" style="margin-left:10px">
+          <el-select v-if="!screeningCondition.project.includes(ins)" v-model="proJuctId" :placeholder="$t('defaultText.pleaseSelectSnItem')" :clearable="ins != 32" filterable size="small" @change="projectChange()" style="margin-left:10px">
             <el-option v-for="(item) in proListOvertime" :key="item.id" :label="item.projectName + (item.projectCode ? item.projectCode : '')" :value="item.id">
               <span style="float: left;color: #8492a6;">{{ item.projectCode }}</span>
               <span style="float: right;font-size: 13px;margin-left: 20px">{{ item.projectName }}</span>
@@ -1618,8 +1627,34 @@
             </el-table-column>
             <el-table-column prop="totalTime" align="center" label="工时合计(h)" width="120px"></el-table-column>
           </el-table>
+
+          <!-- 任务工时填报及时表 -->
+          <template v-if="ins == 32">
+            <el-table v-if="timelyTaskHoursRadio == '按任务查看'"  key="32" border :data="timelyReportingOfTaskHoursList" highlight-current-row v-loading="timelyReportingOfTaskHoursLoading" :height="+tableHeight + 50" :span-method="timelyFormForFillingInTaskHoursSpanMethod" style="width: 100%;" :max-height="+tableHeight + 50">
+              <el-table-column prop="projectName" align="center" label="所属项目"></el-table-column>
+              <el-table-column prop="taskName" align="center" label="任务"></el-table-column>
+              <el-table-column prop="startDate" align="center" label="任务开始时间"></el-table-column>
+              <el-table-column prop="endDate" align="center" label="任务截止时间"></el-table-column>
+              <el-table-column prop="userName" align="center" label="人员"></el-table-column>
+              <el-table-column prop="jobNumber" align="center" label="工号"></el-table-column>
+              <el-table-column prop="departmentName" align="center" label="所属部门"></el-table-column>
+              <el-table-column prop="timelinessRate" align="center" label="填报及时率"></el-table-column>
+              <el-table-column prop="timelinessRateWithLeave" align="center" label="填报及时率(含请假)"></el-table-column>
+            </el-table>
+            <el-table v-if="timelyTaskHoursRadio == '按人员查看'"  key="321" border :data="timelyReportingOfTaskHoursList" highlight-current-row v-loading="timelyReportingOfTaskHoursLoading" :height="+tableHeight + 50" :span-method="timelyFormForFillingInTaskHoursSpanMethod" style="width: 100%;" :max-height="+tableHeight + 50">
+              <el-table-column prop="userName" align="center" label="人员"></el-table-column>
+              <el-table-column prop="taskName" align="center" label="任务"></el-table-column>
+              <el-table-column prop="startDate" align="center" label="任务开始时间"></el-table-column>
+              <el-table-column prop="endDate" align="center" label="任务截止时间"></el-table-column>
+              <el-table-column prop="timelinessRate" align="center" label="填报及时率"></el-table-column>
+              <el-table-column prop="timelinessRateWithLeave" align="center" label="填报及时率(含请假)"></el-table-column>
+              <el-table-column prop="averagePercentage" align="center" label="总填报及时率"></el-table-column>
+              <el-table-column prop="averageLeavePercentage" align="center" label="总填报及时率(含请假)"></el-table-column>
+            </el-table>
+          </template>
+          
         <!--工具条-->
-        <el-col :span="24" class="toolbar" v-if="ins != 6 && ins != 20 && ins != 21 && tabPosition==0 && tabsType == 'all' && ins != 31">
+        <el-col :span="24" class="toolbar" v-if="ins != 6 && ins != 20 && ins != 21 && tabPosition==0 && tabsType == 'all' && ins != 31 && ins != 32">
           <el-pagination
                 v-if="ins == 12"
                 @size-change="groupSizeChange"
@@ -2022,7 +2057,7 @@ export default {
         project: [4, 8, 9, 10, 11, 14, 15, 17, 19, 20, 21, 22, 28, 30, 31], // 项目筛选条件 (不等于)
         months: [14, 15], // 月份筛选条件 (等于)
         monthRange: [19, 30], // 月份区间筛选条件 (等于)
-        staff: [6, 8, 9, 19, 11, 14, 18, 23, 25, 26,28, 30], // 人员筛选条件 (等于)
+        staff: [6, 8, 9, 19, 11, 14, 18, 23, 25, 26,28, 30, 32], // 人员筛选条件 (等于)
         departments: [14, 15, 23,21,26,28,19, 30], // 部门筛选条件 (等于)
         timePeriod: [5, 6, 8, 9, 10, 11, 12, 16, 17, 18, 20, 21, 22, 24, 25, 26,28], // 时间段筛选条件 (等于)
       },
@@ -2083,14 +2118,14 @@ export default {
       this.$t('statisticsofovertimework'),this.$t('timecostearlywarningtable'),this.$t('personneltimeallocationtable'),
       this.$t('statisticsofstafffillingintimerate'),this.$t('dailyreporttobereviewedstatistics'),this.$t('statisticsofpersonnelhours'),this.$t('taskgrouptimesheet'),this.$t('projectcostbaselinetable'),
       this.$t('ren-yuan-yue-du-gong-shi-biao'), this.$t('bumenchanyuqingkuang'), this.$t('ge-fen-zu-yu-jie-duan-gong-shi-biao'), this.$t('ziXiangMuGongShiChengBenBiao'), this.$t('renWuZhongQiBiao'), this.$t('fteBaoBiao'), this.$t('youXiaoGongShiShuaiBiao'), this.$t('xiangMuFenLeiGongShiZhanBiBiao'), this.$t('fenLeiGongShiMingXiBiao'),
-      this.$t('yuanGongXiangMuJinDuBiao'), this.$t('fenZuHaoYongJinDuBiao'), this.$t('xiangMuHaoYongJinDuBiao'), this.$t('yuanGongRenWuJinDuBiao'), this.$t('xiangMuYuGuGongShiBiao'),this.$t('yuanGongRenWuWanChengQingKuangBiao'), this.$t('taskPlanCostReport'), 'FTE计划报表', '月度财务工时表'],
+      this.$t('yuanGongXiangMuJinDuBiao'), this.$t('fenZuHaoYongJinDuBiao'), this.$t('xiangMuHaoYongJinDuBiao'), this.$t('yuanGongRenWuJinDuBiao'), this.$t('xiangMuYuGuGongShiBiao'),this.$t('yuanGongRenWuWanChengQingKuangBiao'), this.$t('taskPlanCostReport'), 'FTE计划报表', '月度财务工时表', '任务工时填报及时表'],
 
       shuzArr: [this.$t('projectreport'),this.$t('projectTaskReport'),this.$t('projectcoststatement'),
       this.$t('projectbalancesheet'),this.$t('customerprojectincomestatement'),this.$t('projectphasetimesheet'),
       this.$t('statisticsofovertimework'),this.$t('timecostearlywarningtable'),this.$t('personneltimeallocationtable'),
       this.$t('employeereporttimelinessrate'),this.$t('dailyreporttobereviewedstatistics'),this.$t('statisticsofpersonnelhours'),this.$t('taskgrouptimesheet'),this.$t('projectcostbaselinetable'),
       this.$t('ren-yuan-yue-du-gong-shi-biao'), this.$t('bumenchanyuqingkuang'), this.$t('ge-fen-zu-yu-jie-duan-gong-shi-biao'), this.$t('ziXiangMuGongShiChengBenBiao'), this.$t('renWuZhongQiBiao'), this.$t('fteBaoBiao'),this.$t('youXiaoGongShiShuaiBiao'), this.$t('xiangMuFenLeiGongShiZhanBiBiao'), this.$t('fenLeiGongShiMingXiBiao'),
-      this.$t('yuanGongXiangMuJinDuBiao'), this.$t('fenZuHaoYongJinDuBiao'), this.$t('xiangMuHaoYongJinDuBiao'), this.$t('yuanGongRenWuJinDuBiao'), this.$t('xiangMuYuGuGongShiBiao'),this.$t('yuanGongRenWuWanChengQingKuangBiao'), this.$t('taskPlanCostReport'), 'FTE计划报表', '月度财务工时表'],
+      this.$t('yuanGongXiangMuJinDuBiao'), this.$t('fenZuHaoYongJinDuBiao'), this.$t('xiangMuHaoYongJinDuBiao'), this.$t('yuanGongRenWuJinDuBiao'), this.$t('xiangMuYuGuGongShiBiao'),this.$t('yuanGongRenWuWanChengQingKuangBiao'), this.$t('taskPlanCostReport'), 'FTE计划报表', '月度财务工时表', '任务工时填报及时表'],
 
       ins: 10000,
       user: JSON.parse(sessionStorage.user),
@@ -2274,6 +2309,10 @@ export default {
       adjustWorkingHoursVisable: false,
       immediateVisable: false,
       immediateDateValue: '',
+
+      timelyTaskHoursRadio: '按任务查看',
+      timelyReportingOfTaskHoursList: [],
+      timelyReportingOfTaskHoursLoading: false,
     };
   },
   computed: {},
@@ -2445,6 +2484,7 @@ export default {
       if(this.permissions.taskPlanCost) {this.ssl(29);this.takCompletedStatus = '1-30';return} else
       if(this.permissions.reportFTEPlanAll || this.permissions.reportFTEPlanPart) {this.ssl(30);this.takCompletedStatus = '1-31';return} else
       if(this.permissions.reportMonthlyFinancialWorkSchedule) {this.ssl(31);this.takCompletedStatus = '1-32';return} else
+      if(this.permissions.reportAllTimelyTaskHours || this.permissions.reportRartTimelyTaskHours) {this.ssl(32);this.takCompletedStatus = '1-33';return} else
       {this.allWrong = false}
     },
     rowspan(spanArr,position,spanName,dataItem = [],fields=false){
@@ -2749,7 +2789,7 @@ export default {
                 this.getGroupWorktimeAll()
             },
             getList(e) {
-              let noUserList = [16, 17, 18, 19, 20, 21, 22, 24, 25, 26,27,29,30,31]
+              let noUserList = [16, 17, 18, 19, 20, 21, 22, 24, 25, 26,27,29,30,31,32]
               if(this.ins == 24) {
                 if(this.tabsType == 'all') {
                   this.rangeDatas = []
@@ -2852,6 +2892,9 @@ export default {
                 if (this.ins == 31) {
                   this.getObtainMonthlyFinancialStatements();
                 }
+                if (this.ins == 32) {
+                  this.getTimelyReportingOfTaskHours();
+                }
             },
       exportExcel() {
         var url = "/project";
@@ -3097,7 +3140,16 @@ export default {
             sl.taskType = this.taskTypeId
           }
           sl.projectId = this.proJuctId
-        } 
+        } else if(this.ins == 32) {
+          fName = `${this.timelyTaskHoursRadio}任务工时填报及时表.xlsx`
+          url = `/report/exportReportRateOfTask`
+          sl.projectId = this.proJuctId
+          sl.userIds = this.userId
+          sl.type = {
+            '按任务查看': 0,
+            '按人员查看': 1,
+          }[this.timelyTaskHoursRadio]
+        }
         this.exportReportLoading = true
           this.http.post(url, sl,
             res => {
@@ -3188,6 +3240,9 @@ export default {
         this.projectMainId = ''
         this.getProjectListOvertime()
       }
+      if(index == 32) {
+        this.proJuctId = this.proListOvertime[0] && this.proListOvertime[0].id || ''
+      }
       this.getList();
     },
     stateKeySel(){
@@ -5103,6 +5158,96 @@ export default {
         })
       })
     },
+    // 任务工时填报及时表
+    getTimelyReportingOfTaskHours() {
+      console.log('发起请求 任务工时填报及时表', this.timelyTaskHoursRadio, this.page, this.size, this.total, this.proJuctId, this.userId, this.timelyReportingOfTaskHoursLoading, this.timelyReportingOfTaskHoursList)
+      let sl = {}
+      sl.projectId = this.proJuctId
+      sl.userIds = this.userId
+      sl.type = {
+        '按任务查看': 0,
+        '按人员查看': 1,
+      }[this.timelyTaskHoursRadio]
+      this.timelyReportingOfTaskHoursLoading = true
+      this.postData(`/report/getReportRateOfTask`, { ...sl }).then(res => { 
+        this.timelyReportingOfTaskHoursList = res.data || []
+      }).finally(() => {
+        this.timelyReportingOfTaskHoursLoading = false
+      })
+    },
+    
+    // 任务工时填报及时表开始合并
+    timelyFormForFillingInTaskHoursSpanMethod({ row, column, rowIndex }) {
+      const theFirstColumn = {
+        '按任务查看': ['projectName'],
+        '按人员查看': ['userName']
+      }
+
+      const secondColumn = {
+        '按任务查看': ['taskName'],
+        '按人员查看': ['averagePercentage', 'averageLeavePercentage']
+      }
+      if (theFirstColumn[this.timelyTaskHoursRadio].includes(column.property)) {
+        return this.getBelongingProjectSpan(rowIndex, theFirstColumn[this.timelyTaskHoursRadio]);
+      }
+      if (secondColumn[this.timelyTaskHoursRadio].includes(column.property)) {
+        return this.getTaskSpan(rowIndex, theFirstColumn[this.timelyTaskHoursRadio], column.property);
+      }
+
+      return { rowspan: 1, colspan: 1 };
+    },
+
+    getBelongingProjectSpan(rowIndex, filed) {
+      const data = this.timelyReportingOfTaskHoursList;
+      const currentProject = data[rowIndex][filed];
+      let rowspan = 1;
+
+      // 如果不是第一个或不是新分组的行,就返回 rowspan: 0(不显示)
+      if (rowIndex > 0 && data[rowIndex - 1][filed] === currentProject) {
+        return { rowspan: 0, colspan: 0 };
+      }
+
+      // 计算 rowspan
+      for (let i = rowIndex + 1; i < data.length; i++) {
+        if (data[i][filed] === currentProject) {
+          rowspan++;
+        } else {
+          break;
+        }
+      }
+      return { rowspan, colspan: 1 };
+    },
+
+    getTaskSpan(rowIndex, preconditions, postCondition) {
+      const data = this.timelyReportingOfTaskHoursList;
+      const currentTask = data[rowIndex][postCondition];
+      const currentProject = data[rowIndex][preconditions];
+      let rowspan = 1;
+
+      // 如果上一行任务和项目都一样,说明是连续的重复项,则返回 0
+      if (
+        rowIndex > 0 &&
+        data[rowIndex - 1][postCondition] === currentTask &&
+        data[rowIndex - 1][preconditions] === currentProject
+      ) {
+        return { rowspan: 0, colspan: 0 };
+      }
+
+      // 计算 rowspan
+      for (let i = rowIndex + 1; i < data.length; i++) {
+        if (
+          data[i][postCondition] === currentTask &&
+          data[i][preconditions] === currentProject
+        ) {
+          rowspan++;
+        } else {
+          break;
+        }
+      }
+
+      return { rowspan, colspan: 1 };
+    },
+
     // 单独封装请求
     async postData(urls, param) {
       return new Promise((resolve, reject) => {

+ 19 - 5
fhKeeper/formulahousekeeper/timesheet_mld/src/components/taskComponent.vue

@@ -1195,11 +1195,12 @@ export default {
             this.mileageCup = false
             this.addFormVisible = true;
             this.curProjectId = obj.stage.projectId;
+            const startDates = obj.addForm.startDate ? obj.addForm.startDate + ' 08:00:00' : ''
             this.addForm = {
                 projectId: obj.stage.projectId, 
                 groupId: obj.stage.groupId, 
                 stagesId: obj.stage.id, 
-                startDate: obj.addForm.startDate + ' 08:00:00',
+                startDate: startDates,
                 taskLevel:0, 
                 planHours: 8, 
                 taskType: 0
@@ -1597,8 +1598,6 @@ export default {
         );
     },
     getUsers() {
-        if (!this.addForm.projectId) return;
-        // if (!this.curProjectId && !) return
         this.http.post('/participation/getByProjectId', {projectId: this.addForm.projectId},
         res => {
             if (res.code == "ok") {
@@ -1932,16 +1931,31 @@ export default {
                                 message: this.$t('message.submittedSuccessfully'),
                                 type: "success"
                             });
-                            
                             if (this.addForm.parentTid == null) {
                                 let obj = {
                                     submitInsert: true,
                                     showOrNot: this.showOrNot
                                 }
+                                // if(!addFormData.id) {
+                                //     obj.dateList = [addFormData.startDate, addFormData.endDate]
+                                // }
+                                if(!addFormData.id) {
+                                    localStorage.setItem('ganttChartTaskId', JSON.stringify(res.data || []))
+                                }
                                 this.$emit('closeBounced', obj)
                             } else {
                                 // this.backToParentTask();
-                                this.$emit('closeBounced', {backToParentTaskSub: true})
+                                // if(!addFormData.id) {
+                                //     this.$emit('closeBounced', {
+                                //         backToParentTaskSub: true,
+                                //         dateList: [addFormData.startDate, addFormData.endDate]
+                                //     })
+                                // } else {
+                                    if(!addFormData.id) {
+                                        localStorage.setItem('ganttChartTaskId', JSON.stringify(res.data || []))
+                                    }
+                                    this.$emit('closeBounced', {backToParentTaskSub: true})
+                                // }
                             }
                         } else {
                             this.$message({

+ 30 - 0
fhKeeper/formulahousekeeper/timesheet_mld/src/views/project/gantt.vue

@@ -169,6 +169,25 @@ export default {
         this.addTask(row)
       }
     },
+    // 定位数据
+    focusAndSelectTaskFull(taskId) {
+      if (gantt.isTaskExists(taskId)) {
+        var task = gantt.getTask(taskId);
+        gantt.showTask(taskId);
+        gantt.selectTask(taskId);
+
+        // 检查日期有效性
+        if (!(task.start_date instanceof Date) || !(task.end_date instanceof Date)) {
+          console.error("Invalid date format in task:", task);
+          return;
+        }
+
+        var midTime = (task.start_date.getTime() + task.end_date.getTime()) / 2;
+        var midDate = new Date(midTime);
+
+        gantt.scrollTo(gantt.posFromDate(midDate) - 200, gantt.getScrollState().y);
+      }
+    }
   },
   mounted: function () {
     const userInfo = JSON.parse(sessionStorage.getItem("user"));
@@ -444,6 +463,17 @@ export default {
     gantt.init(this.$refs.ganttContainer);
     this.containerRect = this.$refs.ganttContainer.getBoundingClientRect();
     gantt.parse(this.$props.tasks);
+
+    setTimeout(() => {
+      // gantt.showTask('任务_2636_2339');
+      // gantt.selectTask('任务_2636_2339');
+      const list = JSON.parse(localStorage.getItem('ganttChartTaskId') || '[]')
+      if(list[0]) {
+        this.focusAndSelectTaskFull(list[0])
+      }
+
+      localStorage.removeItem('ganttChartTaskId')
+    }, 1000)
   }
 }
 

+ 17 - 0
fhKeeper/formulahousekeeper/timesheet_mld/src/views/project/project_gantt.vue

@@ -248,6 +248,9 @@ export default {
     this.isDataLoaded = true
 
     this.getTaskTypeList()
+
+    console.log('<===== 开始执行咯')
+    localStorage.removeItem('ganttChartTaskId')
   },
   methods: {
     getTaskTypeList() {
@@ -270,9 +273,23 @@ export default {
     },
     closeBounced(obj) {
       if(obj.submitInsert) {
+        if(obj.dateList && obj.dateList.length > 0) {
+          const formattedDates = obj.dateList.map(dateString => this.formatDate(dateString));
+          const one = formattedDates[0]
+          const two = formattedDates[1]
+          this.valueDate = [one, two]
+        }
         this.dateupdata()
       }
     },
+    formatDate(dateString) {
+      const date = new Date(dateString);
+      const year = date.getFullYear();
+      const month = String(date.getMonth() + 1).padStart(2, '0');
+      const day = String(date.getDate()).padStart(2, '0');
+      return `${year}-${month}-${day}`;
+    },
+
     selectCal(obj) {
       if(obj.distinction == '1') {
           this.valuex = obj.id

+ 22 - 22
fhKeeper/formulahousekeeper/timesheet_mld/src/views/task/list.vue

@@ -82,7 +82,7 @@
                 </el-form-item>
                 <el-form-item style="float: right;" v-if="user.companyId != '3092'">
                     <el-link type="primary" :underline="false" @click="isganttshow = true" style="margin-right: 10px;" v-if="permissions.projectResources">资源分配</el-link>
-                     <el-link type="primary" :underline="false" @click="addTask()">新建任务</el-link>
+                     <el-link type="primary" :underline="false" @click="addTask()">新建计划</el-link>
                      <el-link type="primary" :underline="false" @click="importTaskDialog = true" style="margin-left: 10px;">批量导入</el-link>
                      <el-link type="primary" :underline="false" @click="exportTaskList()" style="margin-left: 10px;" v-loading="exportTaskLoading"  >数据导出</el-link>
                 </el-form-item>
@@ -351,7 +351,7 @@
             </div>
         </el-dialog>
 
-        <!-- 任务详情信息弹出框 -->
+        <!-- 计划详情信息弹出框 -->
         <el-dialog :class="addForm.id==null?'':'jm'" :title="title" v-if="addFormVisible" :visible.sync="addFormVisible" 
         :close-on-click-modal="false" customClass="customWidth" width="840px" :top="'6vh'">
         <!-- <div style="width: 200%;height:80%;position: absolute;right:-100%;top:0;background:#000;opacity: 0;" @click="sss"></div> -->
@@ -759,7 +759,7 @@ import { getThemeColor } from '@/utils/commonMethod.js'
                 textContent: true, // 控制提交 
                 times: null,
                 text2: '',
-                innerVisibless: false, // 任务展示弹出层
+                innerVisibless: false, // 计划展示弹出层
                 activities: [{
                     content: this.$t('normals'),
                     timestamp: this.$t('hoursago'),
@@ -840,7 +840,7 @@ import { getThemeColor } from '@/utils/commonMethod.js'
             };
         },
         methods: {
-            // 批量导入任务
+            // 批量导入计划
             importTask(item) {
                 //首先判断文件类型
                 this.loadingExport = true
@@ -1017,7 +1017,7 @@ import { getThemeColor } from '@/utils/commonMethod.js'
                 this.rejectItem = data;
                 if (isPass) {
                     //弹窗confirm确认
-                    this.$confirm('确认审核通过该任务吗', this.$t('other.prompts'), {
+                    this.$confirm('确认审核通过该计划吗', this.$t('other.prompts'), {
                     //type: 'warning'
                     }).then(() => {
                         this.viewFilesAndReviewThemRejectCli(true);
@@ -1522,7 +1522,7 @@ import { getThemeColor } from '@/utils/commonMethod.js'
                     });
                 })
             },
-            // 导出任务
+            // 导出计划
             exportTask() {
                 // console.log('执行代码')
                 this.exportTaskLoading = true
@@ -1757,7 +1757,7 @@ import { getThemeColor } from '@/utils/commonMethod.js'
             },
             //进行中的,撤销操作
             cancelTask(item) {
-                this.$confirm('您确定要撤销该任务吗?', this.$t('other.prompts'), {
+                this.$confirm('您确定要撤销该计划吗?', this.$t('other.prompts'), {
                     //type: 'warning'
                 }).then(() => {
                     this.isDeleting = true;
@@ -1845,14 +1845,14 @@ import { getThemeColor } from '@/utils/commonMethod.js'
                     });
                 })
             },
-            // 重启任务点击事件
+            // 重启计划点击事件
             causeRejectionClick() {
                 this.causeRejectionForm.userList = this.causeRejectionForm.responsible.toString()
                 console.log(this.causeRejectionForm)
                 // return
                 this.restart(this.causeRejectionForm)
             },
-            // 点击任务事件
+            // 点击计划事件
             editTask(task) {
                 this.addFormVisible = true;
                 // this.addLoading = false;
@@ -1879,7 +1879,7 @@ import { getThemeColor } from '@/utils/commonMethod.js'
                 this.taskComponentFlg = true
 
                 this.getTaskDetail(task.id);
-                // this.getTaskProgressList(task.id); // 获取任务进展列表 
+                // this.getTaskProgressList(task.id); // 获取计划进展列表 
                 // this.getUsers(); // 获取名单数据
                 // this.gain(task); // 获取评论列表
                 // this.getDailyList(task.id) // 获取来自日报
@@ -1920,7 +1920,7 @@ import { getThemeColor } from '@/utils/commonMethod.js'
                     });
                 });
             },
-            //获取任务进展列表
+            //获取计划进展列表
             getTaskProgressList(taskId) {
                 this.taskIid = taskId
                 this.http.post('/task-progress/list', {taskId: taskId},
@@ -2016,11 +2016,11 @@ import { getThemeColor } from '@/utils/commonMethod.js'
             sss(){
                 this.$refs.addRem.style.display="none" 
             },
-            addprogress(){ // 添加子任务进展事件
+            addprogress(){ // 添加子计划进展事件
                 this.$refs.proBox.style.display="block"
                 this.$refs.addPro.style.display="none"
             },
-            shutPro() { // 关闭任务进展
+            shutPro() { // 关闭计划进展
                 this.$refs.addPro.style.display="block"
                 this.$refs.addRem.style.display="none" 
                 this.$refs.proBox.style.display="none" 
@@ -2043,12 +2043,12 @@ import { getThemeColor } from '@/utils/commonMethod.js'
                     this.checkLists.splice(k, 1)
                 }
             },
-            shutPro() { // 关闭任务进展
+            shutPro() { // 关闭计划进展
                 this.$refs.addPro.style.display="block"
                 this.$refs.addRem.style.display="none" 
                 this.$refs.proBox.style.display="none" 
             },
-            addTaskProgress() { //创建任务进展
+            addTaskProgress() { //创建计划进展
                 var param = {
                     taskId: this.taskIid,
                     status: this.radio,
@@ -2081,7 +2081,7 @@ import { getThemeColor } from '@/utils/commonMethod.js'
                     }
                 );
             },
-            //删除任务进展
+            //删除计划进展
             deleteTaskProgress(id) {
                 this.http.post('/task-progress/deleteProgress', {id: id},
                     res => {
@@ -2100,7 +2100,7 @@ import { getThemeColor } from '@/utils/commonMethod.js'
                     }
                 );
             },
-            //显示子任务创建卡片
+            //显示子计划创建卡片
             addSubTask() {
                 this.addFormVisible = true;
                 this.addForm = {parentTname: this.addForm.name,parentTid: this.addForm.id,projectId: this.addForm.projectId, groupId: this.addForm.groupId,  taskLevel:0, planHours: 8, taskType: 0};
@@ -2133,7 +2133,7 @@ import { getThemeColor } from '@/utils/commonMethod.js'
                             });
                         });
             },
-            //认领任务
+            //认领计划
             addAsMyTask(task) {
                 this.http.post('/task/addAsMyTask',{id: task.id},
                 res => {
@@ -2338,14 +2338,14 @@ import { getThemeColor } from '@/utils/commonMethod.js'
                         }
                 });
             },
-            //加载项目内的任务列表
+            //加载项目内的计划列表
             getStageList() {
                 // console.log('进来了')
                 this.http.post('/stages/list',{groupId: this.selectedGroup.id, projectId: this.selectedGroup.projectId, order: this.order, isDesc: this.isDesc},
                 res => {
                     if (res.code == "ok") {
                         this.stageList = res.data.list;
-                        // console.log('触发获取任务列表函数')
+                        // console.log('触发获取计划列表函数')
                         this.timess() // 处理时间的方法
                     } else {
                         this.$message({
@@ -2361,7 +2361,7 @@ import { getThemeColor } from '@/utils/commonMethod.js'
                     });
                 });
             },
-            //删除当前编辑的任务
+            //删除当前编辑的计划
             deleteTask() {
                 var warning='';
                 if (this.addForm.subTaskList.length > 0) {
@@ -2501,7 +2501,7 @@ import { getThemeColor } from '@/utils/commonMethod.js'
                     });
                 });
             },
-            // 获取任务分组列表
+            // 获取计划分组列表
             getTaskGroupList() {
                 this.http.post('/task-group/list',{
                     projectId: this.screenProjectId