Jelajahi Sumber

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

QuYueTing 11 bulan lalu
induk
melakukan
16bbe80afa
51 mengubah file dengan 2333 tambahan dan 151 penghapusan
  1. 1 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/components/TaskModal/index.vue
  2. 2 1
      fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/contacts/component/relatedBusiness.vue
  3. 19 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ProjectController.java
  4. 24 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ReportController.java
  5. 2 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ReportLogController.java
  6. 20 2
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/UserController.java
  7. 87 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/UserGroupController.java
  8. 36 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/UserWorkbenchController.java
  9. 6 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/User.java
  10. 54 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/UserGroup.java
  11. 44 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/UserWorkbench.java
  12. 3 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/vo/UserVO.java
  13. 12 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/ProjectMapper.java
  14. 16 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/UserGroupMapper.java
  15. 16 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/UserWorkbenchMapper.java
  16. 7 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/ProjectService.java
  17. 16 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/UserGroupService.java
  18. 1 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/UserService.java
  19. 19 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/UserWorkbenchService.java
  20. 235 17
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ProjectServiceImpl.java
  21. 1 5
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ReportServiceImpl.java
  22. 20 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/UserGroupServiceImpl.java
  23. 10 3
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/UserServiceImpl.java
  24. 73 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/UserWorkbenchServiceImpl.java
  25. 1 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/util/MessageUtils.java
  26. 4 2
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/application.yml
  27. 230 5
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/ProjectMapper.xml
  28. 18 0
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/UserGroupMapper.xml
  29. 4 2
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/UserMapper.xml
  30. 16 0
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/UserWorkbenchMapper.xml
  31. TEMPAT SAMPAH
      fhKeeper/formulahousekeeper/management-platform/费用报销导入模板.xlsx
  32. 17 10
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/controller/WxCorpInfoController.java
  33. 13 11
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/impl/DepartmentServiceImpl.java
  34. 17 6
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/impl/ReportServiceImpl.java
  35. 17 11
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/task/TimingTask.java
  36. 5 4
      fhKeeper/formulahousekeeper/management-workshop/src/main/resources/mapper/ReportMapper.xml
  37. 92 0
      fhKeeper/formulahousekeeper/timesheet-workshop/src/views/plan/orderInsert.vue
  38. 2 2
      fhKeeper/formulahousekeeper/timesheet-workshop/src/views/statistic/index.vue
  39. 5 0
      fhKeeper/formulahousekeeper/timesheet/src/components/echartsEchar.vue
  40. 1 1
      fhKeeper/formulahousekeeper/timesheet/src/http.js
  41. 2 1
      fhKeeper/formulahousekeeper/timesheet/src/i18n/en.json
  42. 2 1
      fhKeeper/formulahousekeeper/timesheet/src/i18n/zh.json
  43. 5 0
      fhKeeper/formulahousekeeper/timesheet/src/permissions.js
  44. 4 0
      fhKeeper/formulahousekeeper/timesheet/src/routes.js
  45. 283 7
      fhKeeper/formulahousekeeper/timesheet/src/views/corpreport/echartsData.js
  46. 189 49
      fhKeeper/formulahousekeeper/timesheet/src/views/corpreport/list.vue
  47. 370 0
      fhKeeper/formulahousekeeper/timesheet/src/views/corpreport/packetConsumption/tables.vue
  48. 7 3
      fhKeeper/formulahousekeeper/timesheet/src/views/project/info.vue
  49. 73 1
      fhKeeper/formulahousekeeper/timesheet/src/views/team/index.vue
  50. 231 0
      fhKeeper/formulahousekeeper/timesheet/src/views/userGrouping/userGrouping.vue
  51. 1 1
      fhKeeper/formulahousekeeper/timesheet/src/views/workReport/list.vue

+ 1 - 1
fhKeeper/formulahousekeeper/customerBuler-crm/src/components/TaskModal/index.vue

@@ -41,7 +41,7 @@
         </el-form-item>
         <el-form-item label="联系人:" v-if="TASK_TYPE.find(v => v.value == (form.taskType || '1'))?.show">
           <el-select v-model="form.contactsId" placeholder="请选择" clearable filterable
-            :disabled="(disabledList && disabledList.includes('contactsId'))">
+            :disabled="(disabledList && disabledList.includes('contactsId')) || !form[TASK_TYPE_FIELD[form.taskType].field]">
             <el-option v-for="item in contactValueData" :key="item.id" :value="item.id" :label="item.name" />
           </el-select>
         </el-form-item>

+ 2 - 1
fhKeeper/formulahousekeeper/customerBuler-crm/src/pages/contacts/component/relatedBusiness.vue

@@ -146,7 +146,8 @@ watchEffect(() => {
     relatedTaskstable.value = (data.businessOpportunityList || []).map((item: any) => {
         return {
             ...item,
-            expectedTransactionDate: item.expectedTransactionDate ? formatDate(new Date(item.expectedTransactionDate)) : ''
+            expectedTransactionDate: item.expectedTransactionDate ? formatDate(new Date(item.expectedTransactionDate)) : '',
+            editTime: item.editTime ? formatDate(new Date(item.editTime)) : ''
         }
     })
 });

+ 19 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ProjectController.java

@@ -1477,12 +1477,30 @@ public class ProjectController {
         return projectService.groupExpendProcessList(startDate,endDate,projectId,pageIndex,pageSize);
     }
 
-    //依斯倍定制 分组耗用进度
+    //依斯倍定制 分组耗用
     @RequestMapping("/groupExpendProcessListForChart")
     public HttpRespMsg groupExpendProcessListForChart(String startDate,String endDate,String projectIds,String groupNames){
         return projectService.groupExpendProcessListForChart(startDate,endDate,projectIds,groupNames);
     }
 
+    //依斯倍定制 分组耗用人员分组耗用
+    @RequestMapping("/groupExpendProcessListForUser")
+    public HttpRespMsg groupExpendProcessListForUser(String startDate,String endDate,String projectIds,String groupNames,String deptIdStr,Integer pageIndex,Integer pageSize){
+        return projectService.groupExpendProcessListForUser(startDate,endDate,projectIds,groupNames,deptIdStr,pageIndex,pageSize);
+    }
+
+    //依斯倍定制 分组耗用人员分组耗用
+    @RequestMapping("/exportGroupExpendProcessListForUser")
+    public HttpRespMsg exportGroupExpendProcessListForUser(String startDate,String endDate,String projectIds,String groupNames,String titleStr,String deptIdStr){
+        return projectService.exportGroupExpendProcessListForUser(startDate,endDate,projectIds,groupNames,titleStr,deptIdStr);
+    }
+
+    //依斯倍定制 分组耗用表项目占比
+    @RequestMapping("/groupExpendProcessListForProject")
+    public HttpRespMsg groupExpendProcessListForProject(String startDate,String endDate,String projectIds,String groupNames,String deptIdStr,Integer pageIndex,Integer pageSize){
+        return projectService.groupExpendProcessListForProject(startDate,endDate,projectIds,groupNames,deptIdStr,pageIndex,pageSize);
+    }
+
     //依斯倍定制 导出分组耗用进度表
     @RequestMapping("/exportGroupExpendProcessList")
     public HttpRespMsg exportGroupExpendProcessList(String startDate,String endDate,Integer projectId){

+ 24 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ReportController.java

@@ -111,6 +111,8 @@ public class ReportController {
     private UserFvTimeMapper userFvTimeMapper;
     @Resource
     private UserCustomMapper userCustomMapper;
+    @Resource
+    private UserGroupMapper userGroupMapper;
 
     //获取任务相关的日报列表
     @RequestMapping("/getTaskReportList")
@@ -1304,6 +1306,28 @@ public class ReportController {
             }
         }
 
+        //校验非项目工时占比
+        User reportOwner = userMapper.selectById(reportList.get(0).getCreatorId());
+        if (reportOwner.getUserGroupId() != null) {
+            //获取非项目列表
+            List<Project> nonProjectList = projectMapper.selectList(new QueryWrapper<Project>().select("id").eq("is_public", 1).eq("company_id", reportOwner.getCompanyId()));
+            List<Integer> collect = nonProjectList.stream().map(Project::getId).collect(Collectors.toList());
+            List<Report> oldRelatedReportList = reportMapper.selectList(new QueryWrapper<Report>().select("id,project_id,working_time").eq("creator_id", reportOwner.getId()).and(wrapper->wrapper.eq("state",0).or().eq("state",1).or().eq("state",3)));
+            //剔除掉当前日报中的
+            oldRelatedReportList = oldRelatedReportList.stream().filter(old->!reportList.stream().map(Report::getId).collect(Collectors.toList()).contains(old.getId())).collect(Collectors.toList());
+            oldRelatedReportList.addAll(reportList);
+            double totalWorkingTime = oldRelatedReportList.stream().mapToDouble(Report::getWorkingTime).sum();
+            double nonProjectWorkingTime = oldRelatedReportList.stream().filter(old->collect.contains(old.getProjectId())).mapToDouble(Report::getWorkingTime).sum();
+            double percent = 100*nonProjectWorkingTime/totalWorkingTime;
+            
+            int maxPercent = userGroupMapper.selectById(reportOwner.getUserGroupId()).getNoProjectPercent();
+            if(percent > maxPercent){
+                HttpRespMsg httpRespMsg = new HttpRespMsg();
+                httpRespMsg.setError("非项目工时占比不得超过"+maxPercent+"%");
+                return httpRespMsg;
+            }
+        }
+
         //如果锁定工作时长上限的话,需要校验每日的合计工作时长
         for (Report report : reportList) {
             String creatorId = report.getCreatorId();
@@ -1430,7 +1454,6 @@ public class ReportController {
             for (Report report : reportList) {
                 report.setDepartmentAuditState(0);
                 //优先按照当前日报填写人的直属审核人审核
-                User reportOwner = creatorList.stream().filter(c->c.getId().equals(report.getCreatorId())).findFirst().get();
                 if (!StringUtils.isEmpty(reportOwner.getSuperiorId())) {
                     User auditor = tempAuditorUserList.stream().filter(t -> t.getId().equals(reportOwner.getSuperiorId())).findFirst().get();
                     report.setProjectAuditorId(auditor.getId());

+ 2 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ReportLogController.java

@@ -179,7 +179,8 @@ public class ReportLogController {
             item.add(String.valueOf(df1.format(reportLog.getOperateDate())));
             dataList.add(item);
         }
-        String resp = ExcelUtil.exportGeneralExcelByTitleAndList("日报审核记录", dataList, path);
+        String fileName = "日报审核记录_"+System.currentTimeMillis();
+        String resp = ExcelUtil.exportGeneralExcelByTitleAndList(fileName, dataList, path);
         msg.setData(resp);
         return msg;
     }

+ 20 - 2
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/UserController.java

@@ -113,6 +113,8 @@ public class UserController {
     private UserMapper userMapper;
     @Resource
     private UserCertMapper userCertMapper;
+    @Resource
+    private UserGroupMapper userGroupMapper;
 
     public static HashMap<String, Integer> corpddJobCenter = new HashMap();
     //用于控制线程锁
@@ -235,9 +237,9 @@ public class UserController {
                                   @RequestParam Integer roleId, Double monthCost, Double cost,
                                   Integer departmentId, Integer salaryType, String costApplyDate,
                                     String position, String certJson,String inductionDate,String superiorId,
-                                    String plate1,String plate2,String plate3,String plate4,String plate5, String jobNumber, String inactiveDate,String reportDeptIds) {
+                                    String plate1,String plate2,String plate3,String plate4,String plate5, String jobNumber, String inactiveDate,String reportDeptIds,Integer groupId) {
         return userService.insertUser(id, name, phone, onlyAuditOnce, roleId, monthCost, cost, departmentId, salaryType, costApplyDate,
-                    position, certJson, request,inductionDate,superiorId,plate1, plate2, plate3,plate4,plate5, jobNumber, inactiveDate,reportDeptIds);
+                    position, certJson, request,inductionDate,superiorId,plate1, plate2, plate3,plate4,plate5, jobNumber, inactiveDate,reportDeptIds,groupId);
     }
 
     /**
@@ -996,5 +998,21 @@ public class UserController {
         return msg;
     }
 
+    @RequestMapping("/batchSetUserGroup")
+    public HttpRespMsg batchSetUserGroup(String userIds,Integer groupId){
+        HttpRespMsg msg=new HttpRespMsg();
+        if(!StringUtils.isEmpty(userIds)){
+            List<String> list = Arrays.asList(userIds.split(","));
+            List<User> userList = userMapper.selectList(new LambdaQueryWrapper<User>().in(User::getId, list));
+            userList.forEach(u->{
+                u.setUserGroupId(groupId);
+            });
+            if(!userService.updateBatchById(userList)){
+                msg.setError("验证失败");
+            }
+        }
+        return msg;
+    }
+
 }
 

+ 87 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/UserGroupController.java

@@ -0,0 +1,87 @@
+package com.management.platform.controller;
+
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.management.platform.entity.User;
+import com.management.platform.entity.UserGroup;
+import com.management.platform.mapper.UserGroupMapper;
+import com.management.platform.mapper.UserMapper;
+import com.management.platform.service.UserGroupService;
+import com.management.platform.service.UserService;
+import com.management.platform.util.HttpRespMsg;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <p>
+ *  前端控制器
+ * </p>
+ *
+ * @author Seyason
+ * @since 2024-07-29
+ */
+@RestController
+@RequestMapping("/user-group")
+@RequiredArgsConstructor
+public class UserGroupController {
+
+    private final UserGroupService userGroupService;
+    private final UserMapper userMapper;
+    private final HttpServletRequest request;
+    private final UserService userService;
+
+
+    @RequestMapping("/addOrUpdate")
+    public HttpRespMsg addOrUpdate(UserGroup userGroup){
+        HttpRespMsg msg=new HttpRespMsg();
+        Integer companyId = userMapper.selectById(request.getHeader("token")).getCompanyId();
+        userGroup.setCompanyId(companyId);
+        Integer count;
+        if(userGroup.getId()==null){
+            count=userGroupService.count(new LambdaQueryWrapper<UserGroup>().eq(UserGroup::getCompanyId,companyId).eq(UserGroup::getGroupName,userGroup.getGroupName()));
+        }else {
+            count=userGroupService.count(new LambdaQueryWrapper<UserGroup>().ne(UserGroup::getId,userGroup.getId()).eq(UserGroup::getCompanyId,companyId).eq(UserGroup::getGroupName,userGroup.getGroupName()));
+        }
+        if(count>0){
+            msg.setError("分组:"+userGroup.getGroupName()+"已存在");
+            return msg;
+        }
+        userGroupService.saveOrUpdate(userGroup);
+        return msg;
+    }
+
+    @RequestMapping("/delete")
+    public HttpRespMsg delete(Integer id){
+        HttpRespMsg msg=new HttpRespMsg();
+        Integer count = userMapper.selectCount(new LambdaQueryWrapper<User>().eq(User::getUserGroupId, id));
+        if(count>0){
+            msg.setError("存在处于当前分组的人员,无法删除");
+            return msg;
+        }
+        if(!userGroupService.removeById(id)){
+            msg.setError("验证失败");
+        }
+        return msg;
+    }
+
+    @RequestMapping("/list")
+    public HttpRespMsg list(){
+        HttpRespMsg msg=new HttpRespMsg();
+        Integer companyId = userMapper.selectById(request.getHeader("token")).getCompanyId();
+        LambdaQueryWrapper<UserGroup> wrapper = new LambdaQueryWrapper<UserGroup>().eq(UserGroup::getCompanyId, companyId).orderByDesc(UserGroup::getId);
+        List<UserGroup> list = userGroupService.list(wrapper);
+        msg.setData(list);
+        return msg;
+    }
+
+}
+

+ 36 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/UserWorkbenchController.java

@@ -0,0 +1,36 @@
+package com.management.platform.controller;
+
+
+import com.management.platform.entity.UserWorkbench;
+import com.management.platform.service.UserWorkbenchService;
+import com.management.platform.util.HttpRespMsg;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+
+/**
+ * <p>
+ *  前端控制器
+ * </p>
+ *
+ * @author Seyason
+ * @since 2024-08-06
+ */
+@RestController
+@RequestMapping("/user-workbench")
+public class UserWorkbenchController {
+    @Resource
+    private UserWorkbenchService userWorkbenchService;
+
+    @RequestMapping("/saveWorkbench")
+    public HttpRespMsg saveWorkbench(String userId, String workbench) {
+        UserWorkbench userWorkbench = new UserWorkbench();
+        userWorkbench.setUserId(userId);
+        userWorkbench.setTableList(workbench);
+        userWorkbenchService.saveOrUpdate(userWorkbench);
+        return new HttpRespMsg();
+    }
+}
+

+ 6 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/User.java

@@ -296,6 +296,12 @@ public class User extends Model<User> {
     @TableField("only_audit_once")
     private Integer onlyAuditOnce;
 
+    /**
+     * 人员所属分组
+     */
+    @TableField("user_group_id")
+    private Integer userGroupId;
+
     @TableField(exist = false)
     private List<Department> userReportDeptList;
 

+ 54 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/UserGroup.java

@@ -0,0 +1,54 @@
+package com.management.platform.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableField;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 
+ * </p>
+ *
+ * @author Seyason
+ * @since 2024-07-29
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class UserGroup extends Model<UserGroup> {
+
+    private static final long serialVersionUID=1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 公司id
+     */
+    @TableField("company_id")
+    private Integer companyId;
+
+    /**
+     * 分组名称
+     */
+    @TableField("group_name")
+    private String groupName;
+
+    /**
+     * 非项目工时占比
+     */
+    @TableField("no_project_percent")
+    private Integer noProjectPercent;
+
+
+    @Override
+    protected Serializable pkVal() {
+        return this.id;
+    }
+
+}

+ 44 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/UserWorkbench.java

@@ -0,0 +1,44 @@
+package com.management.platform.entity;
+
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableField;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 
+ * </p>
+ *
+ * @author Seyason
+ * @since 2024-08-06
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class UserWorkbench extends Model<UserWorkbench> {
+
+    private static final long serialVersionUID=1L;
+
+    /**
+     * 用户id
+     */
+    @TableId("user_id")
+    private String userId;
+
+    /**
+     * 表集合,json array格式
+     */
+    @TableField("table_list")
+    private String tableList;
+
+
+    @Override
+    protected Serializable pkVal() {
+        return this.userId;
+    }
+
+}

+ 3 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/vo/UserVO.java

@@ -1,5 +1,6 @@
 package com.management.platform.entity.vo;
 
+import com.alibaba.fastjson.JSONArray;
 import com.management.platform.entity.*;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
@@ -26,4 +27,6 @@ public class UserVO extends User {
 
     private boolean hasAuditDept;
 
+    private JSONArray userWorkbench;
+
 }

+ 12 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/ProjectMapper.java

@@ -9,6 +9,7 @@ import com.management.platform.entity.vo.StageCost;
 import com.management.platform.entity.vo.UserCateTimeVo;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Update;
+import org.omg.CORBA.INTERNAL;
 
 import java.time.LocalDate;
 import java.util.HashMap;
@@ -186,4 +187,15 @@ public interface ProjectMapper extends BaseMapper<Project> {
     void removeReviwer(Integer id);
 
     List<Map<String, Object>> groupExpendProcessListForChart(String userId, Integer companyId, String startDate, String endDate,@Param("list") List<Integer> deptIds,@Param("listSecond") List<Integer> regularDeptIds,@Param("listThird") List<Integer> projectIdList,@Param("listFour") List<String> groupNameList);
+
+    List<Map<String, Object>> groupExpendProcessListForUser(String userId, Integer companyId, String startDate, String endDate, @Param("list") List<Integer> deptIds, @Param("listSecond") List<Integer> regularDeptIds, @Param("listThird")List<Integer> projectIdList, @Param("listFour") List<String> groupNameList, @Param("listFive") List<Integer> deptIdList,Integer start,Integer size);
+
+    Integer groupExpendProcessListForUserCount(String userId, Integer companyId, String startDate, String endDate, @Param("list") List<Integer> deptIds, @Param("listSecond") List<Integer> regularDeptIds, @Param("listThird")List<Integer> projectIdList, @Param("listFour") List<String> groupNameList, @Param("listFive") List<Integer> deptIdList);
+
+    List<Map<String, Object>> groupExpendProcessListForProject(String userId,  Integer companyId, String startDate, String endDate, @Param("list") List<Integer> deptIds, @Param("listSecond") List<Integer> regularDeptIds, @Param("listThird")List<Integer> projectIdList, @Param("listFour") List<String> groupNameList, @Param("listFive") List<Integer> deptIdList,Integer start,Integer size);
+
+    Integer groupExpendProcessListForProjectCount(String userId, Integer companyId, String startDate, String endDate, @Param("list") List<Integer> deptIds, @Param("listSecond") List<Integer> regularDeptIds, @Param("listThird")List<Integer> projectIdList, @Param("listFour") List<String> groupNameList, @Param("listFive") List<Integer> deptIdList);
+
+    @Update("update project set category=null,category_name=null where id=#{id}")
+    void updateProjectCategoryToNull(@Param("id") Integer id);
 }

+ 16 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/UserGroupMapper.java

@@ -0,0 +1,16 @@
+package com.management.platform.mapper;
+
+import com.management.platform.entity.UserGroup;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ *  Mapper 接口
+ * </p>
+ *
+ * @author Seyason
+ * @since 2024-07-29
+ */
+public interface UserGroupMapper extends BaseMapper<UserGroup> {
+
+}

+ 16 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/UserWorkbenchMapper.java

@@ -0,0 +1,16 @@
+package com.management.platform.mapper;
+
+import com.management.platform.entity.UserWorkbench;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ *  Mapper 接口
+ * </p>
+ *
+ * @author Seyason
+ * @since 2024-08-06
+ */
+public interface UserWorkbenchMapper extends BaseMapper<UserWorkbench> {
+
+}

+ 7 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/ProjectService.java

@@ -300,4 +300,11 @@ public interface ProjectService extends IService<Project> {
     HttpRespMsg batchSetProjectTaskExecutor(String projectIds, String userIds);
 
     HttpRespMsg groupExpendProcessListForChart(String startDate, String endDate, String projectIds, String groupNames);
+
+    HttpRespMsg groupExpendProcessListForUser(String startDate, String endDate, String projectIds, String groupNames, String deptIdStr,Integer pageIndex,Integer pageSize);
+
+    HttpRespMsg groupExpendProcessListForProject(String startDate, String endDate, String projectIds, String groupNames, String deptIdStr,Integer pageIndex,Integer pageSize);
+
+    HttpRespMsg exportGroupExpendProcessListForUser(String startDate, String endDate, String projectIds, String groupNames,String titleStr, String deptIdStr);
+
 }

+ 16 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/UserGroupService.java

@@ -0,0 +1,16 @@
+package com.management.platform.service;
+
+import com.management.platform.entity.UserGroup;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ *  服务类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2024-07-29
+ */
+public interface UserGroupService extends IService<UserGroup> {
+
+}

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

@@ -38,7 +38,7 @@ public interface UserService extends IService<User> {
     HttpRespMsg insertUser(String id, String name, String phone,Integer onlyAuditOnce, Integer roleId, Double monthCost, Double cost, Integer departmentId,
                            Integer salaryType, String costApplyDate, String position, String certJson,
                            HttpServletRequest request,String inductionDate, String superiorId,String plate1,
-                           String plate2,String plate3,String plate4,String plate5, String jobNumber, String inactiveDate,String reportDeptIds);
+                           String plate2,String plate3,String plate4,String plate5, String jobNumber, String inactiveDate,String reportDeptIds,Integer groupId);
 
     HttpRespMsg importUser(MultipartFile multipartFile, HttpServletRequest request);
 

+ 19 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/UserWorkbenchService.java

@@ -0,0 +1,19 @@
+package com.management.platform.service;
+
+import com.alibaba.fastjson.JSONArray;
+import com.management.platform.entity.UserWorkbench;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ *  服务类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2024-08-06
+ */
+public interface UserWorkbenchService extends IService<UserWorkbench> {
+
+    public JSONArray getMyWorkbench(String userId);
+
+}

+ 235 - 17
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ProjectServiceImpl.java

@@ -318,7 +318,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                     .mapToDouble(r->r.getWorkingTime()).sum();
             String rWorkTime=reallWorkTime==null ? "0":df.format(reallWorkTime);
             project.setReallyWorkTime(rWorkTime);
-            String pEstimatedWork=Integer.valueOf(String.valueOf(project.getManDay()))==null ? 0*allday+"": project.getManDay()*allday+"";
+            String pEstimatedWork=project.getManDay()==null? "0": (project.getManDay()*allday+"");
             project.setEstimatedWorkTime(pEstimatedWork);
             List<TaskGroup> taskGroupCollect = taskGroups.stream().filter(t -> t.getProjectId().equals(project.getId())).collect(Collectors.toList());
 
@@ -649,17 +649,20 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
             }
             long end = System.currentTimeMillis();
             List<String> stringList = providerCategoryList.stream().map(ProviderCategory::getProviderCategoryName).distinct().collect(Collectors.toList());
-            //处理项目日报审核人
-            if(projectIds.size()>0){
-                List<ProjectAuditor> projectAuditorList = projectAuditorMapper.selectList(new LambdaQueryWrapper<ProjectAuditor>().in(ProjectAuditor::getProjectId, projectIds));
-                list.forEach(l->{
-                    Optional<ProjectAuditor> first = projectAuditorList.stream().filter(p -> p.getProjectId().equals(l.getId())).findFirst();
-                    if(first.isPresent()){
-                        l.setProjectAuditorName(first.get().getAuditorName());
-                        l.setProjectAuditorId(first.get().getAuditorId());
-                    }
-                });
+            //针对成都明夷电子科技有限公司,显示项目日报审核人
+            if (company.getCompanyName().equals("成都明夷电子科技有限公司")) {
+                if(projectIds.size()>0){
+                    List<ProjectAuditor> projectAuditorList = projectAuditorMapper.selectList(new LambdaQueryWrapper<ProjectAuditor>().in(ProjectAuditor::getProjectId, projectIds));
+                    list.forEach(l->{
+                        Optional<ProjectAuditor> first = projectAuditorList.stream().filter(p -> p.getProjectId().equals(l.getId())).findFirst();
+                        if(first.isPresent()){
+                            l.setProjectAuditorName(first.get().getAuditorName());
+                            l.setProjectAuditorId(first.get().getAuditorId());
+                        }
+                    });
+                }
             }
+
             //stringList.add("未分类");
             stringList.add(MessageUtils.message("excel.unclassified"));
             Long total = projectIPage.getTotal();
@@ -1020,6 +1023,8 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                         p.setCategory(category);
                         p.setCategoryName(projectCategory.getName());
                     }
+                }else {
+                    projectMapper.updateProjectCategoryToNull(p.getId());
                 }
                 ProjectSeparate oldSeparate = projectSeparateMapper.selectById(id);
                 if(companyId==936){
@@ -2219,9 +2224,9 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
             //String fileName = "项目成本工时统计_"+System.currentTimeMillis();
             String fileName = null;
             if (withMainProject == 1) {
-                fileName = "主项目成本工时统计"+System.currentTimeMillis();
+                fileName = "主项目成本工时统计" +(startDate==null?"":(startDate+MessageUtils.message("leave.to")+endDate))+System.currentTimeMillis();
             } else {
-                fileName = MessageUtils.message("fileName.projectCost")+System.currentTimeMillis();
+                fileName = (startDate==null?"":(startDate+MessageUtils.message("leave.to")+endDate)) + MessageUtils.message("fileName.projectCost")+System.currentTimeMillis();
             }
 
             return excelExportService.exportGeneralExcelByTitleAndList(wxCorpInfo,dingding,fileName , allList, path);
@@ -8227,7 +8232,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
             }
             //生成excel文件导出
             //String fileName = "项目分类工时成本统计_"+System.currentTimeMillis();
-            String fileName = MessageUtils.message("fileName.proClassLaborCost")+System.currentTimeMillis();
+            String fileName = (startDate==null?"":(startDate+MessageUtils.message("leave.to")+endDate)) + MessageUtils.message("fileName.proClassLaborCost")+System.currentTimeMillis();
             try {
                 return excelExportService.exportGeneralExcelByTitleAndList(wxCorpInfo,dingding,fileName , allList, path);
             } catch (Exception e) {
@@ -11789,7 +11794,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
             allList.add(sumRow);
             //生成excel文件导出
             //String fileName = "维度成本工时统计_"+System.currentTimeMillis();
-            String fileName = timeType.getCustomDegreeName() + MessageUtils.message("fileName.degreeCost")+System.currentTimeMillis();
+            String fileName = (startDate==null?"":(startDate+MessageUtils.message("leave.to")+endDate)) + timeType.getCustomDegreeName() + MessageUtils.message("fileName.degreeCost")+System.currentTimeMillis();
             return excelExportService.exportGeneralExcelByTitleAndList(wxCorpInfo,dingding,fileName , allList, path);
         } catch (NullPointerException e) {
             e.printStackTrace();
@@ -13552,8 +13557,6 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                             item.put("corpwxDeptId",corpwxDeptid);
                             item.put("department_name",departmentName);
                             if(taskGroup.isPresent()){
-//                                List<Map<String, Object>> mapList = resultList.stream().filter(r -> Integer.valueOf(String.valueOf(r.get("projectId"))).equals(project.getId())
-//                                        && Integer.valueOf(String.valueOf(r.get("groupId"))).equals(taskGroup.get().getId()) && (Integer.valueOf(String.valueOf(r.get("deptId"))).equals(7458) || subDeptIds.contains(Integer.valueOf(String.valueOf(r.get("deptId")))))).collect(Collectors.toList());
                                 List<Map<String, Object>> mapList = resultList.stream().filter(r -> Integer.valueOf(String.valueOf(r.get("projectId"))).equals(project.getId())
                                         && Integer.valueOf(String.valueOf(r.get("groupId"))).equals(taskGroup.get().getId())).collect(Collectors.toList());
                                 if(mapList!=null&&mapList.size()>0){
@@ -14407,4 +14410,219 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
         msg.setData(resultList);
         return msg;
     }
+
+    @Override
+    public HttpRespMsg groupExpendProcessListForUser(String startDate, String endDate, String projectIds, String groupNames, String deptIdStr,Integer pageIndex,Integer pageSize) {
+        HttpRespMsg msg=new HttpRespMsg();
+        User user = userMapper.selectById(request.getHeader("token"));
+        List<Department> departments = departmentMapper.selectList(new LambdaQueryWrapper<Department>().eq(Department::getCompanyId, user.getCompanyId()));
+        NumberFormat percentFormat = NumberFormat.getPercentInstance();
+        percentFormat.setMaximumFractionDigits(2);
+        Integer start=null;
+        Integer size=null;
+        if(pageIndex!=null&&pageSize!=null){
+            size=pageSize;
+            start=(pageIndex-1)*size;
+        }
+        Integer companyId = user.getCompanyId();
+        List<String> groupNameList=new ArrayList<>();
+        List<Integer> projectIdList=new ArrayList<>();
+        List<Integer> deptIdList=new ArrayList<>();
+        if(!StringUtils.isEmpty(groupNames)){
+            groupNameList = Arrays.asList(groupNames.split(","));
+        }
+        if(!StringUtils.isEmpty(projectIds)){
+            projectIdList=Arrays.asList(projectIds.split(",")).stream().map(i->Integer.valueOf(i)).collect(Collectors.toList());
+        }
+        if(!StringUtils.isEmpty(deptIdStr)){
+            deptIdList=Arrays.asList(deptIdStr.split(",")).stream().map(i->Integer.valueOf(i)).collect(Collectors.toList());
+        }
+        boolean viewAll = sysFunctionService.hasPriviledge(user.getRoleId(), "全部分组耗用进度表");
+        boolean incharger = sysFunctionService.hasPriviledge(user.getRoleId(), "负责部门分组耗用进度表");
+        List<Department> allDeptList = departmentMapper.selectList(new LambdaQueryWrapper<Department>().eq(Department::getCompanyId, companyId));
+        List<Map<String,Object>> resultList;
+        Integer total;
+        //是否具有查看全部数据的权限
+        //针对依斯呗 指定部门
+        List<Integer> regularDeptIds=new ArrayList<>();
+        if(user.getCompanyId()==3092){
+            List<String> nameString=new ArrayList<>();
+            nameString.add("4");
+            nameString.add("46");
+            nameString.add("45");
+            List<Department> departmentList = departmentMapper.selectList(new LambdaQueryWrapper<Department>().eq(Department::getCompanyId, user.getCompanyId()).in(Department::getDepartmentName, nameString));
+            List<Integer> theCollect = departmentList.stream().map(dm -> dm.getDepartmentId()).distinct().collect(Collectors.toList());
+            theCollect.add(-1);
+            for (Integer integer : theCollect) {
+                List<Integer> branchDepartment = getBranchDepartment(integer, allDeptList);
+                regularDeptIds.addAll(branchDepartment);
+            }
+        }
+        if(!viewAll){
+            if(!incharger){
+                //只能查看本人的数据
+                resultList=projectMapper.groupExpendProcessListForUser(user.getId(),companyId,startDate,endDate,null,null,projectIdList,groupNameList,deptIdList,start,size);
+                total=projectMapper.groupExpendProcessListForUserCount(user.getId(),companyId,startDate,endDate,null,null,projectIdList,groupNameList,deptIdList);
+            }else {
+                List<Department> departmentList = departmentMapper.selectList(new LambdaQueryWrapper<Department>().select(Department::getDepartmentId).eq(Department::getManagerId, user.getId()));
+                List<DepartmentOtherManager> departmentOtherManagerList = departmentOtherManagerMapper.selectList(new QueryWrapper<DepartmentOtherManager>().eq("other_manager_id", user.getId()));
+                List<Integer> deptIds=new ArrayList<>();
+                List<Integer> theCollect = departmentList.stream().map(dm -> dm.getDepartmentId()).distinct().collect(Collectors.toList());
+                theCollect.add(-1);
+                List<Integer> otherCollect = departmentOtherManagerList.stream().map(dom -> dom.getDepartmentId()).distinct().collect(Collectors.toList());
+                otherCollect.add(-1);
+                theCollect.addAll(otherCollect);
+                for (Integer integer : theCollect) {
+                    List<Integer> branchDepartment = getBranchDepartment(integer, allDeptList);
+                    deptIds.addAll(branchDepartment);
+                }
+                resultList=projectMapper.groupExpendProcessListForUser(null,companyId,startDate,endDate,deptIdList,regularDeptIds,projectIdList,groupNameList,deptIdList,start,size);
+                total=projectMapper.groupExpendProcessListForUserCount(null,companyId,startDate,endDate,deptIdList,regularDeptIds,projectIdList,groupNameList,deptIdList);
+            }
+        }else {
+            resultList=projectMapper.groupExpendProcessListForUser(null,companyId,startDate,endDate,null,regularDeptIds,projectIdList,groupNameList,deptIdList,start,size);
+            total=projectMapper.groupExpendProcessListForUserCount(null,companyId,startDate,endDate,null,regularDeptIds,projectIdList,groupNameList,deptIdList);
+        }
+        resultList.forEach(r->{
+            Optional<Department> department = departments.stream().filter(d -> d.getDepartmentId().equals(Integer.valueOf(String.valueOf(r.get("departmentId"))))).findFirst();
+            r.put("departmentName",departmentService.getSupDepartment(department.get(),departments));
+        });
+        Map<String,Object> map=new HashMap<>();
+        resultList=resultList.stream().filter(r->Double.valueOf(String.valueOf(r.get("totalWorkTime")))>0).collect(Collectors.toList());
+        map.put("record",resultList);
+        map.put("total",total);
+        msg.setData(map);
+        return msg;
+    }
+
+    @Override
+    public HttpRespMsg groupExpendProcessListForProject(String startDate, String endDate, String projectIds, String groupNames, String deptIdStr,Integer pageIndex,Integer pageSize) {
+        HttpRespMsg msg=new HttpRespMsg();
+        User user = userMapper.selectById(request.getHeader("token"));
+        List<Department> departments = departmentMapper.selectList(new LambdaQueryWrapper<Department>().eq(Department::getCompanyId, user.getCompanyId()));
+        NumberFormat percentFormat = NumberFormat.getPercentInstance();
+        percentFormat.setMaximumFractionDigits(2);
+        Integer start=null;
+        Integer size=null;
+        if(pageIndex!=null&&pageSize!=null){
+            size=pageSize;
+            start=(pageIndex-1)*size;
+        }
+        Integer companyId = user.getCompanyId();
+        List<String> groupNameList=new ArrayList<>();
+        List<Integer> projectIdList=new ArrayList<>();
+        List<Integer> deptIdList=new ArrayList<>();
+        if(!StringUtils.isEmpty(groupNames)){
+            groupNameList = Arrays.asList(groupNames.split(","));
+        }
+        if(!StringUtils.isEmpty(projectIds)){
+            projectIdList=Arrays.asList(projectIds.split(",")).stream().map(i->Integer.valueOf(i)).collect(Collectors.toList());
+        }
+        if(!StringUtils.isEmpty(deptIdStr)){
+            deptIdList=Arrays.asList(deptIdStr.split(",")).stream().map(i->Integer.valueOf(i)).collect(Collectors.toList());
+        }
+        boolean viewAll = sysFunctionService.hasPriviledge(user.getRoleId(), "全部分组耗用进度表");
+        boolean incharger = sysFunctionService.hasPriviledge(user.getRoleId(), "负责部门分组耗用进度表");
+        List<Department> allDeptList = departmentMapper.selectList(new LambdaQueryWrapper<Department>().eq(Department::getCompanyId, companyId));
+        List<Map<String,Object>> resultList;
+        Integer total;
+        //是否具有查看全部数据的权限
+        //针对依斯呗 指定部门
+        List<Integer> regularDeptIds=new ArrayList<>();
+        if(user.getCompanyId()==3092){
+            List<String> nameString=new ArrayList<>();
+            nameString.add("4");
+            nameString.add("46");
+            nameString.add("45");
+            List<Department> departmentList = departmentMapper.selectList(new LambdaQueryWrapper<Department>().eq(Department::getCompanyId, user.getCompanyId()).in(Department::getDepartmentName, nameString));
+            List<Integer> theCollect = departmentList.stream().map(dm -> dm.getDepartmentId()).distinct().collect(Collectors.toList());
+            theCollect.add(-1);
+            for (Integer integer : theCollect) {
+                List<Integer> branchDepartment = getBranchDepartment(integer, allDeptList);
+                regularDeptIds.addAll(branchDepartment);
+            }
+        }
+        if(!viewAll){
+            if(!incharger){
+                //只能查看本人的数据
+                resultList=projectMapper.groupExpendProcessListForProject(user.getId(),companyId,startDate,endDate,null,null,projectIdList,groupNameList,deptIdList,start,size);
+                total=projectMapper.groupExpendProcessListForProjectCount(user.getId(),companyId,startDate,endDate,null,null,projectIdList,groupNameList,deptIdList);
+            }else {
+                List<Department> departmentList = departmentMapper.selectList(new LambdaQueryWrapper<Department>().select(Department::getDepartmentId).eq(Department::getManagerId, user.getId()));
+                List<DepartmentOtherManager> departmentOtherManagerList = departmentOtherManagerMapper.selectList(new QueryWrapper<DepartmentOtherManager>().eq("other_manager_id", user.getId()));
+                List<Integer> deptIds=new ArrayList<>();
+                List<Integer> theCollect = departmentList.stream().map(dm -> dm.getDepartmentId()).distinct().collect(Collectors.toList());
+                theCollect.add(-1);
+                List<Integer> otherCollect = departmentOtherManagerList.stream().map(dom -> dom.getDepartmentId()).distinct().collect(Collectors.toList());
+                otherCollect.add(-1);
+                theCollect.addAll(otherCollect);
+                for (Integer integer : theCollect) {
+                    List<Integer> branchDepartment = getBranchDepartment(integer, allDeptList);
+                    deptIds.addAll(branchDepartment);
+                }
+                resultList=projectMapper.groupExpendProcessListForProject(null,companyId,startDate,endDate,deptIdList,regularDeptIds,projectIdList,groupNameList,deptIdList,start,size);
+                total=projectMapper.groupExpendProcessListForProjectCount(null,companyId,startDate,endDate,deptIdList,regularDeptIds,projectIdList,groupNameList,deptIdList);
+            }
+        }else {
+            resultList=projectMapper.groupExpendProcessListForProject(null,companyId,startDate,endDate,null,regularDeptIds,projectIdList,groupNameList,deptIdList,start,size);
+            total=projectMapper.groupExpendProcessListForProjectCount(null,companyId,startDate,endDate,null,regularDeptIds,projectIdList,groupNameList,deptIdList);
+        }
+        //计算占比
+        double workTime = resultList.stream().mapToDouble(r -> Double.valueOf(String.valueOf(r.get("workTime")))).sum();
+        resultList.forEach(r->{
+            BigDecimal time = new BigDecimal(String.valueOf(r.get("workTime")));
+            time=time.divide(new BigDecimal(workTime),4,RoundingMode.HALF_UP);
+            time=time.multiply(new BigDecimal(100));
+//            String format = percentFormat.format(time.doubleValue());
+            r.put("percent",time.doubleValue()+"%");
+        });
+        Map<String,Object> map=new HashMap<>();
+        map.put("record",resultList);
+        map.put("total",total);
+        msg.setData(map);
+        return msg;
+    }
+
+    @Override
+    public HttpRespMsg exportGroupExpendProcessListForUser(String startDate, String endDate, String projectIds, String groupNames,String titleStr, String deptIdStr) {
+        User user = userMapper.selectById(request.getHeader("token"));
+        WxCorpInfo wxCorpInfo = wxCorpInfoMapper.selectOne(new LambdaQueryWrapper<WxCorpInfo>().eq(WxCorpInfo::getCompanyId, user.getCompanyId()));
+        List<List<String>> dataList=new ArrayList<>();
+        List<String> titleList=new ArrayList<>();
+        titleList.add("所属部门");
+        titleList.add("工号");
+        titleList.add("员工");
+        if(!StringUtils.isEmpty(titleStr)){
+            List<String> strings = Arrays.asList(titleStr.split(","));
+            titleList.addAll(strings);
+        }
+        dataList.add(titleList);
+        HttpRespMsg msg = groupExpendProcessListForUser(startDate, endDate, projectIds, groupNames, deptIdStr, null, null);
+        Map<String, Object> data = (Map<String, Object>)  msg.data;
+        List<Map<String, Object>> mapList = (List<Map<String, Object>>) data.get("record");
+        for (Map<String, Object> map : mapList) {
+            List<String> item=new ArrayList<>();
+            if(wxCorpInfo!=null&&wxCorpInfo.getSaasSyncContact()==1){
+                item.add("$departmentName="+String.valueOf(map.get("departmentName"))+"$");
+            }else {
+                item.add(String.valueOf(map.get("departmentName")));
+            }
+            item.add(String.valueOf(map.get("jobNumber")));
+            if(wxCorpInfo!=null&&wxCorpInfo.getSaasSyncContact()==1){
+                item.add("$userName="+String.valueOf(map.get("userName"))+"$");
+            }else {
+                item.add(String.valueOf(map.get("userName")));
+            }
+            for (String s : titleList) {
+                item.add(String.valueOf(map.get(s)));
+            }
+            dataList.add(item);
+        }
+        try {
+            return excelExportService.exportGeneralExcelByTitleAndList(wxCorpInfo,null,"人员分组耗用表",dataList,path);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return msg;
+    }
 }

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

@@ -662,7 +662,7 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                         Optional<TaskGroup> tgoup = taskGroups.stream().filter(tg->tg.getId().equals(r.getGroupId())).findFirst();
                         if (tgoup.isPresent()) {
                             TaskGroup curGroup = tgoup.get();
-                            if (curGroup.getInchargerId() != null) {
+                            if (!StringUtils.isEmpty(curGroup.getInchargerId())) {
                                 User user = userMapper.selectById(curGroup.getInchargerId());
                                 HashMap map = new HashMap();
                                 map.put("auditorId", user.getId());
@@ -3045,17 +3045,14 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
         if (list.size() > 0) {
             //存在查看权限的部门
             //获取公司全部人员; 按照人员状态,如果是已经离职的,当前日期在离职日期以后的,不需要显示该人员
-
             QueryWrapper<User> queryWrapper = new QueryWrapper<User>().eq("company_id", companyId);
             queryWrapper.and(wrapper->wrapper.eq("is_active", 1).eq("report_status",0)
                     .or(wrapper2->wrapper2.eq("is_active", 0).gt("inactive_date", date)));
             List<User> userList = userMapper.selectList(queryWrapper);
             long t3 = System.currentTimeMillis();
-            System.out.println("获取人员列表耗时:" + (t3 - t2) + "ms");
             List<LeaveSheet> leaveSheetList = leaveSheetMapper.selectList(
                     new QueryWrapper<LeaveSheet>().select("id, owner_id, start_date, end_date, leave_type, time_type, time_days, time_hours").eq("company_id", companyId));
             long t4 = System.currentTimeMillis();
-            System.out.println("获取人员请假列表耗时:" + (t4 - t3) + "ms");
             LocalDate localDate = LocalDate.parse(date, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
             List<HashMap> userMapList = new ArrayList<>();
             LocalDate curDate = LocalDate.parse(date, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
@@ -3063,7 +3060,6 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
             //获取当日已填写的人员报告
             List<Map<String, Object>> reportNameByDate = reportMapper.getReportNameByDate(date, companyId, null);
             long t5 = System.currentTimeMillis();
-            System.out.println("获取当日已填写的人员报告耗时:" + (t5 - t4) + "ms");
             Company company = companyMapper.selectById(companyId);
             TimeType timeType = timeTypeMapper.selectById(companyId);
             //如果没有开通OA模块,有开通企业微信同步考勤,从user_corpwx_time表中获取请假时长

+ 20 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/UserGroupServiceImpl.java

@@ -0,0 +1,20 @@
+package com.management.platform.service.impl;
+
+import com.management.platform.entity.UserGroup;
+import com.management.platform.mapper.UserGroupMapper;
+import com.management.platform.service.UserGroupService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ *  服务实现类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2024-07-29
+ */
+@Service
+public class UserGroupServiceImpl extends ServiceImpl<UserGroupMapper, UserGroup> implements UserGroupService {
+
+}

+ 10 - 3
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/UserServiceImpl.java

@@ -113,6 +113,8 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
     @Autowired
     private RestTemplate restTemplate;
     @Resource
+    private UserWorkbenchService userWorkbenchService;
+    @Resource
     ExpenseMainTypeService expenseMainTypeService;
     @Resource
     private SysRoleModuleMapper sysRoleModuleMapper;
@@ -726,6 +728,9 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
         } else {
             user.setFunctionList(new ArrayList<>());
         }
+
+        //设置用户的工作台模块
+        user.setUserWorkbench(userWorkbenchService.getMyWorkbench(user.getId()));
     }
 
     private boolean judgeIsLeader(String userId) {
@@ -1327,7 +1332,7 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
     @Override
     public HttpRespMsg insertUser(String targetId, String name, String phone, Integer onlyAuditOnce, Integer roleId, Double monthCost, Double cost,
                                   Integer departmentId, Integer salaryType, String costApplyDate, String position, String certJson, HttpServletRequest request,String inductionDate,
-                                  String superiorId,   String plate1,String plate2,String plate3,String plate4,String plate5, String jobNumber, String inactiveDate,String reportDeptIds) {
+                                  String superiorId,   String plate1,String plate2,String plate3,String plate4,String plate5, String jobNumber, String inactiveDate,String reportDeptIds,Integer groupId) {
         HttpRespMsg httpRespMsg = new HttpRespMsg();
         DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
         try {
@@ -1384,7 +1389,8 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
                                 .setPlate3(plate3)
                                 .setPlate4(plate4)
                                 .setPlate5(plate5)
-                                .setJobNumber(jobNumber);
+                                .setJobNumber(jobNumber)
+                                .setUserGroupId(groupId);
                         if(inductionDate!=null&&inductionDate!=""){
                             user.setInductionDate(LocalDate.parse(inductionDate,dtf));
                         }
@@ -1477,7 +1483,8 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
                         .setPlate3(plate3)
                         .setPlate4(plate4)
                         .setPlate5(plate5)
-                        .setJobNumber(jobNumber));
+                        .setJobNumber(jobNumber)
+                        .setUserGroupId(groupId));
                 if (oldSuperiorId != null && superiorId == null) {
                     //清空直属审核人
                     userMapper.setSuperiorNull(oldUser.getId());

+ 73 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/UserWorkbenchServiceImpl.java

@@ -0,0 +1,73 @@
+package com.management.platform.service.impl;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.management.platform.entity.UserWorkbench;
+import com.management.platform.mapper.UserWorkbenchMapper;
+import com.management.platform.service.UserWorkbenchService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.management.platform.util.HttpRespMsg;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+
+/**
+ * <p>
+ *  服务实现类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2024-08-06
+ */
+@Service
+public class UserWorkbenchServiceImpl extends ServiceImpl<UserWorkbenchMapper, UserWorkbench> implements UserWorkbenchService {
+
+    @Resource
+    private UserWorkbenchMapper userWorkbenchMapper;
+
+    public final WorkBenchItem[] WORKBENCH_MODULES = new WorkBenchItem[]{
+            new WorkBenchItem(1, "我的工时日历", "basic"),
+            new WorkBenchItem(2, "我的工时统计", "basic"),
+            new WorkBenchItem(3, "团队项目工时统计", "basic"),//分为全部项目查看权限和负责项目查看权限
+            new WorkBenchItem(4, "工时状态统计", "basic"),
+            new WorkBenchItem(5, "我的近期执行任务", "project"),
+            new WorkBenchItem(6, "项目/非项目工时占比", "basic"),
+            new WorkBenchItem(7, "团队成员工时统计", "basic"),
+            new WorkBenchItem(9, "近期任务工时", "basic"),
+            new WorkBenchItem(10, "项目工时走势图", "basic")
+    };
+
+    class WorkBenchItem {
+        int id;
+        String name;
+        String module;
+
+        public WorkBenchItem(int id, String name, String module) {
+            this.id = id;
+            this.name = name;
+            this.module = module;
+        }
+    }
+    @Override
+    public JSONArray getMyWorkbench(String userId) {
+        UserWorkbench userWorkbench = userWorkbenchMapper.selectById(userId);
+        JSONArray array = new JSONArray();
+        if (userWorkbench == null) {
+            //返回默认的前四个模块
+            for (int i = 0; i < WORKBENCH_MODULES.length; i++) {
+                if (i < 4) {
+                    JSONObject object = new JSONObject();
+                    object.put("id", WORKBENCH_MODULES[i].id);
+                    object.put("position", i/2+","+(i)%2);
+                    object.put("size", 1);
+                    array.add(object);
+                }
+            }
+        } else {
+            String workbench = userWorkbench.getTableList();
+            array = JSONArray.parseArray(workbench);
+        }
+        return array;
+    }
+}

+ 1 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/util/MessageUtils.java

@@ -21,7 +21,7 @@ public class MessageUtils {
     public static String message(String code, Object... args) {
         MessageSource messageSource = SpringUtils.getBean(MessageSource.class);
         Locale locale = LocaleContextHolder.getLocale();
-        System.out.println("本地为:" +locale.getDisplayName()+", code="+code);
+//        System.out.println("本地为:" +locale.getDisplayName()+", code="+code);
         return messageSource.getMessage(code, args, locale);
     }
 

+ 4 - 2
fhKeeper/formulahousekeeper/management-platform/src/main/resources/application.yml

@@ -3,7 +3,7 @@ server:
   tomcat:
     uri-encoding: utf-8
     max-http-form-post-size: -1
-    connection-timeout: 18000000s
+    connection-timeout: 18000000
 spring:
   servlet:
     multipart:
@@ -22,7 +22,9 @@ spring:
     hikari:
       maximum-pool-size: 60
       minimum-idle: 10
-      max-lifetime: 180000
+      # 空闲连接超时时间,3分钟
+      idle-timeout: 180000
+      max-lifetime: 1800000
       # 数据库连接超时时间,默认30秒,即30000
       connection-timeout: 60000
       connection-test-query: SELECT 1

+ 230 - 5
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/ProjectMapper.xml

@@ -1907,10 +1907,11 @@
         SELECT p.project_name AS projectName,p.id AS projectId,tg.id AS groupId,d.department_name,d.department_id AS deptId,d.corpwx_deptid AS corpwxDeptId,tg.name AS groupName,
         IFNULL(r.realHour,0) AS realHour,IFNULL(r.realCost,0) AS realCost,IFNULL(r.normalHour,0) as normalHour,IFNULL(r.overHour,0) as overHour,
         IFNULL(tg.man_day*8,0) AS planHour,IFNULL((SELECT SUM(change_man_day*8) FROM `group_budget_review` WHERE group_id=tg.`id` AND `status`=1),0) AS afterSetPlanHour
-        FROM task_executor te
-        LEFT JOIN task t ON t.id=te.task_id
-        LEFT JOIN user u ON te.executor_id=u.id
-        LEFT JOIN task_group tg ON tg.id=t.group_id
+        FROM task_group tg
+        LEFT JOIN task t ON tg.id = t.group_id
+        LEFT JOIN task_executor te ON t.id = te.task_id
+        LEFT JOIN user u
+        ON te.executor_id = u.id
         LEFT JOIN project p ON p.id=tg.project_id
         LEFT JOIN department d ON d.department_id=u.department_id
         LEFT JOIN (
@@ -1920,7 +1921,7 @@
          AND create_date BETWEEN #{startDate} AND #{endDate}
         </if>
         AND project_id IS NOT NULL AND company_id=#{companyId} GROUP BY group_id,dept_id) r ON r.group_id=tg.`id` and r.dept_id=u.department_id
-        WHERE u.company_id=#{companyId}
+        WHERE p.company_id=#{companyId}
         AND tg.name IN ('生产部电气','生产部车间','工程部现场安装施工','工程部配合调试','研发部工艺设计','研发部结构设计','研发部BIM设计','研发部电气设计','研发部工艺调试验收','研发部电气调试验收')
         <if test="userId!=null and userId!=''">
             and t.executor_id=#{userId}
@@ -1969,6 +1970,230 @@
          GROUP BY t.groupName
     </select>
 
+    <select id="groupExpendProcessListForUser" resultType="java.util.Map">
+        SELECT departmentId, departmentName,jobNumber,userName,
+        SUM(CASE WHEN groupName='方案设计' THEN workTime ELSE 0 END) AS '方案设计' ,
+        SUM(CASE WHEN groupName='研发部' THEN workTime ELSE 0 END) AS '研发部' ,
+        SUM(CASE WHEN groupName='研发部工艺调试' THEN workTime ELSE 0 END) AS '研发部工艺调试',
+        SUM(CASE WHEN groupName='研发部工艺调试验收' THEN workTime ELSE 0 END) AS '研发部工艺调试验收' ,
+        SUM(CASE WHEN groupName='研发部工艺设计' THEN workTime ELSE 0 END) AS '研发部工艺设计' ,
+        SUM(CASE WHEN groupName='研发部结构设计' THEN workTime ELSE 0 END) AS '研发部结构设计' ,
+        SUM(CASE WHEN groupName='研发部BIM设计' THEN workTime ELSE 0 END) AS '研发部BIM设计' ,
+        SUM(CASE WHEN groupName='研发部电气调试验收' THEN workTime ELSE 0 END) AS '研发部电气调试验收' ,
+        SUM(CASE WHEN groupName='研发部电气设计' THEN workTime ELSE 0 END) AS '研发部电气设计' ,
+        SUM(CASE WHEN groupName='研发部售后' THEN workTime ELSE 0 END) AS '研发部售后' ,
+        SUM(CASE WHEN groupName='工程部配合运维' THEN workTime ELSE 0 END) AS '工程部配合运维' ,
+        SUM(CASE WHEN groupName='研发部运维' THEN workTime ELSE 0 END) AS '研发部运维' ,
+        SUM(CASE WHEN groupName='生产部' THEN workTime ELSE 0 END) AS '生产部' ,
+        SUM(CASE WHEN groupName='生产部车间' THEN workTime ELSE 0 END) AS '生产部车间' ,
+        SUM(CASE WHEN groupName='生产部电气' THEN workTime ELSE 0 END) AS '生产部电气' ,
+        SUM(CASE WHEN groupName='工程部配合调试' THEN workTime ELSE 0 END) AS '工程部配合调试' ,
+        SUM(CASE WHEN groupName='工程部' THEN workTime ELSE 0 END) AS '工程部' ,
+        SUM(CASE WHEN groupName='工程部售后' THEN workTime ELSE 0 END) AS '工程部售后' ,
+        SUM(CASE WHEN groupName='工程部现场安装施工' THEN workTime ELSE 0 END) AS '工程部现场安装施工',
+        IFNULL(SUM(workTime),0) AS totalWorkTime
+        FROM (
+            SELECT  d.`department_id` AS departmentId,d.`department_name` AS departmentName,u.`job_number` AS jobNumber,u.`name` AS userName ,tg.name AS groupName,rr.realHour AS workTime,u.id
+            FROM task_executor te
+            LEFT JOIN task t ON t.id=te.task_id
+            LEFT JOIN `user` u ON te.executor_id=u.id
+            LEFT JOIN task_group tg ON tg.id=t.group_id
+            LEFT JOIN project p ON p.id=tg.project_id
+            LEFT JOIN department d ON d.department_id=u.department_id
+            LEFT JOIN (
+            SELECT r.creator_id AS creatorId,SUM(r.working_time) AS realHour,tg.id AS groupId
+            FROM report r
+            LEFT JOIN task_group tg ON r.group_id=tg.`id`
+            WHERE r.state=1 AND r.project_id IS NOT NULL
+            <if test="startDate!=null and startDate!='' and endDate!=null and endDate!=''">
+                AND r.create_date  BETWEEN #{startDate} AND #{endDate}
+            </if>  AND r.company_id=#{companyId}
+            GROUP BY r.creator_id,tg.id ) rr ON rr.groupId=tg.`id` AND rr.creatorId=u.id
+            WHERE u.company_id=#{companyId}
+            <if test="listThird!=null and listThird.size()>0">
+                AND tg.project_id in
+                <foreach collection="listThird" separator="," open="(" close=")" item="item">
+                    #{item}
+                </foreach>
+            </if>
+            AND tg.name IN ('方案设计','研发部','生产部','工程部','生产部电气','生产部车间','工程部现场安装施工','工程部配合调试','研发部工艺设计','研发部结构设计','研发部BIM设计','研发部电气设计','研发部工艺调试验收','研发部电气调试验收')
+            <if test="listFour!=null and listFour.size()>0">
+                and tg.name in
+                <foreach collection="listFour" close=")" open="(" separator="," item="item">
+                    #{item}
+                </foreach>
+            </if>
+            GROUP BY u.`id`,tg.id
+            ) AS t
+            <where>
+            <if test="listFive!=null and listFive.size()>0">
+                t.departmentId in
+                <foreach collection="listFive" close=")" open="(" separator="," item="item">
+                    #{item}
+                </foreach>
+            </if>
+            </where>
+            GROUP BY t.id
+            <if test="start!=null and size!=null">
+                limit #{start},#{size}
+            </if>
+    </select>
+
+    <select id="groupExpendProcessListForUserCount" resultType="java.lang.Integer">
+        select count(1) from (
+        SELECT departmentId,departmentName,jobNumber,userName,IFNULL(SUM(workTime),0) AS totalWorkTime
+        FROM (
+            SELECT d.`department_id` AS departmentId,d.`department_name` AS departmentName,u.`job_number` AS jobNumber,u.`name` AS userName ,tg.name AS groupName,rr.realHour AS workTime,u.id
+            FROM task_executor te
+            LEFT JOIN task t ON t.id=te.task_id
+            LEFT JOIN `user` u ON te.executor_id=u.id
+            LEFT JOIN task_group tg ON tg.id=t.group_id
+            LEFT JOIN project p ON p.id=tg.project_id
+            LEFT JOIN department d ON d.department_id=u.department_id
+            LEFT JOIN (
+            SELECT r.creator_id AS creatorId,SUM(r.working_time) AS realHour,tg.id AS groupId
+            FROM report r
+            LEFT JOIN task_group tg ON r.group_id=tg.`id`
+            WHERE r.state=1 AND r.project_id IS NOT NULL
+            <if test="startDate!=null and startDate!='' and endDate!=null and endDate!=''">
+                AND r.create_date  BETWEEN #{startDate} AND #{endDate}
+            </if>  AND r.company_id=#{companyId}
+            GROUP BY r.creator_id,tg.id ) rr ON rr.groupId=tg.`id` AND rr.creatorId=u.id
+            WHERE u.company_id=#{companyId}
+            <if test="listThird!=null and listThird.size()>0">
+                AND tg.project_id in
+                <foreach collection="listThird" separator="," open="(" close=")" item="item">
+                    #{item}
+                </foreach>
+            </if>
+            AND tg.name IN ('方案设计','研发部','生产部','工程部','生产部电气','生产部车间','工程部现场安装施工','工程部配合调试','研发部工艺设计','研发部结构设计','研发部BIM设计','研发部电气设计','研发部工艺调试验收','研发部电气调试验收')
+            <if test="listFour!=null and listFour.size()>0">
+                and tg.name in
+                <foreach collection="listFour" close=")" open="(" separator="," item="item">
+                    #{item}
+                </foreach>
+            </if>
+            GROUP BY u.`id`,tg.id
+            ) AS t
+            <where>
+                <if test="listFive!=null and listFive.size()>0">
+                    t.departmentId in
+                    <foreach collection="listFive" close=")" open="(" separator="," item="item">
+                        #{item}
+                    </foreach>
+                </if>
+            </where>
+            GROUP BY t.id
+        ) as total
+    </select>
+
+    <select id="groupExpendProcessListForProject" resultType="java.util.Map">
+        SELECT projectName,projectId,projectCode,SUM(realHour) AS workTime  FROM (
+        SELECT p.project_name AS projectName,p.project_code as projectCode,p.id AS projectId,tg.id AS groupId,tg.name AS groupName,
+        IFNULL(r.realHour,0) AS realHour
+        FROM task_executor te
+        LEFT JOIN task t ON t.id=te.task_id
+        LEFT JOIN `user` u ON te.executor_id=u.id
+        LEFT JOIN task_group tg ON tg.id=t.group_id
+        LEFT JOIN project p ON p.id=tg.project_id
+        LEFT JOIN department d ON d.department_id=u.department_id
+        LEFT JOIN (
+        SELECT SUM(working_time) AS realHour,group_id,dept_id
+        FROM report  WHERE state=1
+        <if test="startDate!=null and startDate!='' and endDate!=null and endDate!=''">
+            AND create_date  BETWEEN #{startDate} AND #{endDate}
+        </if>
+        AND project_id IS NOT NULL AND company_id=#{companyId} GROUP BY group_id) r ON r.group_id=tg.`id`
+        WHERE u.company_id=#{companyId}
+        <if test="listThird!=null and listThird.size()>0">
+            AND tg.project_id in
+            <foreach collection="listThird" separator="," open="(" close=")" item="item">
+                #{item}
+            </foreach>
+        </if>
+        AND tg.name IN ('方案设计','研发部','生产部','工程部','生产部电气','生产部车间','工程部现场安装施工','工程部配合调试','研发部工艺设计','研发部结构设计','研发部BIM设计','研发部电气设计','研发部工艺调试验收','研发部电气调试验收')
+        <if test="listFour!=null and listFour.size()>0">
+            and tg.name in
+            <foreach collection="listFour" close=")" open="(" separator="," item="item">
+                #{item}
+            </foreach>
+        </if>
+        <if test="listFive!=null and listFive.size()>0">
+            and d.department_id in
+            <foreach collection="listFive" close=")" open="(" separator="," item="item">
+                #{item}
+            </foreach>
+        </if>
+        GROUP BY p.id,tg.id ORDER BY p.id,d.department_id) AS f
+        <where>
+            realHour>0
+            <if test="listThird!=null and listThird.size()>0">
+                and
+                projectId in
+                <foreach collection="listThird" separator="," open="(" close=")" item="item">
+                    #{item}
+                </foreach>
+            </if>
+        </where>
+        GROUP BY  projectId
+        <if test="start!=null and size!=null">
+            limit #{start},#{size}
+        </if>
+    </select>
+
+    <select id="groupExpendProcessListForProjectCount" resultType="java.lang.Integer">
+        select count(1) from (
+            SELECT projectName,projectId,projectCode,SUM(realHour) AS workTime  FROM (
+            SELECT p.project_name AS projectName,p.project_code as projectCode,p.id AS projectId,tg.id AS groupId,tg.name AS groupName,
+            IFNULL(r.realHour,0) AS realHour
+            FROM task_executor te
+            LEFT JOIN task t ON t.id=te.task_id
+            LEFT JOIN `user` u ON te.executor_id=u.id
+            LEFT JOIN task_group tg ON tg.id=t.group_id
+            LEFT JOIN project p ON p.id=tg.project_id
+            LEFT JOIN department d ON d.department_id=u.department_id
+            LEFT JOIN (
+            SELECT SUM(working_time) AS realHour,group_id,dept_id
+            FROM report  WHERE state=1
+            <if test="startDate!=null and startDate!='' and endDate!=null and endDate!=''">
+                AND create_date  BETWEEN #{startDate} AND #{endDate}
+            </if>
+            AND project_id IS NOT NULL AND company_id=#{companyId} GROUP BY group_id) r ON r.group_id=tg.`id`
+            WHERE u.company_id=#{companyId}
+            <if test="listThird!=null and listThird.size()>0">
+                AND tg.project_id in
+                <foreach collection="listThird" separator="," open="(" close=")" item="item">
+                    #{item}
+                </foreach>
+            </if>
+            AND tg.name IN ('方案设计','研发部','生产部','工程部','生产部电气','生产部车间','工程部现场安装施工','工程部配合调试','研发部工艺设计','研发部结构设计','研发部BIM设计','研发部电气设计','研发部工艺调试验收','研发部电气调试验收')
+            <if test="listFour!=null and listFour.size()>0">
+                and tg.name in
+                <foreach collection="listFour" close=")" open="(" separator="," item="item">
+                    #{item}
+                </foreach>
+            </if>
+            <if test="listFive!=null and listFive.size()>0">
+                and d.department_id in
+                <foreach collection="listFive" close=")" open="(" separator="," item="item">
+                    #{item}
+                </foreach>
+            </if>
+            GROUP BY p.id,tg.id ORDER BY p.id,d.department_id) AS f
+            <where>
+                realHour>0
+                <if test="listThird!=null and listThird.size()>0">
+                    and
+                    projectId in
+                    <foreach collection="listThird" separator="," open="(" close=")" item="item">
+                        #{item}
+                    </foreach>
+                </if>
+            </where>
+            GROUP BY  projectId
+        ) as total
+    </select>
+
     <select id="projectExpendProcessList" resultType="java.util.Map">
         select p.id AS projectId,p.project_name as projectName,DATE_FORMAT(p.`plan_start_date`,'%Y-%m-%d') AS planStartDate,DATE_FORMAT(p.`plan_end_date`,'%Y-%m-%d') AS planEndDate,pc.name as categoryName,p.project_code as projectCode,IFNULL(SUM(te.plan_hours),0) as planHour,
         IFNULL((select SUM(working_time) from report where project_id=p.id and create_date BETWEEN #{startDate} AND #{endDate} and state=1),0) as realHour, IFNULL((select SUM(cost) from report where project_id=p.id and create_date BETWEEN #{startDate} AND #{endDate} and state=1),0) as realCost,

+ 18 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/UserGroupMapper.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.management.platform.mapper.UserGroupMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.management.platform.entity.UserGroup">
+        <id column="id" property="id" />
+        <result column="company_id" property="companyId" />
+        <result column="group_name" property="groupName" />
+        <result column="no_project_percent" property="noProjectPercent" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, company_id, group_name, no_project_percent
+    </sql>
+
+</mapper>

File diff ditekan karena terlalu besar
+ 4 - 2
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/UserMapper.xml


+ 16 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/UserWorkbenchMapper.xml

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.management.platform.mapper.UserWorkbenchMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.management.platform.entity.UserWorkbench">
+        <id column="user_id" property="userId" />
+        <result column="table_list" property="tableList" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        user_id, table_list
+    </sql>
+
+</mapper>

TEMPAT SAMPAH
fhKeeper/formulahousekeeper/management-platform/费用报销导入模板.xlsx


+ 17 - 10
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/controller/WxCorpInfoController.java

@@ -12,6 +12,7 @@ import com.management.platform.util.DateTimeUtil;
 import com.management.platform.util.HttpRespMsg;
 import org.springframework.http.*;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.StringUtils;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 import org.springframework.web.client.RestTemplate;
@@ -250,6 +251,10 @@ public class WxCorpInfoController {
                 JSONObject apply_data = info.getJSONObject("apply_data");
                 System.out.println("获取到的单据信息===========>"+apply_data);
                 JSONArray contents = apply_data.getJSONArray("contents");
+                int count = planService.count(new LambdaQueryWrapper<Plan>().eq(Plan::getTaskChangeNoticeNum, info.getString("sp_no")));
+                if(count>0){
+                    continue;
+                }
                 //生成 车间插单计划
                 Plan plan=new Plan();
                 plan.setCompanyId(7);
@@ -347,17 +352,14 @@ public class WxCorpInfoController {
                             plan.setEndDate(localDateFromUnix);
                         }
                     }
-                    if(title.getJSONObject(0).getString("text").equals("工作时长")){
+                    if(title.getJSONObject(0).getString("text").equals("结算总时长")){
                         if(control.equals("Number")){
-                            double new_number = value.getDoubleValue("new_number");
-                            workTime=new_number;
+                            double new_number = StringUtils.isEmpty(value.getString("new_number")) ?0.0:value.getDoubleValue("new_number");
+                            BigDecimal bigDecimal = new BigDecimal(new_number);
+                            workTime=bigDecimal.doubleValue();
                         }
                     }
-                    BigDecimal bigDecimal = new BigDecimal(plan.getPlanManNum()==null?0:plan.getPlanManNum());
-                    //工时以分钟为单位 *60
-                    bigDecimal=bigDecimal.multiply(new BigDecimal(workTime));
-                    bigDecimal=bigDecimal.multiply(new BigDecimal(60));
-                    plan.setPlanWorkHour(bigDecimal.doubleValue());
+                    plan.setPlanWorkHour(workTime*60);
                     if(title.getJSONObject(0).getString("text").equals("所属工位")){
                         if(control.equals("Contact")){
                             JSONArray departments = value.getJSONArray("departments");
@@ -389,7 +391,11 @@ public class WxCorpInfoController {
                             JSONObject formula = value.getJSONObject("formula");
                             if(!formula.getString("value").equals("")){
                                 double formulaDoubleValue = formula.getDoubleValue("value");
-                                plan.setMoneyOfJob(new BigDecimal(formulaDoubleValue));
+                                BigDecimal bigDecimal = new BigDecimal(formulaDoubleValue);
+                                if(workTime>0){
+                                    BigDecimal divide = bigDecimal.divide(new BigDecimal(workTime), 0, RoundingMode.HALF_UP);
+                                    plan.setMoneyOfJob(divide);
+                                }
                             }
                         }
                     }
@@ -411,9 +417,10 @@ public class WxCorpInfoController {
                         report.setCreatorId(user.get().getId());
                         report.setCreateTime(LocalDateTime.now());
                         BigDecimal bigDecimal = new BigDecimal(workTime);
+                        bigDecimal=bigDecimal.divide(new BigDecimal(plan.getPlanManNum()==null?0:plan.getPlanManNum()),1,RoundingMode.HALF_UP);
+                        report.setWorkingTime(bigDecimal.doubleValue());
                         bigDecimal=bigDecimal.multiply(price);
                         report.setCost(bigDecimal);
-                        report.setWorkingTime(workTime);
                         report.setStatus(2);
                         report.setPlanId(plan.getId());
                         report.setCompanyId(7);

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

@@ -202,18 +202,20 @@ public class DepartmentServiceImpl extends ServiceImpl<DepartmentMapper, Departm
                             planList.forEach(p->{
                                 boolean match=true;
                                 Optional<Map<String, Object>> planId = planRealTimeProgressList.stream().filter(plan -> plan.get("planId").equals(p.getId())).findFirst();
-                                Map<String, Object> map = planId.get();
-                                BigDecimal planWorkTime = new BigDecimal(map.get("planWorkTime") == null ? 0 : Double.valueOf(String.valueOf(map.get("planWorkTime"))));
-                                BigDecimal nowWorkTime = new BigDecimal(map.get("nowWorkTime") == null ? 0 : Double.valueOf(String.valueOf(map.get("nowWorkTime"))));
-                                if(nowWorkTime.compareTo(BigDecimal.ZERO)!=0){
-                                    BigDecimal divide = nowWorkTime.divide(planWorkTime, 4, RoundingMode.HALF_UP);
-                                    if(divide.doubleValue()>1){
-                                        match=false;
+                                if(planId.isPresent()){
+                                    Map<String, Object> map = planId.get();
+                                    BigDecimal planWorkTime = new BigDecimal(map.get("planWorkTime") == null ? 0 : Double.valueOf(String.valueOf(map.get("planWorkTime"))));
+                                    BigDecimal nowWorkTime = new BigDecimal(map.get("nowWorkTime") == null ? 0 : Double.valueOf(String.valueOf(map.get("nowWorkTime"))));
+                                    if(nowWorkTime.compareTo(BigDecimal.ZERO)!=0){
+                                        BigDecimal divide = nowWorkTime.divide(planWorkTime, 4, RoundingMode.HALF_UP);
+                                        if(divide.doubleValue()>1){
+                                            match=false;
+                                        }
+                                    }
+                                    if(match){
+                                        p.setForemanName(manager.getName());
+                                        p.setForemanId(manager.getId());
                                     }
-                                }
-                                if(match){
-                                    p.setForemanName(manager.getName());
-                                    p.setForemanId(manager.getId());
                                 }
                             });
                             planService.updateBatchById(planList);

+ 17 - 6
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/impl/ReportServiceImpl.java

@@ -4300,7 +4300,7 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
             u.setTotalResult(String.format("%.2f",bigDecimal.doubleValue()) + "分钟 " + String.format("%.2f", cost) + "元");
             u.setTotalPlanResult(String.format("%.2f",planBigDecimal.doubleValue()) + "分钟 " + String.format("%.2f", planCost) + "元");
             u.setTotalSurplusResult(String.format("%.2f",surplusBigDecimal.doubleValue()) + "分钟 " + String.format("%.2f", surplusCost) + "元");
-            u.setTotalTempResult(String.format("%.2f",tempBigDecimal.doubleValue()) + "小时 " + String.format("%.2f", tempCost) + "元");
+            u.setTotalTempResult(String.format("%.2f",tempBigDecimal.doubleValue()) + "分钟 " + String.format("%.2f", tempCost) + "元");
         }
         resultMap.put("total",userIPage.getTotal());
         resultMap.put("records",userList);
@@ -5037,12 +5037,23 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
             item.add("");
 //            item.add(String.valueOf(map.get("progress"))+"%");
             item.add(String.valueOf(map.get("finishNum")));
-            item.add(String.valueOf(map.get("workingTime")));
-            item.add(String.valueOf(map.get("unitPrice")));
+            if(planType==0){
+                item.add(String.valueOf(map.get("workingTime")));
+                item.add(String.valueOf(map.get("unitPrice")));
+            }else {
+                item.add(String.valueOf(map.get("workingTime"))+" h");
+                item.add((map.get("unitPrice")==null?0:String.valueOf(map.get("unitPrice")))+" 元/h");
+            }
             String cost = String.valueOf(map.get("cost"));
-            BigDecimal finishNum = new BigDecimal(map.get("finishNum")==null?String.valueOf(0):String.valueOf(map.get("finishNum")));
-            finishNum=finishNum.multiply(new BigDecimal(map.get("unitPrice")==null?String.valueOf(0):String.valueOf(map.get("unitPrice")))).setScale(2,RoundingMode.HALF_UP);
-            item.add(String.valueOf(finishNum.doubleValue()));
+            if(planType==0){
+                BigDecimal finishNum = new BigDecimal(map.get("finishNum")==null?String.valueOf(0):String.valueOf(map.get("finishNum")));
+                finishNum=finishNum.multiply(new BigDecimal(map.get("unitPrice")==null?String.valueOf(0):String.valueOf(map.get("unitPrice")))).setScale(2,RoundingMode.HALF_UP);
+                item.add(String.valueOf(finishNum.doubleValue()));
+            }else {
+                BigDecimal workingTime = new BigDecimal(map.get("workingTime")==null?String.valueOf(0):String.valueOf(map.get("workingTime")));
+                workingTime=workingTime.multiply(new BigDecimal(map.get("unitPrice")==null?String.valueOf(0):String.valueOf(map.get("unitPrice")))).setScale(2,RoundingMode.HALF_UP);
+                item.add(String.valueOf(workingTime.doubleValue()));
+            }
 //            item.add(cost);
             item.add(String.valueOf(map.get("userName")));
             item.add(String.valueOf(map.get("createDate")));

+ 17 - 11
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/task/TimingTask.java

@@ -356,7 +356,7 @@ public class TimingTask {
             return;
         }
         DateTimeFormatter df=DateTimeFormatter.ofPattern("yyyy-MM-dd");
-        LocalDate start=LocalDate.now().minusDays(1);
+        LocalDate start=LocalDate.now().minusDays(7);
         LocalDate end=LocalDate.now();
         JSONArray jsonArrayFilter = new JSONArray();
         JSONObject filter1 = new JSONObject();
@@ -393,6 +393,10 @@ public class TimingTask {
                 System.out.println("获取到的单据信息===========>"+apply_data);
                 JSONArray contents = apply_data.getJSONArray("contents");
                 //生成 车间插单计划
+                int count = planService.count(new LambdaQueryWrapper<Plan>().eq(Plan::getTaskChangeNoticeNum, info.getString("sp_no")));
+                if(count>0){
+                    continue;
+                }
                 Plan plan=new Plan();
                 plan.setCompanyId(7);
                 plan.setCreateTime(LocalDateTime.now());
@@ -488,17 +492,14 @@ public class TimingTask {
                             plan.setEndDate(localDateFromUnix);
                         }
                     }
-                    if(title.getJSONObject(0).getString("text").equals("工作时长")){
+                    if(title.getJSONObject(0).getString("text").equals("结算总时长")){
                         if(control.equals("Number")){
-                            double new_number = value.getDoubleValue("new_number");
-                            workTime=new_number;
+                            double new_number = StringUtils.isEmpty(value.getString("new_number")) ?0.0:value.getDoubleValue("new_number");
+                            BigDecimal bigDecimal = new BigDecimal(new_number);
+                            workTime=bigDecimal.doubleValue();
                         }
                     }
-                    BigDecimal bigDecimal = new BigDecimal(plan.getPlanManNum()==null?0:plan.getPlanManNum());
-                    //工时以分钟为单位 *60
-                    bigDecimal=bigDecimal.multiply(new BigDecimal(workTime));
-                    bigDecimal=bigDecimal.multiply(new BigDecimal(60));
-                    plan.setPlanWorkHour(bigDecimal.doubleValue());
+                    plan.setPlanWorkHour(workTime*60);
                     if(title.getJSONObject(0).getString("text").equals("所属工位")){
                         if(control.equals("Contact")){
                             JSONArray departments = value.getJSONArray("departments");
@@ -530,7 +531,11 @@ public class TimingTask {
                             JSONObject formula = value.getJSONObject("formula");
                             if(!formula.getString("value").equals("")){
                                 double formulaDoubleValue = formula.getDoubleValue("value");
-                                plan.setMoneyOfJob(new BigDecimal(formulaDoubleValue));
+                                BigDecimal bigDecimal = new BigDecimal(formulaDoubleValue);
+                                if(workTime>0){
+                                    BigDecimal divide = bigDecimal.divide(new BigDecimal(workTime), 0, RoundingMode.HALF_UP);
+                                    plan.setMoneyOfJob(divide);
+                                }
                             }
                         }
                     }
@@ -552,9 +557,10 @@ public class TimingTask {
                         report.setCreatorId(user.get().getId());
                         report.setCreateTime(LocalDateTime.now());
                         BigDecimal bigDecimal = new BigDecimal(workTime);
+                        bigDecimal=bigDecimal.divide(new BigDecimal(plan.getPlanManNum()==null?0:plan.getPlanManNum()),1,RoundingMode.HALF_UP);
+                        report.setWorkingTime(bigDecimal.doubleValue());
                         bigDecimal=bigDecimal.multiply(price);
                         report.setCost(bigDecimal);
-                        report.setWorkingTime(workTime);
                         report.setStatus(2);
                         report.setPlanId(plan.getId());
                         report.setCompanyId(7);

+ 5 - 4
fhKeeper/formulahousekeeper/management-workshop/src/main/resources/mapper/ReportMapper.xml

@@ -139,10 +139,11 @@
         IFNULL(SUM(IF(a.`user_procedure_team_id`IS NOT NULL,a.cost,NULL)),0) AS cost,
         IFNULL(SUM(IF(a.`user_procedure_team_id` IS NOT NULL,a.working_time,NULL)),0) AS workTime,
         IFNULL(SUM(IF(a.`user_procedure_team_id`IS NULL,a.cost,NULL)),0) AS tempCost,
-        IFNULL(SUM(IF(a.`user_procedure_team_id` IS NULL,a.working_time,NULL)),0) AS tempWorkTime
+        IFNULL(SUM(IF(a.`user_procedure_team_id` IS NULL,a.working_time*60,NULL)),0) AS tempWorkTime
         from report a
         left join user b on a.creator_id=b.id
         left join department c on c.department_id=b.department_id
+        left join plan p on p.id=a.plan_id
         where a.company_id=#{companyId}
         <if test="list!=null and list.size()>0">
             and c.department_id in
@@ -171,7 +172,7 @@
         left join plan on plan.id=r.plan_id
         left join user u on r.checker_id=u.id
         left join user u2 on r.creator_id=u2.id
-        where r.company_id=#{companyId}  and r.finish_num &gt; 0
+        where r.company_id=#{companyId}  and ((plan.plan_type=0 and r.finish_num &gt; 0) || plan.plan_type=1)
         <if test="date!=null and date!=''">
             and r.create_date=#{date}
         </if>
@@ -191,7 +192,7 @@
     </select>
 
     <select id="getPersonWorkHoursWagesDetailForTemp" resultType="java.util.Map">
-        select r.cost,r.working_time,r.finish_num, r.creator_id,DATE_FORMAT(r.create_date,'%Y%m%d') as createDate,
+        select r.cost,(r.working_time*60) as working_time,r.finish_num, r.creator_id,DATE_FORMAT(r.create_date,'%Y%m%d') as createDate,
         p.name as productName,DATE_FORMAT(plan.start_date,'%Y%m%d') as planStartDate,DATE_FORMAT(plan.end_date,'%Y%m%d') as planEndDate ,
         plan.task_change_notice_num as taskChangeNoticeNum,plan.plan_type as planType,u.name as checkerName,u2.name as creatorName,plan.task_name as taskName,plan.task_type_name
         from report r
@@ -255,7 +256,7 @@
         LEFT JOIN prod_procedure pp ON ppt.prod_procedure_id=pp.id
         LEFT JOIN product p ON p.id=plan.product_id
         WHERE ppt2.company_id=#{companyId}
-        AND r.sumReport &lt; ppt2.work_time
+        AND IFNULL(r.sumReport,0) &lt; ppt2.work_time AND ppt.total_progress &lt; 100
         <if test="date!=null and date!=''">
             and ppt2.distribute_date=#{date}
         </if>

+ 92 - 0
fhKeeper/formulahousekeeper/timesheet-workshop/src/views/plan/orderInsert.vue

@@ -15,6 +15,8 @@
           </div>
         </div>
         <div class="OutSide_right">
+          <el-link type="primary" :underline="false" @click="showReportingDialog()">{{ "同步临时报工"
+          }}</el-link>
           <el-link type="primary" :underline="false" @click="(taskTypeDialog = true)">{{ "任务类型管理"
           }}</el-link>
           <el-link type="primary" :underline="false" @click="addPlan()">{{
@@ -222,6 +224,29 @@
       </span>
     </el-dialog>
 
+    <!-- 同步临时报工 -->
+    <el-dialog title="同步临时报工" :visible.sync="synchronousReportingDialog" width="600px" :before-close="handleClose">
+      <div class="tongbu">
+        <div :style="`color: ${reportWorkDayDisable ? 'red' : '#999'}`">选择的日期在三十天内</div>
+        <el-date-picker
+          v-model="reportWorkDay"
+          type="daterange"
+          value-format="yyyy-MM-dd"
+          :clearable="false"
+          range-separator="至"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          @change="handleDateChange">
+        </el-date-picker>
+      </div>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="
+          (synchronousReportingDialog = false)
+          ">取 消</el-button>
+        <el-button type="primary" :loading="reportWorkLoading" :disabled="reportWorkDayDisable" @click="reportWorkCli()">确定</el-button>
+      </span>
+    </el-dialog>
+
     <!-- 任务类型新增 -->
     <el-dialog title="新增任务类型" :visible.sync="taskTypeAddDialog" width="800" :before-close="handleClose">
       <div>
@@ -290,6 +315,10 @@ export default {
   },
   data() {
     return {
+      synchronousReportingDialog: false, 
+      reportWorkDay: [],
+      reportWorkDayDisable: false,
+      reportWorkLoading: false,
       steelStampNumber: "",
       todayDate: this.dayjs().format('YYYY-MM-DD'),
       planDate: this.dayjs().format('YYYY-MM-DD'),
@@ -390,6 +419,55 @@ export default {
       this.getTaskTypeList();
   },
   methods: {
+    reportWorkCli() {
+      this.reportWorkLoading = true;
+      this.http.post(
+        "/wx-corp-info/testSyncTemporaryJobApplication",
+        { startDate: this.reportWorkDay[0], endDate: this.reportWorkDay[1] },
+        (res) => {
+          this.reportWorkLoading = false;
+          if (res.code == "ok") {
+            this.synchronousReportingDialog = false
+            this.$message({
+              message: '同步成功',
+              type: "success",
+            });
+            this.getTableData()
+          } else {
+            this.$message({
+              message: res.msg,
+              type: "error",
+            });
+          }
+        },
+        (error) => {
+          this.reportWorkLoading = false;
+          this.$message({
+            message: error,
+            type: "error",
+          });
+        }
+      );
+    },
+    // 显示临时报工
+    showReportingDialog() {
+      this.reportWorkDay = [this.dayjs().format('YYYY-MM-DD'), this.dayjs().format('YYYY-MM-DD')]
+      this.synchronousReportingDialog = true
+    },
+    handleDateChange(value) {
+      const startDate = value[0];
+      const endDate = value[1];
+      const d1 = this.dayjs(startDate);
+      const d2 = this.dayjs(endDate);
+      const diffDays = Math.abs(d1.diff(d2, 'day'));
+      if (diffDays > 30) {
+        this.reportWorkDayDisable = true
+        console.log('日期相隔超过三十天');
+      } else {
+        console.log('日期相隔不超过三十天');
+        this.reportWorkDayDisable = false
+      }
+    },
     // 初始化 Form
     initTodayPlanForm() {
       this.todayPlanForm = {
@@ -1058,6 +1136,20 @@ export default {
 };
 </script>
 <style scoped lang='scss'>
+
+.tongbu {
+  width: 100%;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  &>div {
+    margin-bottom: 15px;
+    color: #999;
+    &:last-child {
+      margin-bottom: 0;
+    }
+  }
+}
 .colorText {
   color: #02a7f0;
   cursor: pointer;

+ 2 - 2
fhKeeper/formulahousekeeper/timesheet-workshop/src/views/statistic/index.vue

@@ -94,7 +94,7 @@
                               <!-- <div @click.stop="showReportDetail(scope.row,item,0)" v-if="items.workTime>0">已填 {{items.workTime}}分钟  {{items.cost}}元 </div>{{items.leave}}
                               <div style="color: green;" @click.stop="showTempReportDetail(scope.row,item,0)" v-if="items.tempWorkTime>0||items.tempCost>0">临时报工 {{items.tempWorkTime}}分钟  {{items.tempCost}}元</div> -->
                               <div  v-if="items.workTime>0">已填 {{items.workTime}}分钟  {{items.cost}}元 </div>{{items.leave}}
-                              <div style="color: green;" v-if="items.tempWorkTime>0||items.tempCost>0">临时报工 {{items.tempWorkTime}}小时  {{items.tempCost}}元</div>
+                              <div style="color: green;" v-if="items.tempWorkTime>0||items.tempCost>0">临时报工 {{items.tempWorkTime}}分钟  {{items.tempCost}}元</div>
                               <div style="color: red;" v-if="items.surplusTime">剩余 {{items.surplusTime}}分钟  {{items.surplusCost}}元</div>
                             </div>
                         </div>
@@ -393,7 +393,7 @@
               <el-table-column prop="checkerName" label="质检人" width="180"></el-table-column>
               <el-table-column prop="working_time" label="工作时长" width="180">
                 <template slot-scope="scope" v-if="scope.row.working_time">
-                  {{scope.row.working_time}}{{scope.row.planType==0?'分钟':'小时'}}
+                  {{scope.row.working_time}}{{'分钟'}}
                 </template>
               </el-table-column>
             </el-table>

+ 5 - 0
fhKeeper/formulahousekeeper/timesheet/src/components/echartsEchar.vue

@@ -53,6 +53,11 @@ export default {
       return new Date().getTime();
     },
   },
+  beforeDestroy() {
+    if (this.myChart) {
+      this.myChart.dispose();
+    }
+  }
 };
 </script>
 

+ 1 - 1
fhKeeper/formulahousekeeper/timesheet/src/http.js

@@ -2,7 +2,7 @@ import axios from 'axios'
 import qs from 'qs'
 import imgPath from "@/assets/image/jiazai.gif"
 
-const TIME_OUT_MS = 180 * 1000 // 默认请求超时时间
+const TIME_OUT_MS = 600 * 1000 // 默认请求超时时间
 
 function prompt() {
     window.ELEMENT.Message({

+ 2 - 1
fhKeeper/formulahousekeeper/timesheet/src/i18n/en.json

@@ -29,7 +29,8 @@
     "caiwushenhe": "Financial review",
     "basicDataManagement": "Basic data management",
     "budgetReview": "Estimated working hours review",
-    "projectFormSettings": "Project Form Settings"
+    "projectFormSettings": "Project Form Settings",
+    "userGroupManagement": "User group management"
   },
   "role": {
     "ordinaryEmployees": "Ordinary employees",

+ 2 - 1
fhKeeper/formulahousekeeper/timesheet/src/i18n/zh.json

@@ -29,7 +29,8 @@
     "projectFormSettings": "项目表单设置",
     "budgetReview": "预估工时审核",
     "gongshitongji": "工时统计表",
-    "caiwushenhe": "财务审核"
+    "caiwushenhe": "财务审核",
+    "userGroupManagement": "用户分组管理"
   },
   "role": {
     "ordinaryEmployees": "普通员工",

+ 5 - 0
fhKeeper/formulahousekeeper/timesheet/src/permissions.js

@@ -145,6 +145,9 @@ const StringUtil = {
         importAudit: false, // 查看导审记录 //
 
         customDataAll: false,// 查看全公司数值-自定义数值统计模块
+
+        // 用户分组管理
+        userGroupManage: false,
         
     }
     // console.log(arr);
@@ -277,6 +280,8 @@ const StringUtil = {
         arr[i] == '查看全部立项申请'  ? obj.projectApprovalView = true : ''
         arr[i] == '管理全部立项申请'  ? obj.projectApprovalEdit = true : ''
         arr[i] == '审核立项申请' ? obj.projectApprovalCheck = true : ''
+
+        arr[i] == '用户分组管理' ? obj.userGroupManage = true : ''
     }
     return obj
   }

+ 4 - 0
fhKeeper/formulahousekeeper/timesheet/src/routes.js

@@ -96,6 +96,9 @@ import budgetReview from './views/project/budgetReview'
 // 财务审核
 import financeAudit from './views/financeAudit/financeAudit.vue'
 
+// 用户分组管理
+import userGrouping from './views/userGrouping/userGrouping.vue'
+
 Vue.use(Router)
 
 export const fixedRouter = [
@@ -505,6 +508,7 @@ export const allRouters = [//组织架构
         children: [
             { path: '/timetype', component: timetype, name: '系统基础设置', iconCls: 'iconfont firerock-iconxitong-', meta: { text: 'navigation.basicSystemSettings' }},
             { path: '/role', component: quanx, name: '角色权限管理', iconCls: 'iconfont firerock-iconquanxian1', meta: { text: 'navigation.roleRightsManagement' } },
+            { path: '/userGrouping', component: userGrouping, name: '用户分组管理', iconCls: 'iconfont firerock-iconquanxian1', meta: { text: 'navigation.userGroupManagement' } },
             { path: '/projectForm', component: projectForm, name: '项目表单设置', iconCls: 'iconfont firerock-iconquanxian1', meta: { text: 'navigation.projectFormSettings' } },
         ],
         // 其他信息

+ 283 - 7
fhKeeper/formulahousekeeper/timesheet/src/views/corpreport/echartsData.js

@@ -38,12 +38,6 @@ export function getGroupConsumption(nameList = [], actualPlan = [], actualSupple
           formatter: "{value} (h)",
         },
       },
-      {
-        type: "value",
-        axisLabel: {
-          formatter: "{value} (h)",
-        },
-      },
     ],
     series: [
       {
@@ -73,7 +67,6 @@ export function getGroupConsumption(nameList = [], actualPlan = [], actualSupple
       {
         name: "汇总",
         type: "line",
-        yAxisIndex: 1,
         lineStyle: {
           normal: {
             width: 3,
@@ -84,4 +77,287 @@ export function getGroupConsumption(nameList = [], actualPlan = [], actualSupple
       },
     ],
   }
+}
+
+export function getPieEchartOption(titleName, datas = []) {
+  return {
+    title: {
+      text: titleName,
+      left: 'center',
+      top: 40
+    },
+    tooltip: {
+      trigger: 'item'
+    },
+    legend: {
+      orient: 'vertical',
+      left: 'left'
+    },
+    series: [
+      {
+        name: titleName,
+        type: 'pie',
+        radius: '50%',
+        data: datas,
+        emphasis: {
+          itemStyle: {
+            shadowBlur: 10,
+            shadowOffsetX: 0,
+            shadowColor: 'rgba(0, 0, 0, 0.5)'
+          }
+        }
+      }
+    ]
+  }
+}
+
+export function debounce(func, delay) {
+  let timer;
+  return function() {
+    const context = this;
+    const args = arguments;
+    clearTimeout(timer);
+    timer = setTimeout(() => {
+      func.apply(context, args);
+    }, delay);
+  };
+}
+
+export const fixedTaskGrouping = ['工程部现场安装施工', '工程部配合调试', '生产部电气', '生产部车间', '研发部BIM设计', '研发部工艺设计', '研发部工艺调试验收', '研发部电气设计', '研发部电气调试验收', '研发部结构设计']
+
+// 固定分组数据
+export const fixedGrouping = {
+  technology: { // 研发工艺
+    tableFileds: [
+      { label: '方案设计', filed: '方案设计' },
+      { label: '研发部', filed: '研发部' },
+      { label: '研发部工艺调试', filed: '研发部工艺调试' },
+      { label: '研发部工艺调试验收', filed: '研发部工艺调试验收' },
+      { label: '研发部工艺设计', filed: '研发部工艺设计' },
+      { label: '报价占比', filed: '报价占比', unit: '%' },
+      { label: '行政占比', filed: '行政占比', unit: '%'  },
+      { label: '项目设计占比', filed: '项目设计占比', unit: '%'  },
+    ],
+    tabPicFileds: [
+      { label: '方案设计', filed: '方案设计', title: '报价项目占比' },
+      // { label: '研发部', filed: '研发部', title: '行政项目占比' },
+      { label: '研发部工艺调试', filed: '研发部工艺调试', title: '项目设计占比' }
+    ],
+    proportion: [
+      { key: '报价占比', value: '方案设计' },
+      { key: '行政占比', value: '研发部' },
+      { key: '项目设计占比', value: '研发部工艺设计' },
+    ],
+    deptIds: '8754,8768',
+    name: '研发工艺',
+    tableKey: 1001
+  },
+  bim: { // 研发BIM
+    tableFileds: [
+      { label: '研发部', filed: '研发部' },
+      { label: '研发部BIM设计', filed: '研发部BIM设计' },
+      { label: '行政占比', filed: '行政占比', unit: '%'  },
+      { label: '设计占比', filed: '设计占比', unit: '%'  },
+    ],
+    tabPicFileds: [
+      // { label: '研发部', filed: '研发部', title: 'BIM行政工时占比' },
+      { label: '研发部BIM设计', filed: '研发部BIM设计', title: 'BIM设计项目占比' }
+    ],
+    proportion: [
+      { key: '行政占比', value: '研发部' },
+      { key: '设计占比', value: '研发部BIM设计' },
+    ],
+    deptIds: '8757',
+    name: '研发BIM',
+    tableKey: 1002,
+  },
+  structure: { // 研发结构
+    tableFileds: [
+      { label: '研发部', filed: '研发部' },
+      { label: '研发部结构设计', filed: '研发部结构设计' },
+      { label: '行政占比', filed: '行政占比', unit: '%'  },
+      { label: '设计占比', filed: '设计占比', unit: '%'  },
+    ],
+    tabPicFileds: [
+      // { label: '研发部', filed: '研发部', title: '研发行政工时占比' },
+      { label: '研发部结构设计', filed: '研发部结构设计', title: '结构设计项目占比' }
+    ],
+    proportion: [
+      { key: '行政占比', value: '研发部' },
+      { key: '设计占比', value: '研发部结构设计' },
+    ],
+    deptIds: '8758,8769',
+    name: '研发结构',
+    tableKey: 1003
+  },
+  electrical: { // 研发电气
+    tableFileds: [
+      { label: '研发部', filed: '研发部' },
+      { label: '研发部电气调试验收', filed: '研发电气调试验收' },
+      { label: '研发部电气设计', filed: '研发部电气设计' },
+      { label: '研发部售后', filed: '研发部售后' },
+      { label: '行政占比', filed: '行政占比', unit: '%'  },
+      { label: '设计占比', filed: '设计占比', unit: '%'  },
+      { label: '调试占比', filed: '调试占比', unit: '%'  },
+    ],
+    tabPicFileds: [
+      // { label: '研发部', filed: '研发部', title: '电气行政工时占比' },
+      { label: '研发部电气设计', filed: '研发部电气设计', title: '电气设计项目占比' },
+      { label: '研发部电气调试验收', filed: '研发部电气调试验收', title: '电气调试项目占比' }
+    ],
+    proportion: [
+      { key: '行政占比', value: '研发部' },
+      { key: '设计占比', value: '研发部电气设计' },
+      { key: '调试占比', value: '研发部电气调试验收' },
+    ],
+    deptIds: '8756,8770',
+    name: '研发电气',
+    tableKey: 1004
+  },
+  shakedown: { // 研发调试
+    tableFileds: [
+      { label: '研发部', filed: '研发部' },
+      { label: '研发部工艺调试', filed: '研发部工艺调试' },
+      { label: '研发部工艺调试验收', filed: '研发部工艺调试验收' },
+      { label: '研发部工艺设计', filed: '研发部工艺设计' },
+      { label: '研发部售后', filed: '研发部售后' },
+      { label: '研发部运维', filed: '研发部运维' },
+      { label: '行政占比', filed: '行政占比', unit: '%'  },
+      { label: '项目调试占比', filed: '项目调试占比', unit: '%'  },
+      { label: '售后占比', filed: '售后占比', unit: '%'  },
+    ],
+    tabPicFileds: [
+      // { label: '研发部', filed: '研发部', title: '研发调试行政工时占比' },
+      { label: '研发部工艺调试验收', filed: '研发部工艺调试验收', title: '调试项目占比' },
+      { label: '研发部售后', filed: '研发部售后', title: '售后项目占比' }
+    ],
+    proportion: [
+      { key: '行政占比', value: '研发部' },
+      { key: '项目调试占比', value: '研发部工艺调试验收' },
+      { key: '售后占比', value: '研发部售后' },
+    ],
+    deptIds: '8755',
+    name: '研发调试',
+    tableKey: 1005
+  },
+  produce: { // 生产部
+    tableFileds: [
+      { label: '生产部', filed: '生产部' },
+      { label: '生产部车间', filed: '生产部车间' },
+      { label: '生产部电气', filed: '生产部电气' },
+      { label: '行政占比', filed: '行政占比', unit: '%'  },
+      { label: '项目占比', filed: '项目占比', unit: '%'  },
+    ],
+    tabPicFileds: [
+      // { label: '研发部', filed: '研发部', title: '生产部行政工时占比' },
+      { label: '生产部车间,生产部电气', filed: '生产部车间,生产部电气', title: '生产项目占比' }
+    ],
+    proportion: [
+      { key: '行政占比', value: '生产部' },
+      { key: '项目占比', value: '生产部车间' },
+      { key: '项目占比', value: '生产部电气' },
+    ],
+    deptIds: '8762,8760,8761,8737,7903',
+    name: '生产部',
+    tableKey: 1006
+  },
+  engineering: { // 工程部
+    tableFileds: [
+      { label: '工程部', filed: '工程部' },
+      { label: '工程部配合调试', filed: '工程部配合调试' },
+      { label: '工程部配合运维', filed: '工程部配合运维' },
+      { label: '工程部售后', filed: '工程部售后' },
+      { label: '工程部现场安装施工', filed: '工程部现场安装施工' },
+      { label: '生产部', filed: '生产部' },
+      { label: '生产部车间', filed: '生产部车间' },
+      { label: '生产部电气', filed: '生产部电气' },
+      { label: '项目阶段', filed: '项目阶段' },
+      { label: '研发部工艺调试验收', filed: '研发部工艺调试验收' },
+      { label: '研发部运维', filed: '研发部运维' },
+      { label: '行政占比', filed: '行政占比', unit: '%'  },
+      { label: '配合调试占比', filed: '配合调试占比', unit: '%'  },
+      { label: '运维占比', filed: '运维占比', unit: '%'  },
+      { label: '售后占比', filed: '售后占比', unit: '%'  },
+      { label: '施工占比', filed: '施工占比', unit: '%'  },
+      { label: '施工占配合生产占比', filed: '施工占配合生产占比', unit: '%'  },
+      { label: '配合生产占比', filed: '配合生产占比', unit: '%'  },
+    ],
+    tabPicFileds: [
+      // { label: '工程部', filed: '工程部', title: '工程部行政工时占比' },
+      { label: '工程部配合调试', filed: '工程部配合调试', title: '配合调试工时占比' },
+      { label: '工程部售后', filed: '工程部售后', title: '售后占比' },
+      { label: '工程部配合运维', filed: '工程部配合运维', title: '运维占比' },
+      { label: '工程部现场安装施工', filed: '工程部现场安装施工', title: '施工占比' },
+      { label: '生产部,生产部车间,生产部电气', filed: '生产部,生产部车间,生产部电气', title: '配合生产占比' },
+    ],
+    proportion: [
+      { key: '行政占比', value: '工程部' },
+      { key: '配合调试占比', value: '工程部配合调试' },
+      { key: '运维占比', value: '工程部配合运维' },
+      { key: '售后占比', value: '工程部售后' },
+      { key: '施工占比', value: '工程部现场安装施工' },
+      { key: '配合生产占比', value: '生产部' },
+      { key: '配合生产占比', value: '生产部车间' },
+      { key: '配合生产占比', value: '生产部电气' },
+    ],
+    deptIds: '7460,8763,8764,8765,8766',
+    name: '工程部',
+    tableKey: 1007
+  },
+}
+
+// 更具计算返回对应的占比
+export const getProportion = (list, fixedKey) => {
+  const newList = JSON.parse(JSON.stringify(list))
+  const listItem = fixedGrouping[fixedKey]
+  const proportion = listItem.proportion
+  newList.forEach(item => {
+    proportion.forEach(proportionItem => {
+      if(!item[proportionItem.key]) {
+        item[proportionItem.key] = item[proportionItem.value]
+      } else {
+        item[proportionItem.key] += item[proportionItem.value]
+      }
+    })
+  })
+  newList.forEach(item => {
+    proportion.forEach(proportionItem => {
+      if(item[proportionItem.key] != 0) {
+        let num = (item[proportionItem.key] / item.totalWorkTime) * 100
+        item[proportionItem.key] = Number(num.toFixed(2))
+      }
+    })
+  })
+  return newList
+}
+
+// 汇总计算
+export const collectNUm = (list, fixedKey) => {
+  const newList = JSON.parse(JSON.stringify(list))
+  const listItem = fixedGrouping[fixedKey]
+  const proportion = listItem.proportion
+  let totalNum = list.reduce((prev, curr) => { // 总计值
+      return { totalWorkTime: prev.totalWorkTime + curr.totalWorkTime };
+  }, { totalWorkTime: 0 }).totalWorkTime
+  let returnedValue = {}
+  newList.forEach(item => {
+    proportion.forEach(proportionItem => {
+      if(!item[proportionItem.key]) {
+        item[proportionItem.key] = item[proportionItem.value]
+      } else {
+        item[proportionItem.key] += item[proportionItem.value]
+      }
+    })
+  })
+
+  proportion.forEach(proportionItem => {
+    returnedValue[proportionItem.key] = newList.reduce((prev, curr) => { // 总计值
+        return { [proportionItem.key]: prev[proportionItem.key] + curr[proportionItem.key] };
+    }, { [proportionItem.key]: 0 })[proportionItem.key]
+  })
+
+  return {
+    ...returnedValue,
+    totalNum: totalNum
+  }
 }

+ 189 - 49
fhKeeper/formulahousekeeper/timesheet/src/views/corpreport/list.vue

@@ -121,7 +121,7 @@
         <template v-if="ins == 24">
           <el-radio-group v-model="tabPosition" size="small" @input="getGroupConsumptionData">
             <el-radio-button label="0">表格</el-radio-button>
-            <el-radio-button label="1">柱状图</el-radio-button>
+            <el-radio-button label="1">图</el-radio-button>
           </el-radio-group>
         </template>
           
@@ -139,7 +139,7 @@
           </el-option>
         </el-select>
 
-        <el-select v-if="ins == 24 && tabPosition == 1" v-model="groupConsumptionName" placeholder="请选择任务分组" clearable filterable size="small" @change="getList(true)" multiple collapse-tags style="margin-left:10px; width: 250px">
+        <el-select v-if="ins == 24 && tabPosition == 1" v-model="groupConsumptionName" placeholder="请选择任务分组" :clearable="tabsType == 'all' ? true : false" filterable size="small" @change="getList(true)" :multiple="tabsType == 'all' ? true : false" collapse-tags style="margin-left:10px; width: 250px" :key="groupTaskKey">
           <el-option v-for="(item, index) in groupConsumptionList" :key="item.id" :label="item" :value="item"> </el-option>
         </el-select>
 
@@ -217,7 +217,7 @@
       </div>
       <!-- <p :style="ins == 9 ? 'float: right;margin-right: 25px;width:20%' : 'float: right;margin-right: 25px;width:10%'" > -->
       <p :style="`${ins == 9 || ins == 14 || ins == 21 ? 'width: 20%' : 'width: 10%'}`" class="tableRightBtn">
-        <el-button type="primary" @click="exportExcel" size="mini">{{ $t('reporderived') }}</el-button>
+        <el-button type="primary" :loading="exportReportLoading" @click="exportExcel" size="mini">{{ $t('reporderived') }}</el-button>
         <el-button type="primary" @click="fillAll" size="mini" v-if="ins == 14">{{ $t('quanBuBuZu') }}</el-button>
         <el-button type="primary" @click="exportExcelByQuarter" size="mini" v-if="ins == 9 && user.companyId == 876">{{ $t('an-ji-du-dao-chu') }}</el-button>
         <el-button type="primary" @click="setWarning" size="mini" v-if="ins == 21">{{ $t('sheZhiYuJing') }}</el-button>
@@ -1170,39 +1170,115 @@
               <el-table-column align="center" prop="projectCode" :label="$t('Itemno')"></el-table-column>
               <el-table-column align="center" prop="residueTime" :label="$t('shengYuGongShiH')" width="150"></el-table-column>
             </el-table>
+            <div class="packetConsumption" v-if="ins == 24" :style="`height:${tabPosition == 0 ? tableHeight : tableHeight + 50}px`" v-loading="listLoading">
+              <el-tabs v-model="tabsType" :tab-position="'left'" @tab-click="handleClick" 
+              :style="`height: 100%;width: 100%;margin-right: 20px`">
+                <el-tab-pane name="all" label="分组耗用表">
+                  <PackTables :datas="{ 
+                    type: tabsType, 
+                    tabPosition: tabPosition,
+                    list: isbeCustomReport.consumptionSchedule,
+                    height: tableHeight,
+                    listArr1,
+                    listArr2,
+                    listArr3,
+                    params: {
+                      groupNames: groupConsumptionName,
+                      projectIds: proJuctId,
+                      pageIndex: page,
+                      pageSize: size,
+                      dataTime: rangeDatas
+                    },
+                    echartsData: groupConsumptionOption
+                  }" />
+                </el-tab-pane>
+                <el-tab-pane name="technology" label="研发工艺">
+                  <PackTables :datas="{ type: tabsType, regular: 'technology', height: tableHeight, tabPosition, params: {
+                    projectIds: proJuctId,
+                    groupNames: groupConsumptionName,
+                    dataTime: rangeDatas
+                  } }" />
+                </el-tab-pane>
+                <el-tab-pane name="bim" label="研发BIM">
+                  <PackTables :datas="{ type: tabsType, regular: 'bim', height: tableHeight, tabPosition, params: {
+                    projectIds: proJuctId,
+                    groupNames: groupConsumptionName,
+                    dataTime: rangeDatas
+                  } }" />
+                </el-tab-pane>
+                <el-tab-pane name="structure" label="研发结构">
+                  <PackTables :datas="{ type: tabsType, regular: 'structure', height: tableHeight, tabPosition, params: {
+                    projectIds: proJuctId,
+                    groupNames: groupConsumptionName,
+                    dataTime: rangeDatas
+                  } }" />
+                </el-tab-pane>
+                <el-tab-pane name="electrical" label="研发电气">
+                  <PackTables :datas="{ type: tabsType, regular: 'electrical', height: tableHeight, tabPosition, params: {
+                    projectIds: proJuctId,
+                    groupNames: groupConsumptionName,
+                    dataTime: rangeDatas
+                  } }" />
+                </el-tab-pane>
+                <el-tab-pane name="shakedown" label="研发调试">
+                  <PackTables :datas="{ type: tabsType, regular: 'shakedown', height: tableHeight, tabPosition, params: {
+                    projectIds: proJuctId,
+                    groupNames: groupConsumptionName,
+                    dataTime: rangeDatas
+                  } }" />
+                </el-tab-pane>
+                <el-tab-pane name="produce" label="生产部">
+                  <PackTables :datas="{ type: tabsType, regular: 'produce', height: tableHeight, tabPosition, params: {
+                    projectIds: proJuctId,
+                    groupNames: groupConsumptionName,
+                    dataTime: rangeDatas
+                  } }" />
+                </el-tab-pane>
+                <el-tab-pane name="engineering" label="工程部">
+                  <PackTables :datas="{ type: tabsType, regular: 'engineering', height: tableHeight, tabPosition, params: {
+                    projectIds: proJuctId,
+                    groupNames: groupConsumptionName,
+                    dataTime: rangeDatas
+                  } }" />
+                </el-tab-pane>
+              </el-tabs>
+              <!-- <div>
 
-            <!-- 分组耗用进度表 -->
-            <el-table  v-if="ins == 24 && tabPosition==0" :key="24" border :data="isbeCustomReport.consumptionSchedule" highlight-current-row v-loading="listLoading" :height="(+tableHeight - 0) - 1" style="width: 100%;" :span-method="objectSpanMethod">
-              <el-table-column align="center" prop="projectName" :label="$t('headerTop.projectName')" min-width="200"></el-table-column>
-              <el-table-column align="center" prop="department_name" :label="$t('fuZeBuMen')" min-width="150">
-                <template slot-scope="scope">
-                  <div>
-                    <span v-if="user.userNameNeedTranslate == '1'">
-                      <TranslationOpenDataText type='departmentName' :openid='scope.row.corpwxDeptId'></TranslationOpenDataText>
-                    </span>
-                    <span v-if="user.userNameNeedTranslate != '1'">
-                      {{scope.row.departmentName}}
-                    </span>
-                    <!-- {{ scope.row.corpwxDeptId }} -->
-                  </div>
-                </template>
-              </el-table-column>
-              <el-table-column align="center" prop="groupName" :label="$t('lable.taskGrouping')" min-width="150"></el-table-column>
-              <el-table-column align="center" prop="planHour" :label="$t('jiHuaGongShiCaiWu')" width="120"></el-table-column>
-              <el-table-column align="center" :label="$t('shiJiGongShiChengBen')">
-                <el-table-column align="center" prop="afterSetPlanHour" :label="$t('zengBuGongShiH')" width="120"></el-table-column>
-                <el-table-column align="center" prop="normalHour" :label="$t('zhengChangGongShiH')" width="100"></el-table-column>
-                <el-table-column align="center" prop="overHour" :label="$t('jiaBanGongShiH')" width="100"></el-table-column>
-                <el-table-column align="center" prop="realHour" :label="$t('heJiGongShiH')" width="100"></el-table-column>
-                <el-table-column align="center" prop="realCost" :label="$t('heJiGongShiChengBen')" width="140"></el-table-column>
-              </el-table-column>
-              <el-table-column align="center" prop="process" :label="$t('gongShiHaoYongShuai')" width="150"></el-table-column>
-            </el-table>
+              </div>
+              <div class="packetConsumption-flex"></div> -->
+              <!-- 分组耗用进度表 -->
+              <!-- <el-table  v-if="ins == 24 && tabPosition==0" :key="24" border :data="isbeCustomReport.consumptionSchedule" highlight-current-row v-loading="listLoading" :height="(+tableHeight - 0) - 1" style="width: 100%;" :span-method="objectSpanMethod">
+                <el-table-column align="center" prop="projectName" :label="$t('headerTop.projectName')" min-width="200"></el-table-column>
+                <el-table-column align="center" prop="department_name" :label="$t('fuZeBuMen')" min-width="150">
+                  <template slot-scope="scope">
+                    <div>
+                      <span v-if="user.userNameNeedTranslate == '1'">
+                        <TranslationOpenDataText type='departmentName' :openid='scope.row.corpwxDeptId'></TranslationOpenDataText>
+                      </span>
+                      <span v-if="user.userNameNeedTranslate != '1'">
+                        {{scope.row.departmentName}}
+                      </span>
+                    </div>
+                  </template>
+                </el-table-column>
+                <el-table-column align="center" prop="groupName" :label="$t('lable.taskGrouping')" min-width="150"></el-table-column>
+                <el-table-column align="center" prop="planHour" :label="$t('jiHuaGongShiCaiWu')" width="120"></el-table-column>
+                <el-table-column align="center" :label="$t('shiJiGongShiChengBen')">
+                  <el-table-column align="center" prop="afterSetPlanHour" :label="$t('zengBuGongShiH')" width="120"></el-table-column>
+                  <el-table-column align="center" prop="normalHour" :label="$t('zhengChangGongShiH')" width="100"></el-table-column>
+                  <el-table-column align="center" prop="overHour" :label="$t('jiaBanGongShiH')" width="100"></el-table-column>
+                  <el-table-column align="center" prop="realHour" :label="$t('heJiGongShiH')" width="100"></el-table-column>
+                  <el-table-column align="center" prop="realCost" :label="$t('heJiGongShiChengBen')" width="140"></el-table-column>
+                </el-table-column>
+                <el-table-column align="center" prop="process" :label="$t('gongShiHaoYongShuai')" width="150"></el-table-column>
+              </el-table> -->
 
-            <!-- 分组耗用进度图表 -->
-            <div v-if="ins == 24 && tabPosition!=0" class="useASchedule" :style="`height:${tableHeight + 50}px`" v-loading="groupConsumptionLoading">
-              <EchartsEchar :options="groupConsumptionOption"></EchartsEchar>
+              <!-- 分组耗用进度图表 -->
+              <!-- <div v-if="ins == 24 && tabPosition == 1 && tabsType == 'all'" class="useASchedule" :style="`height:${tableHeight + 50}px;width: 100%`" v-loading="groupConsumptionLoading">
+                <EchartsEchar :options="groupConsumptionOption"></EchartsEchar>
+              </div> -->
             </div>
+            
 
             <!-- 项目耗用进度表 -->
             <el-table  v-if="ins == 25" :key="25" border :data="isbeCustomReport.consumptionScheduleTwo" highlight-current-row v-loading="listLoading" :height="(+tableHeight) - 1" style="width: 100%;" >
@@ -1330,7 +1406,7 @@
               <el-table-column align="center" prop="onTimePercent" :label="$t('anShiWanChengShuai')" min-width="150"></el-table-column>
             </el-table>
         <!--工具条-->
-        <el-col :span="24" class="toolbar" v-if="ins != 6 && ins != 20 && ins != 21 && tabPosition==0">
+        <el-col :span="24" class="toolbar" v-if="ins != 6 && ins != 20 && ins != 21 && tabPosition==0 && tabsType == 'all'">
           <el-pagination
                 v-if="ins == 12"
                 @size-change="groupSizeChange"
@@ -1647,14 +1723,16 @@ import selectCat from "@/components/select.vue"
 // 引入自定义级联组件
 import vueCascader from "@/components/cascader.vue"
 import EchartsEchar from "@/components/echartsEchar.vue"
-import { getGroupConsumption } from "./echartsData"
+import { getGroupConsumption, fixedTaskGrouping, fixedGrouping } from "./echartsData"
+import PackTables from "./packetConsumption/tables.vue"
 
 export default {
   name: "expense",
   components: {
     selectCat,
     vueCascader,
-    EchartsEchar
+    EchartsEchar,
+    PackTables
   },
   props: {},
   data() {
@@ -1885,9 +1963,13 @@ export default {
       // 分组耗用进度图表
       groupConsumptionOption: {},
       groupConsumptionLoading: false,
-      groupConsumptionList: ['工程部现场安装施工', '工程部配合调试', '生产部电气', '生产部车间', '研发部BIM设计', '研发部工艺设计', '研发部工艺调试验收', '研发部电气设计', '研发部电气调试验收', '研发部结构设计'],
+      groupConsumptionList: fixedTaskGrouping,
       groupConsumptionName: [],
-      groupConsumptionTimer: null
+      groupConsumptionTimer: null,
+      tabsType: 'all',
+      tabParams: {},
+      groupTaskKey: 1,
+      exportReportLoading: false
     };
   },
   computed: {},
@@ -1968,6 +2050,26 @@ export default {
       }
   },
   methods: {
+    handleClick() {
+      console.log(this.tabsType, '<==== 返回的书')
+      this.groupTaskKey++
+      if(this.tabsType == 'all') {
+        this.$set(this, 'groupConsumptionName', '')
+        this.$set(this, 'groupConsumptionList', fixedTaskGrouping)
+        this.$set(this, 'rangeDatas', null)
+        if(this.tabPosition == 1) {
+          this.getGroupConsumptionData()
+        } else {
+          this.getConsumptionSchedule()
+        }
+        return
+      }
+      this.rangeDatas = this.getCurrentRangeTime()
+      const type = this.tabsType
+      const list = fixedGrouping[type].tabPicFileds
+      this.groupConsumptionName = list[0].filed
+      this.groupConsumptionList = list.map(item => item.filed)
+    },
     authorityToJudge() {
       if(this.permissions.reportProject || this.permissions.reportAllProject) {this.ssl(0);this.defaultActive = '1-1';return} else
       if(this.permissions.reportTask || this.permissions.reportAllTask) {this.ssl(1);this.defaultActive = '1-2';return} else
@@ -2273,7 +2375,9 @@ export default {
             getList(e) {
               let noUserList = [16, 17, 18, 19, 20, 21, 22, 24, 25, 26,27]
               if(this.ins == 24) {
-                this.rangeDatas = []
+                if(this.tabsType == 'all') {
+                  this.rangeDatas = []
+                }
               } else if(this.ins == 15) {
                 this.rangeDatas = null
               } else if(!e){
@@ -2535,11 +2639,24 @@ export default {
           this.userId ? sl.userId = this.userId : ''
           dept ? sl.deptId = dept : ''
         } else if(this.ins == 24) {
-          fName = this.$t('fenZuHaoYongJinDuBiao') + '.xlsx'
-          url = "/project/exportGroupExpendProcessList"
-          this.proJuctId ? sl.projectId = this.proJuctId : ''
-          sl.startDate = this.rangeDatas[0]
-          sl.endDate = this.rangeDatas[1]
+          this.exportReportLoading = true
+          if(this.tabsType == 'all') {
+            fName = this.$t('fenZuHaoYongJinDuBiao') + '.xlsx'
+            url = "/project/exportGroupExpendProcessList"
+            this.proJuctId ? sl.projectId = this.proJuctId : ''
+            sl.startDate = this.rangeDatas[0]
+            sl.endDate = this.rangeDatas[1]
+          } else {
+            const type = this.tabsType
+            const row = fixedGrouping[type]
+            const listText = row.tableFileds.map(item => item.label).join(',')
+            fName = row + '表' + '.xlsx'
+            url = "/project/exportGroupExpendProcessListForUser"
+            this.proJuctId ? sl.projectId = this.proJuctId : ''
+            sl.startDate = this.rangeDatas[0]
+            sl.endDate = this.rangeDatas[1]
+            sl.titleStr = (listText || '')+',所属部门,工号,员工,总计'
+          }
         } else if(this.ins == 25) {
           fName = this.$t('xiangMuHaoYongJinDuBiao') + '.xlsx'
           url = "/project/exportProjectExpendProcessList"
@@ -2572,6 +2689,7 @@ export default {
         }
           this.http.post(url, sl,
             res => {
+                this.exportReportLoading = false
                 if (res.code == "ok") {
                     var filePath = res.data;
                     const a = document.createElement('a'); // 创建a标签
@@ -2587,6 +2705,7 @@ export default {
                 }
             },
             error => {
+                this.exportReportLoading = false
                 this.$message({
                     message: error,
                     type: "error"
@@ -2651,6 +2770,7 @@ export default {
       this.userId = null
       this.selUserList = this.userList
       this.tabPosition="0"
+      this.tabsType = 'all'
       this.getList();
     },
     stateKeySel(){
@@ -4176,6 +4296,9 @@ export default {
     },
     // 分组耗用进度表
     async getConsumptionSchedule() {
+      if(this.tabsType != 'all') {
+        return
+      }
       let parameter = {
         // startDate: this.rangeDatas[0],
         // endDate: this.rangeDatas[1],
@@ -4293,23 +4416,29 @@ export default {
         clearTimeout(this.groupConsumptionTimer)
       }
       this.groupConsumptionTimer = setTimeout(async () => {
+        if(this.tabsType != 'all') {
+          return
+        }
         if(this.tabPosition == 0) {
           this.proJuctId = ''
           return
         }
-        this.groupConsumptionLoading = true
+        // this.groupConsumptionLoading = true
+        this.listLoading = true
         let { data } = await this.postData('/project/groupExpendProcessListForChart', {
           startDate: this.rangeDatas[0],
           endDate: this.rangeDatas[1],
           projectIds: this.proJuctId,
           groupNames: this.groupConsumptionName.join(',')
         })
-        this.groupConsumptionLoading = false
+        // this.groupConsumptionLoading = false
+        this.listLoading = false
         let nameList = data.map(item => (item.groupName || ''))
         let realHourList = data.map(item => returnNum((item.realHour || 0)))
-        let actualPlan = data.map(item => returnNum((item.planHour || 0)))
-        let actualSupplement = data.map(item => returnNum((item.afterSetPlanHour || 0)))
-        let summary = data.map(item => returnNum((item.planHour || 0)) + returnNum((item.realHour || 0)))
+        let actualPlan = data.map(item => returnNum((item.planHour || 0))) // 实际计划
+        let actualSupplement = data.map(item => returnNum((item.afterSetPlanHour || 0))) // 实际增补
+        let summary = data.map(item => returnNum((item.realHour || 0))) // 汇总
+        // let summary = data.map(item => returnNum((item.planHour || 0)) + returnNum((item.realHour || 0))) // 汇总
         this.groupConsumptionOption = getGroupConsumption(nameList, actualPlan, actualSupplement, summary, realHourList)
 
         function returnNum(num) {
@@ -4548,4 +4677,15 @@ export default {
 .useASchedule {
   width: 100%;
 }
+
+.packetConsumption {
+  width: 100%;
+  display: flex;
+  &>div {
+    height: 100%;
+  }
+  .packetConsumption-flex {
+    flex: 1;
+  }
+}
 </style>

+ 370 - 0
fhKeeper/formulahousekeeper/timesheet/src/views/corpreport/packetConsumption/tables.vue

@@ -0,0 +1,370 @@
+<template>
+  <div class="tabless">
+    <!-- 表格 -->
+    <template v-if="tabPosition != '1'">
+      <template v-if="types != 'all'">
+        <el-table :key="typesDataObj[types].tableKey" border :data="tableList" highlight-current-row :height="(+tableHeight - 0) - 1" style="width: 100%;" :span-method="objectSpanMethod" show-summary :summary-method="getSummaries" v-loading="tableLoading">
+          <el-table-column align="center" prop="departmentName" :label="'所属部门'" min-width="200" fixed="left">
+            <template slot-scope="scope">
+              <template v-for="(list, listIndex) in scope.row.departmentNameList">
+                <TranslationOpenDataText type='departmentName' :openid='list'></TranslationOpenDataText> <template v-if="listIndex < scope.row.departmentNameList.length - 1">/</template>
+              </template>
+            </template>
+          </el-table-column>
+          <el-table-column align="center" prop="userName" :label="'员工'" min-width="150" fixed="left">
+            <template slot-scope="scope">
+              <TranslationOpenDataText type='userName' :openid='scope.row.userName'></TranslationOpenDataText>
+            </template>
+          </el-table-column>
+          <el-table-column align="center" prop="jobNumber" :label="'工号'" min-width="150"></el-table-column>
+          <template v-for="(item, index) in typesDataObj[types].tableFileds">
+            <el-table-column align="center" :prop="item.filed" :label="`${item.label}${item.unit ? '' : '(h)'}`" min-width="170">
+              <template slot-scope="scope">
+                <div>
+                  <span v-if="!item.unit">{{ scope.row[item.filed] }}</span> 
+                  <el-progress :text-inside="true" :stroke-width="26" :percentage="scope.row[item.filed] || 0" :color="'#a7cef9'" v-else></el-progress>
+                </div>
+              </template>
+            </el-table-column>
+          </template>
+          <el-table-column align="center" prop="totalWorkTime" :label="'总计(h)'" min-width="150">
+            <template slot-scope="scope">
+              <div>
+                {{ scope.row['totalWorkTime'] }}
+              </div>
+            </template>
+          </el-table-column>
+        </el-table>
+      </template>
+
+      <!-- 单个 -->
+      <template v-if="types == 'all'">
+        <el-table :key="24" border :data="tableList" highlight-current-row :height="(+tableHeight - 0) - 1" style="width: 100%;" :span-method="objectSpanMethod">
+          <el-table-column align="center" prop="projectName" :label="$t('headerTop.projectName')" min-width="200"></el-table-column>
+          <el-table-column align="center" prop="department_name" :label="$t('fuZeBuMen')" min-width="150">
+            <template slot-scope="scope">
+              <div>
+                <span v-if="user.userNameNeedTranslate == '1'">
+                  <TranslationOpenDataText type='departmentName' :openid='scope.row.corpwxDeptId'></TranslationOpenDataText>
+                </span>
+                <span v-if="user.userNameNeedTranslate != '1'">
+                  {{scope.row.departmentName}}
+                </span>
+              </div>
+            </template>
+          </el-table-column>
+          <el-table-column align="center" prop="groupName" :label="$t('lable.taskGrouping')" min-width="150"></el-table-column>
+          <el-table-column align="center" prop="planHour" :label="$t('jiHuaGongShiCaiWu')" width="120"></el-table-column>
+          <el-table-column align="center" :label="$t('shiJiGongShiChengBen')">
+            <el-table-column align="center" prop="afterSetPlanHour" :label="$t('zengBuGongShiH')" width="120"></el-table-column>
+            <el-table-column align="center" prop="normalHour" :label="$t('zhengChangGongShiH')" width="100"></el-table-column>
+            <el-table-column align="center" prop="overHour" :label="$t('jiaBanGongShiH')" width="100"></el-table-column>
+            <el-table-column align="center" prop="realHour" :label="$t('heJiGongShiH')" width="100"></el-table-column>
+            <el-table-column align="center" prop="realCost" :label="$t('heJiGongShiChengBen')" width="140"></el-table-column>
+          </el-table-column>
+          <el-table-column align="center" prop="process" :label="$t('gongShiHaoYongShuai')" width="150"></el-table-column>
+        </el-table>
+      </template>
+    </template>
+
+    <!-- 图表 -->
+    <template v-if="tabPosition == '1'">
+      <template v-if="echartTableType == '图表'">
+        <div ref="echartsRef" :style="`width: 100%;height: ${tableHeight - 0}px;`" v-loading="echartsLoading">
+          <EchartsEchar :options="echartsEcharData" :key="echartsKey"></EchartsEchar>
+        </div>
+      </template>
+      <template v-if="echartTableType == '表格'">
+        <el-table :data="echartsTableData" border style="width: 100%" :height="(+tableHeight - 0) - 1" v-loading="echartsLoading" show-summary :summary-method="getSummaries">
+          <el-table-column prop="projectCode" label="项目编号"></el-table-column>
+          <el-table-column prop="projectName" label="项目名称"></el-table-column>
+          <el-table-column prop="workTime" label="时长(h)" width="180"></el-table-column>
+        </el-table>
+      </template>
+      <div class="echarts-table" v-if="types != 'all'">
+        <el-radio-group v-model="echartTableType" size="small">
+          <el-radio-button label="表格"></el-radio-button>
+          <el-radio-button label="图表"></el-radio-button>
+        </el-radio-group>
+        </div>
+    </template>
+  </div>
+</template>
+
+<script>
+import { debounce, fixedGrouping, getPieEchartOption, getProportion, collectNUm } from "../echartsData.js";
+import EchartsEchar from "@/components/echartsEchar.vue"
+export default {
+  props: {
+    datas: { type: Object, default: () => {} },
+    tabType: { type: String, default: () => "all" },
+  },
+  components: {
+    EchartsEchar
+  },
+  data() {
+    return {
+      user: JSON.parse(sessionStorage.user),
+      permissions: JSON.parse(sessionStorage.getItem("permissions")),
+      types: "all",
+      tableList: [],
+      timer: null,
+      tableHeight: 0,
+      tabPosition: '0',
+      list1: [],
+      listArr1: [],
+      listArr2: [],
+      listArr3: [],
+      echartsWidth: 0,
+      listPosition1: [],
+      tableLoading: false,
+      echartsLoading: false,
+      echartsEcharData: {},
+      typesDataObj: fixedGrouping,
+      echartsTableData: [],
+      echartsKey: 1,
+      echartTableType: '图表',
+      returnedValueItem: {}
+    };
+  },
+  computed: {},
+  watch: {
+    datas(newVal) {
+      const { type, regular, tabPosition } = newVal
+      this.types = type;
+      this.tabPosition = tabPosition
+      this.handleWatchTabDatas(newVal);
+    },
+  },
+  created() {},
+  mounted() {
+  },
+  methods: {
+    handleWatchTabDatas(newVal) {
+      const { type, list, regular, height, tabPosition, params, listArr1, listArr2, listArr3, echartsData = {} } = newVal;
+      this.tableHeight = height;
+      this.tableList = []
+      this.echartTableType = '图表'
+      if(type == regular && tabPosition == '0') {
+        this.getTableList(params)
+      }
+      if(type == regular && tabPosition == '1') {
+        this.getEchartsData(params)
+      }
+      if (type == "all") {
+        this.echartsKey++
+        this.listArr1 = listArr1
+        this.listArr2 = listArr2
+        this.listArr3 = listArr3
+        this.echartsEcharData = echartsData
+        setTimeout(() => {  
+          this.tableList = list;
+        }, 200)
+      }
+    },
+    async getEchartsData(params) {
+      const { groupNames, dataTime = [], projectIds } = params
+      const type = this.types
+      const row = fixedGrouping[type]
+      this.echartsLoading = true
+      let res = await this.postData('/project/groupExpendProcessListForProject', {
+        projectIds,
+        startDate: dataTime[0] || '',
+        endDate: dataTime[1] || '',
+        deptIdStr: row.deptIds,
+        groupNames
+      })
+      this.echartsKey++
+      this.echartsLoading = false
+      const dataList = res.data.record
+      this.echartsTableData = dataList
+      const list = fixedGrouping[type].tabPicFileds
+      const item = list.find(item => item.filed == groupNames)
+      const strList = fixedGrouping[type].proportion.map(item => item.key)
+      const datas = dataList.map(item => {
+        return {
+          name: `${item.projectName} ${item.percent}`,
+          value: item.workTime,
+          fledStrList: [...new Set(strList)]
+        }
+      })
+      this.echartsEcharData = getPieEchartOption(item.title, datas)
+    },
+    async getTableList(params) {
+      const { dataTime = [], projectIds } = params
+      const type = this.types
+      const row = fixedGrouping[type]
+      this.tableLoading = true
+      let groupNames = this.typesDataObj[this.types].tableFileds.map(item => item.label).join(',')
+      let { data } = await this.postData('/project/groupExpendProcessListForUser', {
+        projectIds,
+        startDate: dataTime[0] || '',
+        endDate: dataTime[1] || '',
+        deptIdStr: row.deptIds,
+        groupNames
+      })
+      this.tableLoading = false
+      this.listArr1 = []
+      this.listArr2 = []
+      this.listArr3 = []
+      this.listPosition1 = 0
+      this.listPosition2 = 0
+      this.listPosition3 = 0
+      const strList = fixedGrouping[type].proportion.map(item => item.key)
+      let dataList = data.record.map(item => {
+        return {
+          ...item,
+          departmentNameList: item.departmentName.split('/'),
+          fledStrList: [...new Set(strList)]
+        }
+      })
+      // console.log(collectNUm(dataList, this.types), '<===== 返回的数据 ============>')
+      this.returnedValueItem = collectNUm(dataList, this.types)
+      this.tableList = getProportion(dataList, this.types)
+      this.typesDataObj[this.types].tableKey = this.randomInt()
+      console.log(this.tableList, '<====== 返回最终的数据')
+    },
+    objectSpanMethod({ row, column, rowIndex, columnIndex }){
+      const { companyId } = this.user
+      if(columnIndex == 0 && this.listArr1.length > 0){
+        const _row = this.listArr1[rowIndex]
+        const _col = _row > 0 ? 1 : 0
+        return {
+          rowspan: _row,
+          colspan: _col
+        }
+      }
+      if(columnIndex == 1 && this.listArr2.length > 0){
+        const _row = this.listArr2[rowIndex]
+        const _col = _row > 0 ? 1 : 0
+        return {
+          rowspan: _row,
+          colspan: _col
+        }
+      }
+      if(columnIndex == 2 && companyId == '3092' && this.listArr3.length > 0) {
+        const _row = this.listArr3[rowIndex]
+        const _col = _row > 0 ? 1 : 0
+        return {
+          rowspan: _row,
+          colspan: _col
+        }
+      }
+    },
+    // 单独封装请求
+    async postData(urls, param) {
+      return new Promise((resolve, reject) => {
+        this.http.post(urls, { ...param },
+          res => {
+            if(res.code == 'ok') {
+              resolve(res)
+            } else {
+              this.$message({
+                message: res.msg,
+                type: 'error'
+              })
+              reject(res)
+            }
+            resolve(res)
+          },
+          error => {
+            this.$message({
+              message: error,
+              type: "error"
+            });
+            reject(error)
+          }
+        )
+      });
+    },
+    groupByJobNumber(data) {
+        let groupedData = [];
+        data.reduce((acc, obj) => {
+            let found = acc.find(item => item.jobNumber === obj.jobNumber);
+            if (found) {
+                found.list.push(obj);
+            } else {
+                acc.push({ 
+                  jobNumber: obj.jobNumber, 
+                  userName: obj.userName, 
+                  departmentName: obj.departmentName, 
+                  workTime: obj.workTime,
+                  list: [obj],
+                });
+            }
+            return acc;
+        }, groupedData);
+        return groupedData;
+    },
+    rowspan(spanArr,position,spanName,dataItem = [],fields=false){
+      let newArray = dataItem.length > 0 ? dataItem : this.tableList
+      newArray.forEach((item,index) => {
+        if(index == 0){
+          spanArr.push(1)
+          position = 0
+        }else {
+          let newArrFlag = newArray[index][spanName] == newArray[index-1][spanName] && (!fields || newArray[index][fields] == newArray[index-1][fields]);
+          // if(newArray[index][spanName] == newArray[index-1][spanName]){
+          if(newArrFlag){
+            spanArr[position] += 1
+            spanArr.push(0)
+          }else {
+            spanArr.push(1)
+            position = index
+          }
+        }
+      })
+    },
+    // 随机整数
+    randomInt(min = 1, max = 10000) {
+      return Math.floor(Math.random() * (max - min + 1) + min);
+    },
+    getSummaries(param) {
+      const { columns, data } = param;
+      const sums = [];
+      const strList = (data[0] && data[0].fledStrList) || []
+      const totalNum = this.returnedValueItem.totalNum
+      columns.forEach((column, index) => {
+        if (index === 0) {
+          sums[index] = '总计';
+          return;
+        }
+        if (strList.includes(column.property)) {
+          let val = this.returnedValueItem[column.property]
+          let num = (val / totalNum) * 100
+          sums[index] = Number(num.toFixed(2)) + '%';
+          return
+        }
+        const values = data.map(item => Number(item[column.property]));
+        if (!values.every(value => isNaN(value))) {
+          sums[index] = values.reduce((prev, curr) => {
+            const value = Number(curr);
+            if (!isNaN(value)) {
+              return prev + curr;
+            } else {
+              return prev;
+            }
+          }, 0);
+          sums[index] += ' h';
+        } else {
+          sums[index] = ' ';
+        }
+      });
+
+      return sums;
+    }
+  },
+};
+</script>
+
+<style scoped lang="scss">
+.tabless {
+  width: 100%;
+  height: 100%;
+}
+.echarts-table {
+  position: fixed;
+  bottom: 15px;
+  right: 38px;
+}
+</style>

+ 7 - 3
fhKeeper/formulahousekeeper/timesheet/src/views/project/info.vue

@@ -127,8 +127,12 @@
                         <span v-if="user.userNameNeedTranslate != 1">{{project.reviwerName}}</span>
                         <span v-else><TranslationOpenDataText type='userName' :openid='project.reviwerName'></TranslationOpenDataText></span>
                     </el-link></div>
-                    <div v-if="user.timeType.reportAuditType != 8" style="margin-top:10px;color:#999;">{{ user.timeType.reportCc == 1?'日报抄送人':$t('newspaperauditor') }}</div>
-                    <div v-if="user.timeType.reportAuditType != 8">
+                    <!-- <div v-if="user.timeType.reportAuditType != 8" style="margin-top:10px;color:#999;"> -->
+                    <div v-if="user.timeType.reportAuditType == 0 || user.timeType.reportAuditType == 4 || user.timeType.reportAuditType == 6" style="margin-top:10px;color:#999;">
+                        {{ user.timeType.reportCc == 1?'日报抄送人':$t('newspaperauditor') }}
+                    </div>
+                    <!-- <div v-if="user.timeType.reportAuditType != 8"> -->
+                    <div v-if="user.timeType.reportAuditType == 0 || user.timeType.reportAuditType == 4 || user.timeType.reportAuditType == 6">
                         <span v-if="project.auditorList.length == 0" style="margin:10px;">-</span>
                         <el-link v-for="item in project.auditorList" :key="item.id" style="margin:10px;" @click="showUser(item.auditorId)">
                             <span v-if="user.userNameNeedTranslate != 1">
@@ -222,7 +226,7 @@
                         </el-col>
                         <el-col :span="4" style="text-align:center;">
                             <p style="color:#666;font-size:12px;">{{ $t('dai-ren-ling') }}</p>
-                            <p style="font-size:20px;color:#orange;font-weight:bold;">{{taskSum.unassignCount}}</p>
+                            <p style="font-size:20px;color:orange;font-weight:bold;">{{taskSum.unassignCount}}</p>
                         </el-col>
                         <el-col :span="4" style="text-align:center;">
                             <p style="color:#666;font-size:12px;">{{ $t('duetoday') }}</p>

+ 73 - 1
fhKeeper/formulahousekeeper/timesheet/src/views/team/index.vue

@@ -236,6 +236,7 @@
                 <el-table-column :label="$t('jiao-se')" width="100">
                     <template slot-scope="scope">{{scope.row.roleName}}</template>
                 </el-table-column>
+                <el-table-column label="分组" prop="groupName" width="150" v-if="permissions.userGroupManage"></el-table-column>
                 <el-table-column prop="monthCost" :label="$t('monthcost')" align="right" v-if="permissions.structurePersonnel" width="140">
                     <template slot-scope="scope">{{user.timeType.isSecretSalary==0?(scope.row.monthCost==null?0:scope.row.monthCost.toFixed(2)):'*'}} {{ $t('yuan') }}</template>
                 </el-table-column>
@@ -279,6 +280,7 @@
                 <el-button size="small" type="primary" @click="handJue">{{ $t('modifyingRoles') }}</el-button>
                 <el-button size="small" type="primary" @click="workingHoursDialogClick()">{{ $t('xiuZhengGongShiSuoShuBuMen') }}</el-button>
                 <el-button size="small" type="primary" @click="handleSelectionUser()">{{ $t('piLiangQiYongYuanGong') }}</el-button>
+                <el-button size="small" type="primary" v-if="permissions.userGroupManage" @click="showUserGroupVisable()">批量修改分组</el-button>
                
                 
                 
@@ -348,6 +350,21 @@
             </div>
         </el-dialog>
 
+        <!-- 批量修改用户分组 -->
+        <el-dialog :title="$t('changes')" :visible.sync="userGroupVisable" v-if="userGroupVisable" width="600px">
+            <el-form model="" label-width="20%">
+                <el-form-item label="用户分组">
+                    <el-select v-model="userGroupId" :placeholder="$t('defaultText.pleaseChoose')" style="width: 100%">
+                        <el-option v-for="(item, index) in userGroupList" :key="index" :label="item.groupName" :value="item.id"></el-option>
+                    </el-select>
+                </el-form-item>
+            </el-form>
+            <div slot="footer" class="dialog-footer">
+                <el-button @click="userGroupVisable = false">{{ $t('btn.cancel') }}</el-button>
+                <el-button type="primary" :disabled="!userGroupId" :loading="userGroupLoading" @click="editUserGroup()">{{ $t('btn.determine') }}</el-button>
+            </div>
+        </el-dialog>
+
         <!-- 新增部门 -->
         <el-dialog :title="depTitle" :visible.sync="departmentVisible" width="500px" >
             <el-form ref="depForm" :model="depForm" :rules="depRules" label-width="100px">
@@ -478,6 +495,11 @@
                           </el-option>
                       </el-select>
                   </el-form-item>
+                  <el-form-item label="用户分组" prop="groupId" v-if="permissions.userGroupManage">
+                    <el-select v-model="insertForm.groupId" :placeholder="$t('defaultText.pleaseChoose')" style="width: 100%">
+                      <el-option v-for="item in userGroupList" :label="item.groupName" :value="item.id" :key="item.id"></el-option>
+                    </el-select>
+                  </el-form-item>
                   <el-form-item :label="item.name" v-for="item,index in userCustomConfig" :key="item.id">
                       <el-select v-if="item.type == 0" v-model="insertForm[suoying[index]]" :placeholder="$t('defaultText.pleaseChoose')" clearable style="width: 100%">
                           <el-option v-for="option in item.itemList" :label="option.name" :value="option.name" :key="option.id">
@@ -1170,6 +1192,12 @@ export default {
       whiteListAll: [],
       whiteListAllTwo: [],
       specialHolidaysDialog: false,
+
+      // 用户分组
+      userGroupList: [],
+      userGroupId: '',
+      userGroupVisable: false,
+      userGroupLoading: false,
     };
   },
   watch: {
@@ -2861,7 +2889,8 @@ export default {
                 plate5: res.data.plate5,
                 jobNumber: res.data.jobNumber,
                 onlyAuditOnce: res.data.onlyAuditOnce,
-                reportDeptIdsList: res.data.userReportDeptList || []
+                reportDeptIdsList: res.data.userReportDeptList || [],
+                groupId: res.data.userGroupId || ''
               };
               this.$set(this.insertForm, 'inductionDate', res.data.inductionDate)
               this.getUserCustomConfig(1);
@@ -2977,6 +3006,9 @@ export default {
           // }
 
           // console.log(form, 'form')
+          if(this.permissions.userGroupManage) {
+            form.groupId = this.insertForm.groupId;
+          } 
 
           if (this.insertForm.id != null) {
             form.id = this.insertForm.id;
@@ -3867,6 +3899,15 @@ export default {
             }
         },error => {})
     },
+    getUserGrpupList() {
+      this.http.post('/user-group/list',{
+        },res => {
+            if(res.code == 'ok'){
+                let list = res.data
+                this.userGroupList = list
+            }
+        },error => {})
+    },
     // 企业微信选人搜索
     echartDepartment() {
         if(this.wxFilterText != '') {
@@ -3932,6 +3973,34 @@ export default {
         if (!value) return true;
         return data.label.indexOf(value) !== -1;
     },
+    showUserGroupVisable() {
+      if (this.handleSelectionZzjgDate.length == 0) {
+        this.$message(this.$t('pleaseselectpersonnel'));
+        return;
+      }
+      this.userGroupId = ''
+      this.userGroupVisable = true
+    },
+    editUserGroup() {
+      this.userGroupLoading = true
+      let ids = this.handleSelectionZzjgDate.map(item => item.id).join(',')
+      this.http.post("/user/batchSetUserGroup", {
+        userIds: ids,
+        groupId: this.userGroupId
+      },
+      res => {
+        this.userGroupLoading = false
+        if (res.code == "ok") {
+          this.$message({
+              message: this.$t('caoZuoChengGong'),
+              type: "success"
+          });
+          this.userGroupVisable = false
+          this.getUser()
+        }
+      },
+      error => { this.userGroupLoading = false });
+    }
   },
   mounted() {
     this.deactiveDate = util.formatDate.format(new Date(), "yyyy-MM-dd");
@@ -3951,6 +4020,9 @@ export default {
     }
     this.statesPush();
     this.getWhiteListAll()
+    if(this.permissions.userGroupManage) {
+      this.getUserGrpupList()
+    }
     // 获取企业微信的参数
     // if(this.user.companyId == '1081' || this.user.companyId == '7') {
     //   this.agentConfig()

+ 231 - 0
fhKeeper/formulahousekeeper/timesheet/src/views/userGrouping/userGrouping.vue

@@ -0,0 +1,231 @@
+<template>
+  <div class="userGroping">
+    <div class="userGroping-title">
+      <div>用户分组管理</div>
+      <div>
+        <el-button type="text" icon="el-icon-circle-plus-outline" @click="showGroupVisable()">创建分组</el-button>
+      </div>
+    </div>
+    <div class="userGroping-table">
+      <el-table :data="tableData" border v-loading="tableLoading" style="width: 100%; height: 100%">
+        <el-table-column align="center" prop="groupName" label="分组名称"></el-table-column>
+        <el-table-column align="center" prop="noProjectPercent" label="非项目工时占比上限(%)"></el-table-column>
+        <el-table-column align="center" prop="operation" label="操作" width="160">
+          <template slot-scope="scope">
+            <el-button size="small" @click="showGroupVisable(scope.row)">编辑</el-button>
+            <el-button size="small" type="danger" @click="deteleGroup(scope.row)">删除</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+
+    <!-- 创建/编辑分组 -->
+    <el-dialog title="新增/编辑分组" :visible.sync="editGroupVisable" width="800px" :before-close="handleClose">
+      <div class="groupForm">
+        <div class="groupFormItem">
+          <div class="label">分组名称</div>
+          <el-input v-model.trim="editGroupForm.groupName" size="small" placeholder="请输入" clearable
+            class="flex1"></el-input>
+        </div>
+        <div class="groupFormItem">
+          <div class="label">非项目占比(%)</div>
+          <el-input-number v-model="editGroupForm.noProjectPercent" size="small" controls-position="right"
+            :precision="0" :min="0" :max="100" class="flex1 textNumber" style="text-align: left;"></el-input-number>
+        </div>
+      </div>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="editGroupVisable = false">取 消</el-button>
+        <el-button type="primary" @click="editGroup()" :loading="editGroupBtnLoading"
+          :disabled="editGroupForm.groupName && !editGroupForm.noProjectPercent">确 定</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+export default {
+  props: {},
+  components: {},
+  data() {
+    return {
+      prefix: "/user-group/",
+      tableLoading: false,
+      editGroupVisable: false,
+      editGroupBtnLoading: false,
+      tableData: [],
+      editGroupForm: {
+        id: '',
+        companyId: '',
+        groupName: '',
+        noProjectPercent: 0,
+      }
+    };
+  },
+  computed: {},
+  watch: {},
+  created() { },
+  mounted() {
+    this.getTableList()
+  },
+  methods: {
+    deteleGroup(row) {
+      this.$confirm(`确定删除【${row.groupName}】?`, '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        this.postData("delete", { id: row.id }).then(res => {
+          if (res.code != 'ok') {
+            this.messages(res.msg)
+            return
+          }
+          this.messages('删除成功', 'success')
+          this.getTableList()
+        })
+      });
+    },
+    editGroup() {
+      let formVal = this.getFromValue(this.editGroupForm)
+      this.editGroupBtnLoading = true
+      this.postData("addOrUpdate", { ...formVal }).then(res => {
+        if (res.code != 'ok') {
+          this.messages(res.msg)
+          return
+        }
+        this.messages('创建成功', 'success')
+        this.editGroupVisable = false
+        this.getTableList()
+      }).finally(() => {
+        this.editGroupBtnLoading = false
+      });
+    },
+    getTableList() {
+      this.tableLoading = true
+      this.postData("list", {}).then(res => {
+        if (res.code != 'ok') {
+          this.messages(res.msg)
+          return
+        }
+        this.tableData = res.data
+      }).finally(() => {
+        this.tableLoading = false
+      });
+    },
+    showGroupVisable(row = false) {
+      if (!row) {
+        // 清空
+        this.editGroupForm = {
+          id: '',
+          companyId: '',
+          groupName: '',
+          noProjectPercent: 0,
+        }
+        this.editGroupVisable = true
+        return
+      }
+
+      this.editGroupForm = {
+        ...row,
+        noProjectPercent: row.noProjectPercent || 0
+      }
+      this.editGroupVisable = true
+    },
+
+    messages(test = '', type = "error") {
+      this.$message({
+        message: test,
+        type: type,
+      });
+    },
+    getFromValue(formData) {
+      const result = {};
+      for (const key in formData) {
+        if (formData[key]) {
+          result[key] = formData[key];
+        }
+      }
+      return result;
+    },
+    // 封装 post 请求
+    postData(url, params) {
+      return new Promise((resolve, reject) => {
+        this.http.post(`${this.prefix}${url}`, { ...params }, (res) => {
+          resolve(res);
+        }, (error) => {
+          this.$message({
+            message: error,
+            type: "error",
+          });
+          this.messages(error)
+          reject(error);
+        }
+        );
+      });
+    },
+  },
+};
+</script>
+
+<style scoped lang="scss">
+.userGroping {
+  width: 100%;
+  height: 100%;
+  box-sizing: border-box;
+  display: flex;
+  flex-direction: column;
+
+  .userGroping-title {
+    background: #f2f2f2;
+    padding: 10px 20px;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+  }
+
+  .userGroping-table {
+    flex: 1;
+  }
+
+  .groupForm {
+    .groupFormItem {
+      margin-bottom: 15px;
+      display: flex;
+      align-items: center;
+      flex-direction: row;
+
+      &:last-child {
+        margin-bottom: 0;
+      }
+
+      .label {
+        width: 120px;
+        text-align: right;
+        margin-right: 10px;
+      }
+
+      .textNumber {
+        text-align: left;
+      }
+
+      .flex1 {
+        flex: 1;
+      }
+    }
+  }
+
+  div {
+    box-sizing: border-box;
+  }
+
+
+}
+</style>
+<style lang="scss">
+.userGroping {
+  .groupFormItem {
+    .el-input-number .el-input__inner {
+      text-align: left !important;
+    }
+  }
+}
+</style>

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

@@ -915,7 +915,7 @@
                         }
                         this.listBackup = JSON.parse(JSON.stringify(res.data));
                         console.log(this.listBackup, "《====== 赋值")
-                        this.list = this.currentChangePage(10, 1, res.data);
+                        this.list = this.currentChangePage(this.reviewTableObj.reviewTableSize, 1, res.data);
                         let total = res.data.length || 0
                         this.reviewTableObj = {
                             reviewTableTotal: total,