Kaynağa Gözat

Merge remote-tracking branch 'origin/master'

# Conflicts:
#	fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/ExpenseSheet.java
yusm 1 yıl önce
ebeveyn
işleme
5de5d5c6db
100 değiştirilmiş dosya ile 5998 ekleme ve 872 silme
  1. 54 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/CategoryRatioTblSettingController.java
  2. 2 2
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/DepartmentController.java
  3. 71 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ExpenseItemController.java
  4. 37 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ExpensePayWayController.java
  5. 10 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ExpenseSheetController.java
  6. 102 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/GroupBudgetReviewController.java
  7. 50 4
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ProjectAuditorController.java
  8. 10 6
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ProjectController.java
  9. 12 2
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ReportController.java
  10. 1 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/SapProjectServiceController.java
  11. 53 15
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/TaskController.java
  12. 82 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/UserWithBeisenController.java
  13. 6 3
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/WeiXinCorpController.java
  14. 56 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/CategoryRatioTblSetting.java
  15. 8 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/Company.java
  16. 42 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/ExpensePayWay.java
  17. 14 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/ExpenseSheet.java
  18. 111 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/GroupBudgetReview.java
  19. 4 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/SapProjectService.java
  20. 6 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/TaskExecutor.java
  21. 66 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/UserWithBeisen.java
  22. 2 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/vo/ExpenseItemVO.java
  23. 16 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/vo/UserCateTimeVo.java
  24. 16 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/CategoryRatioTblSettingMapper.java
  25. 16 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/ExpensePayWayMapper.java
  26. 16 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/GroupBudgetReviewMapper.java
  27. 4 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/ProjectMapper.java
  28. 5 2
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/ReportMapper.java
  29. 2 2
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/TaskMapper.java
  30. 16 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/UserWithBeisenMapper.java
  31. 16 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/CategoryRatioTblSettingService.java
  32. 1 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/DepartmentService.java
  33. 16 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/ExpensePayWayService.java
  34. 16 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/GroupBudgetReviewService.java
  35. 5 3
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/ProjectService.java
  36. 4 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/ReportService.java
  37. 1 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/TaskService.java
  38. 16 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/UserWithBeisenService.java
  39. 20 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/CategoryRatioTblSettingServiceImpl.java
  40. 144 62
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/DepartmentServiceImpl.java
  41. 13 2
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ExcelExportServiceImpl.java
  42. 20 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ExpensePayWayServiceImpl.java
  43. 28 12
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ExpenseSheetServiceImpl.java
  44. 20 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/GroupBudgetReviewServiceImpl.java
  45. 43 11
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/LeaveSheetServiceImpl.java
  46. 6 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/PermissionServiceImpl.java
  47. 464 127
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ProjectServiceImpl.java
  48. 427 117
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ReportServiceImpl.java
  49. 98 37
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/TaskServiceImpl.java
  50. 37 11
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/UserServiceImpl.java
  51. 20 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/UserWithBeisenServiceImpl.java
  52. 119 49
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/task/TimingTask.java
  53. 103 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/util/BeiSenUtils.java
  54. 70 43
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/util/SyncSapUtils.java
  55. 2 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/util/WebServiceUtils.java
  56. 37 15
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/util/WorkDayCalculateUtils.java
  57. 6 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/webservice/po/ProcessingConditions.java
  58. 4 2
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/webservice/po/ProjectSelectionByElement.java
  59. 17 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/webservice/po/Sales.java
  60. 6 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/webservice/po/ServiceProduct.java
  61. 1 1
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/application.yml
  62. 18 0
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/CategoryRatioTblSettingMapper.xml
  63. 2 1
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/CompanyMapper.xml
  64. 2 1
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/DepartmentMapper.xml
  65. 7 4
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/ExpenseItemMapper.xml
  66. 17 0
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/ExpensePayWayMapper.xml
  67. 3 1
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/ExpenseSheetMapper.xml
  68. 28 0
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/GroupBudgetReviewMapper.xml
  69. 17 4
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/ProjectMapper.xml
  70. 61 5
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/ReportMapper.xml
  71. 2 1
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/SapProjectServiceMapper.xml
  72. 7 1
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/TaskMapper.xml
  73. 20 0
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/UserWithBeisenMapper.xml
  74. 28 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/controller/ReportController.java
  75. 7 1
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/entity/Plan.java
  76. 6 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/mapper/ReportMapper.java
  77. 10 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/ReportService.java
  78. 4 0
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/impl/PlanProcedureTotalServiceImpl.java
  79. 71 24
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/impl/PlanServiceImpl.java
  80. 851 52
      fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/impl/ReportServiceImpl.java
  81. 2 1
      fhKeeper/formulahousekeeper/management-workshop/src/main/resources/mapper/PlanMapper.xml
  82. 117 61
      fhKeeper/formulahousekeeper/management-workshop/src/main/resources/mapper/ReportMapper.xml
  83. 13 3
      fhKeeper/formulahousekeeper/timesheet-workshop-h5/src/views/statisticsView/statisticsView.vue
  84. 42 13
      fhKeeper/formulahousekeeper/timesheet-workshop-h5/src/views/workView/fillReport.vue
  85. 1 1
      fhKeeper/formulahousekeeper/timesheet-workshop-h5/src/views/workView/workView.vue
  86. 262 17
      fhKeeper/formulahousekeeper/timesheet-workshop/src/views/statistic/index.vue
  87. BIN
      fhKeeper/formulahousekeeper/timesheet/src/assets/image/pdfIcon.png
  88. 16 3
      fhKeeper/formulahousekeeper/timesheet/src/components/select.vue
  89. 12 12
      fhKeeper/formulahousekeeper/timesheet/src/components/taskComponent.vue
  90. 2 1
      fhKeeper/formulahousekeeper/timesheet/src/i18n/zh.json
  91. 11 0
      fhKeeper/formulahousekeeper/timesheet/src/permissions.js
  92. 16 0
      fhKeeper/formulahousekeeper/timesheet/src/routes.js
  93. 18 0
      fhKeeper/formulahousekeeper/timesheet/src/views/Login.vue
  94. 445 32
      fhKeeper/formulahousekeeper/timesheet/src/views/corpreport/list.vue
  95. 125 22
      fhKeeper/formulahousekeeper/timesheet/src/views/expense/expense.vue
  96. 739 0
      fhKeeper/formulahousekeeper/timesheet/src/views/project/budgetReview.vue
  97. 27 13
      fhKeeper/formulahousekeeper/timesheet/src/views/project/cost.vue
  98. 198 39
      fhKeeper/formulahousekeeper/timesheet/src/views/project/list.vue
  99. 121 21
      fhKeeper/formulahousekeeper/timesheet/src/views/project/projectInside.vue
  100. 0 0
      fhKeeper/formulahousekeeper/timesheet/src/views/task/list.vue

+ 54 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/CategoryRatioTblSettingController.java

@@ -0,0 +1,54 @@
+package com.management.platform.controller;
+
+
+import com.management.platform.entity.CategoryRatioTblSetting;
+import com.management.platform.service.CategoryRatioTblSettingService;
+import com.management.platform.util.HttpRespMsg;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * <p>
+ *  前端控制器
+ * </p>
+ *
+ * @author Seyason
+ * @since 2024-01-01
+ */
+@RestController
+@RequestMapping("/category-ratio-tbl-setting")
+public class CategoryRatioTblSettingController {
+
+    @Resource
+    private HttpServletRequest request;
+
+    @Resource
+    private CategoryRatioTblSettingService categoryRatioTblSettingService;
+
+    @RequestMapping("/get")
+    public HttpRespMsg get(Integer companyId) {
+        HttpRespMsg msg = new HttpRespMsg();
+        CategoryRatioTblSetting byId = categoryRatioTblSettingService.getById(companyId);
+        if (byId == null) {
+            byId = new CategoryRatioTblSetting();
+            byId.setCompanyId(companyId);
+        }
+        msg.setData(byId);
+        return msg;
+    }
+
+    @RequestMapping("/update")
+    public HttpRespMsg update(CategoryRatioTblSetting categoryRatioTblSetting) {
+        HttpRespMsg msg = new HttpRespMsg();
+        categoryRatioTblSettingService.saveOrUpdate(categoryRatioTblSetting);
+        return msg;
+    }
+
+
+}
+

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

@@ -132,8 +132,8 @@ public class DepartmentController {
      * departmentId 要查询的项目
      */
     @RequestMapping("/exportUserStatistic")
-    public HttpRespMsg exportUserStatistic(String startDate, String endDate, String userIds, HttpServletRequest request) {
-        return departmentService.exportUserStatistic(startDate, endDate, userIds, request);
+    public HttpRespMsg exportUserStatistic(boolean mainProjectColumn, String startDate, String endDate, String userIds, HttpServletRequest request) {
+        return departmentService.exportUserStatistic(mainProjectColumn, startDate, endDate, userIds, request);
     }
 
 

+ 71 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ExpenseItemController.java

@@ -1,16 +1,26 @@
 package com.management.platform.controller;
 
 
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.management.platform.entity.ExpenseItem;
+import com.management.platform.entity.WxCorpInfo;
 import com.management.platform.entity.vo.ExpenseItemVO;
 import com.management.platform.mapper.ExpenseItemMapper;
+import com.management.platform.mapper.UserMapper;
+import com.management.platform.mapper.WxCorpInfoMapper;
+import com.management.platform.service.ExcelExportService;
 import com.management.platform.util.HttpRespMsg;
+import com.management.platform.util.MessageUtils;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.web.bind.annotation.RequestMapping;
 
 import org.springframework.web.bind.annotation.RestController;
 
 import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import java.math.BigDecimal;
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -27,6 +37,16 @@ public class ExpenseItemController {
 
     @Resource
     private ExpenseItemMapper expenseItemMapper;
+    @Resource
+    private UserMapper userMapper;
+    @Resource
+    private HttpServletRequest request;
+    @Resource
+    private WxCorpInfoMapper wxCorpInfoMapper;
+    @Resource
+    private ExcelExportService excelExportService;
+    @Value(value = "${upload.path}")
+    private String path;
 
     @RequestMapping("/list")
     public HttpRespMsg list(Integer projectId) {
@@ -35,5 +55,56 @@ public class ExpenseItemController {
         msg.data = userExpenseDetail;
         return msg;
     }
+
+    @RequestMapping("/exportData")
+    public HttpRespMsg exportData(Integer projectId) {
+        HttpRespMsg msg = new HttpRespMsg();
+        Integer companyId = userMapper.selectById(request.getHeader("token")).getCompanyId();
+        WxCorpInfo wxCorpInfo = wxCorpInfoMapper.selectOne(new LambdaQueryWrapper<WxCorpInfo>().eq(WxCorpInfo::getCompanyId,companyId));
+        HttpRespMsg data = list(projectId);
+        List<ExpenseItemVO> itemVOS = (List<ExpenseItemVO>) data.getData();
+        List<List<String>> dataList=new ArrayList<>();
+        List<String> titleList=new ArrayList<>();
+        titleList.add("员工姓名");
+        titleList.add("所在部门");
+        titleList.add("费用日期");
+        titleList.add("费用类型");
+        titleList.add("票据类型");
+        titleList.add("金额(含税)");
+        titleList.add("税额");
+        titleList.add("金额(不含税)");
+        titleList.add("备注");
+        dataList.add(titleList);
+        for (ExpenseItemVO itemVO : itemVOS) {
+            List<String> item=new ArrayList<>();
+            if(wxCorpInfo!=null&&wxCorpInfo.getSaasSyncContact()==1){
+                String userName ="$userName="+String.valueOf(itemVO.getCorpwxUserId())+"$";
+                String deptName ="$departmentName="+String.valueOf(itemVO.getCorpwxDeptId())+"$";
+                item.add(userName);
+                item.add(deptName);
+            }else {
+                item.add(itemVO.getUsername());
+                item.add(itemVO.getDepartmentName());
+            }
+            item.add(itemVO.getHappenDate());
+            item.add(itemVO.getExpenseType());
+            item.add(itemVO.getInvoiceType()==null?"":(itemVO.getInvoiceType()==0?"增值税专用发票":"增值税普通发票"));
+            BigDecimal decimal = new BigDecimal(itemVO.getAmount()==null?0:itemVO.getAmount());
+            item.add(String.valueOf(itemVO.getAmount()==null?"0":itemVO.getAmount()));
+            item.add(String.valueOf(itemVO.getTaxValue()==null?"0":itemVO.getTaxValue()));
+            decimal=decimal.subtract(new BigDecimal(itemVO.getTaxValue()==null?0:itemVO.getTaxValue())).setScale(2,BigDecimal.ROUND_HALF_UP);
+            item.add(String.valueOf(decimal.doubleValue()));
+            item.add(itemVO.getRemark()==null?"":itemVO.getRemark());
+            dataList.add(item);
+        }
+        String fileUrlSuffix = "费用报销明细表_" + System.currentTimeMillis();
+        try {
+           return excelExportService.exportGeneralExcelByTitleAndList(wxCorpInfo, fileUrlSuffix, dataList, path);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return msg;
+    }
 }
 
+

+ 37 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ExpensePayWayController.java

@@ -0,0 +1,37 @@
+package com.management.platform.controller;
+
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.management.platform.entity.ExpensePayWay;
+import com.management.platform.service.ExpensePayWayService;
+import com.management.platform.util.HttpRespMsg;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * <p>
+ *  前端控制器
+ * </p>
+ *
+ * @author Seyason
+ * @since 2024-01-09
+ */
+@RestController
+@RequestMapping("/expense-pay-way")
+public class ExpensePayWayController {
+
+    @Resource
+    private ExpensePayWayService expensePayWayService;
+    @RequestMapping("/get")
+    public HttpRespMsg get(Integer companyId) {
+        List<ExpensePayWay> data = expensePayWayService.list(new QueryWrapper<ExpensePayWay>().eq("company_id", companyId));
+        HttpRespMsg msg = new HttpRespMsg();
+        msg.data = data;
+        return msg;
+    }
+}
+

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

@@ -2,11 +2,13 @@ package com.management.platform.controller;
 
 
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.management.platform.entity.ExpensePayWay;
 import com.management.platform.entity.ExpenseSheet;
 import com.management.platform.entity.User;
 import com.management.platform.entity.vo.SysRichFunction;
 import com.management.platform.mapper.SysFunctionMapper;
 import com.management.platform.mapper.UserMapper;
+import com.management.platform.service.ExpensePayWayService;
 import com.management.platform.service.ExpenseSheetService;
 import com.management.platform.util.HttpRespMsg;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -39,6 +41,8 @@ public class ExpenseSheetController {
     private HttpServletRequest request;
     @Resource
     SysFunctionMapper sysFunctionMapper;
+    @Resource
+    ExpensePayWayService expensePayWayService;
 
     @RequestMapping("/getNextCode")
     public HttpRespMsg getNextCode() {
@@ -127,15 +131,20 @@ public class ExpenseSheetController {
     }
 
     @RequestMapping("/editSendExpense")
-    public HttpRespMsg sendExpense(String expenseIds,Integer sendState){
+    public HttpRespMsg sendExpense(String expenseIds,Integer sendState, Integer payWayId){
         HttpRespMsg msg=new HttpRespMsg();
         String[] split = expenseIds.split(",");
         List<String> asList = Arrays.asList(split);
         List<Integer> ids = asList.stream().map(i -> Integer.parseInt(i)).collect(Collectors.toList());
         ids.add(-1);
+        ExpensePayWay payway = expensePayWayService.getById(payWayId);
         List<ExpenseSheet> expenseSheets = expenseSheetService.list(new QueryWrapper<ExpenseSheet>().in("id", ids));
         expenseSheets.forEach(e->{
             e.setSendState(sendState);
+            if (payway != null) {
+                e.setPayWayId(payWayId);
+                e.setPayWayName(payway.getName());
+            }
         });
         if(!expenseSheetService.updateBatchById(expenseSheets)){
             msg.setError("验证失败");

+ 102 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/GroupBudgetReviewController.java

@@ -0,0 +1,102 @@
+package com.management.platform.controller;
+
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.management.platform.entity.*;
+import com.management.platform.mapper.ProjectMapper;
+import com.management.platform.mapper.TaskGroupMapper;
+import com.management.platform.mapper.UserMapper;
+import com.management.platform.service.GroupBudgetReviewService;
+import com.management.platform.util.HttpRespMsg;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * <p>
+ *  前端控制器
+ * </p>
+ *
+ * @author Seyason
+ * @since 2023-12-28
+ */
+@RestController
+@RequestMapping("/group-budget-review")
+public class GroupBudgetReviewController {
+
+    @Resource
+    private GroupBudgetReviewService groupBudgetReviewService;
+    @Resource
+    private HttpServletRequest request;
+    @Resource
+    private UserMapper userMapper;
+    @Resource
+    private TaskGroupMapper taskGroupMapper;
+    @Resource
+    private ProjectMapper projectMapper;
+
+    @RequestMapping("/add")
+    public HttpRespMsg add(Integer groupId,Integer oldManDay,Integer changeManDay,Integer nowManDay,String remark){
+        HttpRespMsg httpRespMsg=new HttpRespMsg();
+        if(changeManDay==null||changeManDay==0){
+            httpRespMsg.setError("预估工时未发生变更");
+            return httpRespMsg;
+        }
+        User user = userMapper.selectById(request.getHeader("token"));
+        GroupBudgetReview groupBudgetReview=new GroupBudgetReview();
+        TaskGroup taskGroup = taskGroupMapper.selectById(groupId);
+        Project project = projectMapper.selectById(taskGroup.getProjectId());
+        groupBudgetReview.setGroupId(groupId).setGroupName(taskGroup.getName())
+                .setOldManDay(oldManDay)
+                .setChangeManDay(changeManDay)
+                .setNowManDay(nowManDay)
+                .setCompanyId(user.getCompanyId())
+                .setProjectId(project.getId()).setProjectName(project.getProjectName())
+                .setCreatorId(user.getId())
+                .setCreator(user.getName())
+                .setRemark(remark);
+        if(!groupBudgetReviewService.save(groupBudgetReview)){
+            httpRespMsg.setError("验证失败");
+        }
+        return  httpRespMsg;
+    }
+
+    @RequestMapping("/check")
+    public HttpRespMsg check(Integer id,Integer checkType){
+        HttpRespMsg httpRespMsg=new HttpRespMsg();
+        GroupBudgetReview groupBudgetReview=groupBudgetReviewService.getById(id);
+        groupBudgetReview.setStatus(checkType);
+        if(checkType==1){
+            //审核通过计算到任务分组的项目人天
+            Integer groupId = groupBudgetReview.getGroupId();
+            TaskGroup taskGroup = taskGroupMapper.selectById(groupId);
+            Integer manDay = taskGroup.getManDay();
+            BigDecimal bigDecimal = new BigDecimal(manDay==null?0:manDay);
+            bigDecimal=bigDecimal.add(new BigDecimal(groupBudgetReview.getChangeManDay()==null?0:groupBudgetReview.getChangeManDay()));
+            taskGroup.setManDay(bigDecimal.intValue());
+            taskGroupMapper.updateById(taskGroup);
+        }
+        if(!groupBudgetReviewService.updateById(groupBudgetReview)){
+            httpRespMsg.setError("验证失败");
+        }
+        return  httpRespMsg;
+    }
+
+    @RequestMapping("/list")
+    public HttpRespMsg list(){
+        HttpRespMsg httpRespMsg=new HttpRespMsg();
+        Integer companyId = userMapper.selectById(request.getHeader("token")).getCompanyId();
+        List<GroupBudgetReview> list = groupBudgetReviewService.list(new LambdaQueryWrapper<GroupBudgetReview>().eq(GroupBudgetReview::getCompanyId, companyId).orderByDesc(GroupBudgetReview::getCreateTime));
+        httpRespMsg.setData(list);
+        return httpRespMsg;
+    }
+
+
+
+}
+

+ 50 - 4
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ProjectAuditorController.java

@@ -2,8 +2,8 @@ package com.management.platform.controller;
 
 
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.management.platform.entity.ProjectAuditor;
-import com.management.platform.mapper.ProjectAuditorMapper;
+import com.management.platform.entity.*;
+import com.management.platform.mapper.*;
 import com.management.platform.service.ProjectAuditorService;
 import com.management.platform.util.HttpRespMsg;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -11,6 +11,8 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
 import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.stream.Collectors;
 
@@ -29,11 +31,55 @@ public class ProjectAuditorController {
     @Resource
     private ProjectAuditorMapper projectAuditorMapper;
 
+    @Resource
+    private CompanyMapper companyMapper;
+    @Resource
+    private UserMapper userMapper;
+    @Resource
+    private ProjectMapper projectMapper;
+    @Resource
+    private DepartmentMapper departmentMapper;
+    @Resource
+    HttpServletRequest request;
+
     @RequestMapping("/getList")
     private HttpRespMsg getList(Integer projectId) {
-        List<ProjectAuditor> auditorList = projectAuditorMapper.selectList(new QueryWrapper<ProjectAuditor>().eq("project_id", projectId));
+        String token = request.getHeader("TOKEN");
         HttpRespMsg msg = new HttpRespMsg();
-        msg.data = auditorList;
+        User user = userMapper.selectById(token);
+        Company company = companyMapper.selectById(user.getCompanyId());
+        int mode = 0;
+        if (company.getNonProjectSimple() == 1) {
+            //启用了简易模式
+            Project project = projectMapper.selectById(projectId);
+            List<ProjectAuditor> auditorList = new ArrayList<>();
+            if (project.getIsPublic() == 1) {
+                //非项目,该员工的部门主要负责人审核
+                mode = 1;
+                String superiorId = null;
+                Integer departmentId = user.getDepartmentId();
+                Department department = departmentMapper.selectById(departmentId);
+                if (department != null) {
+                    superiorId = department.getManagerId();
+                }
+                if (superiorId != null) {
+                    User superior = userMapper.selectById(superiorId);
+                    if (superior != null) {
+                        ProjectAuditor auditor = new ProjectAuditor();
+                        auditor.setAuditorId(superiorId);
+                        auditor.setAuditorName(superior.getName());
+                        auditorList.add(auditor);
+
+                    }
+                }
+                msg.data = auditorList;
+            }
+        }
+        if (mode == 0) {
+            List<ProjectAuditor> auditorList = projectAuditorMapper.selectList(new QueryWrapper<ProjectAuditor>().eq("project_id", projectId));
+            msg.data = auditorList;
+        }
+
         return msg;
     }
 }

+ 10 - 6
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ProjectController.java

@@ -262,8 +262,8 @@ public class ProjectController {
      * 导出查询者所在公司每个项目的工时成本
      */
     @RequestMapping("/exportTimeCost")
-    public HttpRespMsg exportTimeCost(String exportContent,String startDate, String endDate, Integer projectId, String userIds, Boolean projectSum,Integer type,Integer deptId,@RequestParam(defaultValue = "1") Integer stateKey, @RequestParam(required = false, defaultValue = "0") Integer withPercent) {
-        return projectService.exportTimeCost(exportContent,startDate, endDate, projectId, userIds, projectSum,type,deptId,stateKey, withPercent, request);
+    public HttpRespMsg exportTimeCost(@RequestParam(required = false, defaultValue = "0") Integer withMainProject, String exportContent,String startDate, String endDate, Integer projectId, String userIds, Boolean projectSum,Integer type,Integer deptId,@RequestParam(defaultValue = "1") Integer stateKey, @RequestParam(required = false, defaultValue = "0") Integer withPercent,Integer projectCategoryId) {
+        return projectService.exportTimeCost(withMainProject, exportContent,startDate, endDate, projectId, userIds, projectSum,type,deptId,stateKey, withPercent,projectCategoryId, request);
     }
 
     /**
@@ -435,8 +435,8 @@ public class ProjectController {
 
     //分页查询项目任务报表
     @RequestMapping("/getProjectTask")
-    public HttpRespMsg getProjectTask(@RequestParam Integer pageIndex, @RequestParam Integer pageSize, Integer projectId,Integer taskType) {
-        return projectService.getProjectTask(pageIndex, pageSize, projectId, request,taskType);
+    public HttpRespMsg getProjectTask(@RequestParam Integer pageIndex, @RequestParam Integer pageSize, Integer projectId,Integer groupId,Integer taskType) {
+        return projectService.getProjectTask(pageIndex, pageSize, projectId,groupId, request,taskType);
     }
 
     //分页查询项目各个阶段的汇总工时成本
@@ -1431,8 +1431,8 @@ public class ProjectController {
     //同步SAP项目数据到工时管家
     @RequestMapping("/syncProjectWithSap")
     @Transactional
-    public HttpRespMsg syncProjectWithSap(String startDate,String endDate){
-        return projectService.syncProjectWithSap(startDate,endDate);
+    public HttpRespMsg syncProjectWithSap(String startDate,String endDate,String projectCodes){
+        return projectService.syncProjectWithSap(startDate,endDate,projectCodes);
     }
 
     @RequestMapping("/getEffectiveLaborHourRate")
@@ -1441,5 +1441,9 @@ public class ProjectController {
     }
 
 
+    @RequestMapping("/getMembProjectCateRatio")
+    public HttpRespMsg getMembProjectCateRatio(String startDate,String endDate, Integer onlyShowWarning){
+        return projectService.getMembProjectCateRatio(startDate,endDate, onlyShowWarning);
+    }
 }
 

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

@@ -2333,8 +2333,8 @@ public class ReportController {
 
     //todo:推送工时管家工时考勤数据到SAP
     @RequestMapping("/pushProjectReportToSap")
-    public HttpRespMsg pushProjectReportToSap(String yearMonth){
-        return reportService.pushProjectReportToSap(yearMonth);
+    public HttpRespMsg pushProjectReportToSap(String pushDate){
+        return reportService.pushProjectReportToSap(pushDate);
     }
 
     //todo: 提供接口(威派格) 获取项目工时数据
@@ -2394,5 +2394,15 @@ public class ReportController {
         }
         return checkDate;
     }
+
+    @RequestMapping("getUserWorkTimeByCategory")
+    public HttpRespMsg getUserWorkTimeByCategory(@RequestParam(required = true) Integer categoryId,Integer deptId,String userId,String startDate,String endDate,Integer pageIndex,Integer pageSize){
+        return reportService.getUserWorkTimeByCategory(categoryId,deptId,userId,startDate,endDate,pageIndex,pageSize);
+    }
+
+    @RequestMapping("exportUserWorkTimeByCategory")
+    public HttpRespMsg exportUserWorkTimeByCategory(@RequestParam(required = true) Integer categoryId,Integer deptId,String userId,String startDate,String endDate){
+        return reportService.exportUserWorkTimeByCategory(categoryId,deptId,userId,startDate,endDate);
+    }
 }
 

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

@@ -37,7 +37,7 @@ public class SapProjectServiceController {
     public HttpRespMsg sapServiceList(){
         HttpRespMsg msg=new HttpRespMsg();
         Integer companyId = userMapper.selectById(request.getHeader("token")).getCompanyId();
-        List<SapProjectService> serviceList = sapProjectServiceService.list(new LambdaQueryWrapper<SapProjectService>().eq(SapProjectService::getCompanyId, companyId));
+        List<SapProjectService> serviceList = sapProjectServiceService.list(new LambdaQueryWrapper<SapProjectService>().eq(SapProjectService::getStatus,2).eq(SapProjectService::getCompanyId, companyId));
         msg.setData(serviceList);
         return msg;
     }

+ 53 - 15
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/TaskController.java

@@ -209,7 +209,7 @@ public class TaskController {
             if (taskList.size() == 0) {
                 task.setSeq(1);
             } else {
-                task.setSeq(taskList.get(0).getSeq() + 1);
+                task.setSeq(taskList.get(0).getSeq()==null?0:taskList.get(0).getSeq() + 1);
             }
             //比当前创建的这条task的seq大于或者等于的,都要往后排一位
             queryWrapper = new QueryWrapper<>();
@@ -693,6 +693,7 @@ public class TaskController {
         String userId = request.getHeader("Token");
         User user = userMapper.selectById(userId);
         Task t = taskService.getById(id);
+        List<SapProjectService> serviceList = sapProjectServiceService.list(new LambdaQueryWrapper<SapProjectService>().eq(SapProjectService::getCompanyId, user.getCompanyId()));
         if (t == null) {
             //msg.setError("该任务已不存在");
             msg.setError(MessageUtils.message("Stages.noExist"));
@@ -711,7 +712,17 @@ public class TaskController {
             list.get(0).setCreatorName(name);
         }
         //查询任务的执行人
-        t.setExecutorList(taskExecutorMapper.selectList(new QueryWrapper<TaskExecutor>().eq("task_id", t.getId())));
+        List<TaskExecutor> executorList = taskExecutorMapper.selectList(new QueryWrapper<TaskExecutor>().eq("task_id", t.getId()));
+        executorList.forEach(e->{
+            if(e.getServiceId()!=null){
+                Optional<SapProjectService> first = serviceList.stream().filter(s -> s.getId().equals(e.getServiceId())).findFirst();
+                if(first.isPresent()){
+                    e.setServiceName(first.get().getServiceName());
+                    e.setServiceCode(first.get().getServiceCode());
+                }
+            }
+        });
+        t.setExecutorList(executorList);
         //查询项目负责人id以及所属任务分组负责人id
         Project project = projectService.getOne(new QueryWrapper<Project>().eq("id", t.getProjectId()));
         TaskGroup group = taskGroupService.getOne(new QueryWrapper<TaskGroup>().eq("id", t.getGroupId()));
@@ -767,17 +778,22 @@ public class TaskController {
     }
 
     @RequestMapping("/getRecentTask")
-    public HttpRespMsg getRecentTask(Integer projectId,
+    public HttpRespMsg getRecentTask(Integer projectId, String userId,
                                      @RequestParam(required = false, defaultValue = "0") Integer isSubstitude, String stage, Integer groupId) {
         HttpRespMsg msg = new HttpRespMsg();
-        String userId = request.getHeader("Token");
-        if (isSubstitude == 0) {
-            msg.data = taskMapper.recentSimpleList(projectId, userId, stage, groupId);
-        } else {
-            //代填的情况,获取的是项目中的所有任务
-            msg.data = taskMapper.recentSimpleList(projectId, null, stage, groupId);
+        if (isSubstitude == 0 || userId == null) {
+            userId = request.getHeader("Token");
         }
 
+        msg.data = taskMapper.recentSimpleList(projectId, userId, stage, groupId);
+
+//        if (isSubstitude == 0) {
+//            msg.data = taskMapper.recentSimpleList(projectId, userId, stage, groupId);
+//        } else {
+//            //代填的情况,获取的是项目中的所有任务
+//            msg.data = taskMapper.recentSimpleList(projectId, null, stage, groupId);
+//        }
+
         return msg;
     }
 
@@ -887,8 +903,22 @@ public class TaskController {
     }
 
     @RequestMapping("/importTask")
-    public HttpRespMsg importUser(Integer projectId, Integer groupId, @RequestParam MultipartFile file) {
-        return taskService.importTask(projectId, groupId, file, request);
+    public HttpRespMsg importUser(@RequestParam(required = false,defaultValue = "0")Integer isMultiProject, Integer projectId, Integer groupId, @RequestParam MultipartFile file) {
+        HttpRespMsg httpRespMsg = new HttpRespMsg();
+        try {
+            httpRespMsg = taskService.importTask(isMultiProject, projectId, groupId, file, request);
+            return httpRespMsg;
+        } catch (NullPointerException e) {
+            e.printStackTrace();
+            //httpRespMsg.setError("数据格式有误或存在空数据 导入失败");
+            httpRespMsg.setError(MessageUtils.message("file.dataFormatError"));
+            return httpRespMsg;
+        } catch (Exception e) {
+            e.printStackTrace();
+            //httpRespMsg.setError("发生其他错误");
+            httpRespMsg.setError(e.getMessage());
+            return httpRespMsg;
+        }
     }
 
 
@@ -901,7 +931,7 @@ public class TaskController {
      * @return
      */
     @RequestMapping("/listByPage")
-    public HttpRespMsg listByPage(Integer status, Integer viewId, Integer pageIndex, Integer pageSize,Integer type,Integer dateType,String startDate,String endDate,Integer deptId) {
+    public HttpRespMsg listByPage(Integer status, Integer viewId, @RequestParam(required = false, defaultValue = "1") Integer pageIndex, Integer pageSize,Integer type,Integer dateType,String startDate,String endDate,Integer deptId) {
         HttpRespMsg msg = new HttpRespMsg();
         String userId = request.getHeader("Token");
         User user = userMapper.selectById(userId);
@@ -946,9 +976,16 @@ public class TaskController {
         List<Integer> collect = list.stream().map(l -> l.getId()).distinct().collect(Collectors.toList());
         collect.add(-1);
         List<TaskExecutor> taskExecutorList = taskExecutorMapper.selectList(new QueryWrapper<TaskExecutor>().in("task_id", collect));
+        List<Integer> pids = list.stream().map(Task::getProjectId).collect(Collectors.toList());
+        pids.add(-1);
+        List<Project> projectList = projectService.list(new QueryWrapper<Project>().in("id", pids));
         list.forEach(l->{
             List<TaskExecutor> executorList = taskExecutorList.stream().filter(tl -> tl.getTaskId().equals(l.getId())&&tl.getExecutorId()!=null).collect(Collectors.toList());
             l.setExecutorList(executorList);
+            Optional<Project> first = projectList.stream().filter(p -> p.getId().equals(l.getProjectId())).findFirst();
+            if (first.isPresent()) {
+                l.setProjectInchargerId(first.get().getInchargerId());
+            }
         });
         int total = taskMapper.selectCount(queryWrapper);
         Map<String, Object> map = new HashMap<>();
@@ -1029,10 +1066,11 @@ public class TaskController {
 
     //获取当前用户在任务上参与的服务
     @RequestMapping("/getMyTaskService")
-    public HttpRespMsg getMyTaskService(Integer taskId) throws Exception {
+    public HttpRespMsg getMyTaskService(Integer taskId, String userId) throws Exception {
         HttpRespMsg httpRespMsg=new HttpRespMsg();
-        String userId = request.getHeader("token");
-        System.out.println(userId+"======="+taskId);
+        if (StringUtils.isEmpty(userId)) {
+            userId = request.getHeader("token");
+        }
         List<TaskExecutor> taskExecutors = taskExecutorMapper.selectList(new QueryWrapper<TaskExecutor>().eq("executor_id", userId).eq("task_id", taskId));
         List<Integer> serviceIds = new ArrayList<>();
         for (TaskExecutor executor : taskExecutors) {

+ 82 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/UserWithBeisenController.java

@@ -0,0 +1,82 @@
+package com.management.platform.controller;
+
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.management.platform.entity.UserWithBeisen;
+import com.management.platform.mapper.UserMapper;
+import com.management.platform.mapper.UserWithBeisenMapper;
+import com.management.platform.service.UserWithBeisenService;
+import com.management.platform.util.BeiSenUtils;
+import com.management.platform.util.HttpRespMsg;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * <p>
+ *  前端控制器
+ * </p>
+ *
+ * @author Seyason
+ * @since 2024-01-09
+ */
+@RestController
+@RequestMapping("/user-with-beisen")
+public class UserWithBeisenController {
+
+    @Resource
+    private UserMapper userMapper;
+    @Resource
+    private HttpServletRequest request;
+    @Resource
+    private UserWithBeisenService userWithBeisenService;
+
+    @RequestMapping("/getByTimeWindow")
+    public HttpRespMsg getByTimeWindow(String startTime,String stopTime){
+        HttpRespMsg httpRespMsg=new HttpRespMsg();
+        Integer companyId = userMapper.selectById(request.getHeader("token")).getCompanyId();
+        List<UserWithBeisen> allBeisenList = userWithBeisenService.list(new LambdaQueryWrapper<UserWithBeisen>().eq(UserWithBeisen::getCompanyId, companyId));
+        List<UserWithBeisen> userWithBeisenList=new ArrayList<>();
+        List<JSONArray> byTimeWindow = BeiSenUtils.getByTimeWindow("",startTime,stopTime);
+        for (JSONArray array : byTimeWindow) {
+            for (int i = 0; i < array.size(); i++) {
+                UserWithBeisen userWithBeisen=new UserWithBeisen();
+                JSONObject targetItem = array.getJSONObject(i);
+                JSONObject employeeInfo = targetItem.getJSONObject("employeeInfo");
+                JSONObject recordInfo = targetItem.getJSONObject("recordInfo");
+                userWithBeisen.setCompanyId(companyId);
+                userWithBeisen.setJobNumber(recordInfo.getString("jobNumber"));
+                userWithBeisen.setMobilePhone(employeeInfo.getString("mobilePhone"));
+                userWithBeisen.setName(employeeInfo.getString("name"));
+                userWithBeisen.setUserId(employeeInfo.getString("userID"));
+                Optional<UserWithBeisen> first = allBeisenList.stream().filter(a -> a.getUserId().equals(employeeInfo.getString("userID"))).findFirst();
+                if(first.isPresent()){
+                    userWithBeisen.setId(first.get().getId());
+                }
+                boolean anyMatch = userWithBeisenList.stream().anyMatch(u -> u.getUserId().equals(userWithBeisen.getUserId()));
+                if(anyMatch){
+                    continue;
+                }
+                userWithBeisenList.add(userWithBeisen);
+            }
+        }
+        if(userWithBeisenList.size()>0){
+            if(!userWithBeisenService.saveOrUpdateBatch(userWithBeisenList)){
+                httpRespMsg.setError("验证失败");
+                return httpRespMsg;
+            }
+        }
+        return httpRespMsg;
+    }
+
+}
+

+ 6 - 3
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/WeiXinCorpController.java

@@ -2420,16 +2420,19 @@ public class WeiXinCorpController {
                         changeUser.setName(userItem.getName());
                     }
                     if (!userItem.getCorpwxDeptid().equals(oldUser.getCorpwxDeptid())) {
-                        changeUser.setId(oldUser.getId());
                         if (userItem.getCorpwxDeptid() != 1) {
+                            changeUser.setId(oldUser.getId());
                             changeUser.setDepartmentId(allDeptList.stream().filter(d->d.getCorpwxDeptid() != null && d.getCorpwxDeptid().equals(userItem.getCorpwxDeptid())).findFirst().get().getDepartmentId());
                             //设置层级部门
                             changeUser.setDepartmentCascade(convertDepartmentIdToCascade(changeUser.getDepartmentId(), allDeptList));
-                        } else {
+                            changeUser.setCorpwxDeptid(userItem.getCorpwxDeptid());
+                        } else if (oldUser.getCorpwxDeptid() == null || oldUser.getCorpwxDeptid() == 1) {
+                            changeUser.setId(oldUser.getId());
+                            //从待分配变成有部门的时候才更新;避免原来有部门的被冲掉,变成无部门
                             changeUser.setDepartmentId(0);
                             changeUser.setDepartmentCascade("0");
+                            changeUser.setCorpwxDeptid(userItem.getCorpwxDeptid());
                         }
-                        changeUser.setCorpwxDeptid(userItem.getCorpwxDeptid());
                     }
                     if (oldUser.getCorpwxRealUserid() == null || !userItem.getCorpwxRealUserid().equals(oldUser.getCorpwxRealUserid())) {
                         changeUser.setId(oldUser.getId());

+ 56 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/CategoryRatioTblSetting.java

@@ -0,0 +1,56 @@
+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-01-01
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class CategoryRatioTblSetting extends Model<CategoryRatioTblSetting> {
+
+    private static final long serialVersionUID=1L;
+
+    /**
+     * 公司id做主键
+     */
+    @TableId("company_id")
+    private Integer companyId;
+
+    /**
+     * 检测的项目分类id
+     */
+    @TableField("monitor_category_id")
+    private Integer monitorCategoryId;
+
+    /**
+     * 百分比
+     */
+    @TableField("ratio")
+    private Integer ratio;
+
+    /**
+     * 0-低于,1-高于
+     */
+    @TableField("more_or_less")
+    private Integer moreOrLess;
+
+
+    @Override
+    protected Serializable pkVal() {
+        return this.companyId;
+    }
+
+}

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

@@ -16,7 +16,7 @@ import lombok.experimental.Accessors;
  * </p>
  *
  * @author Seyason
- * @since 2023-04-10
+ * @since 2023-12-28
  */
 @Data
 @EqualsAndHashCode(callSuper = false)
@@ -140,6 +140,13 @@ public class Company extends Model<Company> {
     private String regFrom;
 
 
+    /**
+     * 非项目采用简易模式,非项目工时由部门主要负责人审核
+     */
+    @TableField("non_project_simple")
+    private Integer nonProjectSimple;
+
+
     @Override
     protected Serializable pkVal() {
         return this.id;

+ 42 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/ExpensePayWay.java

@@ -0,0 +1,42 @@
+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-01-09
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class ExpensePayWay extends Model<ExpensePayWay> {
+
+    private static final long serialVersionUID=1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    @TableField("company_id")
+    private Integer companyId;
+
+    @TableField("name")
+    private String name;
+
+
+    @Override
+    protected Serializable pkVal() {
+        return this.id;
+    }
+
+}

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

@@ -20,7 +20,7 @@ import org.springframework.format.annotation.DateTimeFormat;
  * </p>
  *
  * @author Seyason
- * @since 2023-12-16
+ * @since 2024-01-09
  */
 @Data
 @EqualsAndHashCode(callSuper = false)
@@ -145,6 +145,19 @@ public class ExpenseSheet extends Model<ExpenseSheet> {
     @TableField(exist = false)
     private Integer projectId;
 
+    /**
+     * 支付方式id
+     */
+    @TableField("pay_way_id")
+    private Integer payWayId;
+
+    /**
+     * 支付方式名称
+     */
+    @TableField("pay_way_name")
+    private String payWayName;
+
+
     @Override
     protected Serializable pkVal() {
         return this.id;

+ 111 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/GroupBudgetReview.java

@@ -0,0 +1,111 @@
+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 java.time.LocalDateTime;
+import com.baomidou.mybatisplus.annotation.TableField;
+import java.io.Serializable;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.springframework.format.annotation.DateTimeFormat;
+
+/**
+ * <p>
+ * 
+ * </p>
+ *
+ * @author Seyason
+ * @since 2024-01-04
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class GroupBudgetReview extends Model<GroupBudgetReview> {
+
+    private static final long serialVersionUID=1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 分组id
+     */
+    @TableField("group_id")
+    private Integer groupId;
+
+    /**
+     * 变更前
+     */
+    @TableField("old_man_day")
+    private Integer oldManDay;
+
+    /**
+     * 变更值
+     */
+    @TableField("change_man_day")
+    private Integer changeManDay;
+
+    /**
+     * 变更后
+     */
+    @TableField("now_man_day")
+    private Integer nowManDay;
+
+    /**
+     * 0-待审核 1-审核通过 2-驳回
+     */
+    @TableField("status")
+    private Integer status;
+
+    @TableField("create_time")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private LocalDateTime createTime;
+
+    @TableField("company_id")
+    private Integer companyId;
+
+    /**
+     * 操作人id
+     */
+    @TableField("creator_id")
+    private String creatorId;
+
+    /**
+     * 任务名称
+     */
+    @TableField("group_name")
+    private String groupName;
+
+    /**
+     * 分组名称
+     */
+    @TableField("creator")
+    private String creator;
+
+    /**
+     * 项目id
+     */
+    @TableField("project_id")
+    private Integer projectId;
+
+    @TableField("project_name")
+    private String projectName;
+
+    /**
+     * 变更原因
+     */
+    @TableField("remark")
+    private String remark;
+
+
+    @Override
+    protected Serializable pkVal() {
+        return this.id;
+    }
+
+}

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

@@ -15,7 +15,7 @@ import lombok.experimental.Accessors;
  * </p>
  *
  * @author Seyason
- * @since 2023-11-27
+ * @since 2024-01-04
  */
 @Data
 @EqualsAndHashCode(callSuper = false)
@@ -45,6 +45,9 @@ public class SapProjectService extends Model<SapProjectService> {
     @TableField("company_id")
     private Integer companyId;
 
+    @TableField("status")
+    private Integer status;
+
 
     @Override
     protected Serializable pkVal() {

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

@@ -67,6 +67,12 @@ public class TaskExecutor extends Model<TaskExecutor> {
     @TableField("service_id")
     private Integer serviceId;
 
+    @TableField(exist = false)
+    private String serviceName;
+
+    @TableField(exist = false)
+    private String serviceCode;
+
 
     @Override
     protected Serializable pkVal() {

+ 66 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/UserWithBeisen.java

@@ -0,0 +1,66 @@
+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-01-09
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class UserWithBeisen extends Model<UserWithBeisen> {
+
+    private static final long serialVersionUID=1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 人员编号 唯一
+     */
+    @TableField("user_id")
+    private String userId;
+
+    /**
+     * 人员名称
+     */
+    @TableField("name")
+    private String name;
+
+    /**
+     * 电话号码
+     */
+    @TableField("mobile_phone")
+    private String mobilePhone;
+
+    /**
+     * 人员工号
+     */
+    @TableField("job_number")
+    private String jobNumber;
+
+    /**
+     * 公司id
+     */
+    @TableField("company_id")
+    private Integer companyId;
+
+
+    @Override
+    protected Serializable pkVal() {
+        return this.id;
+    }
+
+}

+ 2 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/vo/ExpenseItemVO.java

@@ -11,5 +11,6 @@ import lombok.experimental.Accessors;
 public class ExpenseItemVO extends ExpenseItem {
     public String username;
     public String departmentName;
-
+    public String corpwxUserId;
+    public String corpwxDeptId;
 }

+ 16 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/vo/UserCateTimeVo.java

@@ -0,0 +1,16 @@
+package com.management.platform.entity.vo;
+
+import lombok.Data;
+
+@Data
+public class UserCateTimeVo {
+    public String userId;
+    public String name;
+    public Integer category;
+    public String categoryName;
+    public Double workingTime;
+    public Double percent;
+
+    public boolean warning;
+
+}

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

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

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

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

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

@@ -0,0 +1,16 @@
+package com.management.platform.mapper;
+
+import com.management.platform.entity.GroupBudgetReview;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ *  Mapper 接口
+ * </p>
+ *
+ * @author Seyason
+ * @since 2023-12-28
+ */
+public interface GroupBudgetReviewMapper extends BaseMapper<GroupBudgetReview> {
+
+}

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

@@ -6,6 +6,7 @@ import com.management.platform.entity.TaskGroup;
 import com.management.platform.entity.vo.CustomerProject;
 import com.management.platform.entity.vo.ProjectWithStage;
 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;
 
@@ -30,7 +31,7 @@ public interface ProjectMapper extends BaseMapper<Project> {
     List<Map<String, Object>> getTimeCost(@Param("companyId") Integer companyId, @Param("startDate") String startDate, @Param("endDate") String endDate,
                                           @Param("projectId") Integer projectId, @Param("userIdList") List<String> userIdList,
                                           @Param("deptIds")List<Integer> deptIds,@Param("filterDeptIds")List<Integer> filterDeptIds, @Param("deptRelatedProjectIds") List<Integer> deptRelatedProjectIds,
-                                          @Param("projectIds") List<Integer> projectIds, @Param("inchargeUserIds") List<String> inchargeUserIds);
+                                          @Param("projectIds") List<Integer> projectIds, @Param("inchargeUserIds") List<String> inchargeUserIds,@Param("categoryId") Integer categoryId);
 
     List<Map<String, Object>> getCustomDataSum(@Param("companyId") Integer companyId, @Param("startDate") String startDate, @Param("endDate") String endDate,
                                           @Param("projectId") Integer projectId, @Param("userId") String userId);
@@ -162,4 +163,6 @@ public interface ProjectMapper extends BaseMapper<Project> {
     List<Map<String, Object>> getFTEData(Integer companyId, String startDate, String endDate, Integer start, Integer size, String area, List<Integer> branchDepartment, List<Integer> deptIds);
 
     List<Map<String, Object>> getTimeCostByToken(Integer companyId, String startDate, String endDate);
+
+    List<UserCateTimeVo> getMembProjectCateTime(Integer companyId, String startDate, String endDate);
 }

+ 5 - 2
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/ReportMapper.java

@@ -135,7 +135,7 @@ public interface ReportMapper extends BaseMapper<Report> {
 
     List<Map> getSameDayPassReport(Integer companyId, @Param("dateReportList") List<Report> dateReportList);
 
-    double getMyOvertime(String userId);
+    double getMyOvertime(String userId, String startDate);
 
     List<Map<String, Object>> getProWaitingApproveCnt(Integer companyId);
 
@@ -188,7 +188,7 @@ public interface ReportMapper extends BaseMapper<Report> {
 
     Double getReallWorkingTimeByProjectAndGroup(Integer projectId, Integer taskGroupId);
 
-    List<Map<String, Object>> getProjectPlanData(Integer companyId, String startDate, String endDate);
+    List<Map<String, Object>> getProjectPlanData(Integer companyId,@Param("list") List<Integer> projectIds, String startDate, String endDate);
 
     List<String> getUserIds(ArrayList<Integer> deptIds, String startDate, String endDate);
 
@@ -197,4 +197,7 @@ public interface ReportMapper extends BaseMapper<Report> {
     List<Map<String, Object>> getProjectMainTimeCost(Integer companyId,String requestProjectMainCode);
 
     List<Map<String, Object>> getTaskGroupPlanTime(@Param("list") List<Integer> projectIds);
+
+    List<Map<String, Object>> getUserWorkTimeByCategory(Integer categoryId, String userId,Integer companyId,@Param("list")List<Integer> deptIds, Integer deptId, String startDate, String endDate);
+
 }

+ 2 - 2
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/TaskMapper.java

@@ -33,9 +33,9 @@ public interface TaskMapper extends BaseMapper<Task> {
 
     List<TimeTask> getTaskWithWorktime(Integer projectId, Integer taskType);
 
-    List getProjectTask(Integer companyId, Integer pageStart, Integer pageSize, Integer projectId,Integer taskType,List<Integer> inchagerIds);
+    List<Map<String,Object>> getProjectTask(Integer companyId, Integer pageStart, Integer pageSize, Integer projectId,Integer groupId,Integer taskType,List<Integer> inchagerIds);
 
-    Integer getProjectTaskCount(Integer companyId, Integer projectId,Integer taskType,List<Integer> inchagerIds);
+    Integer getProjectTaskCount(Integer companyId, Integer projectId,Integer groupId,Integer taskType,List<Integer> inchagerIds);
 
     List getTaskWithProjectName(@Param(Constants.WRAPPER) Wrapper wrapper, Integer pageStart, Integer pageSize,Integer companyId,List<Integer> deptIds);
 

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

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

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

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

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

@@ -34,7 +34,7 @@ public interface DepartmentService extends IService<Department> {
 
     HttpRespMsg getUserStatistics(String startDate, String endDate, Integer departmentId, HttpServletRequest request);
 
-    HttpRespMsg exportUserStatistic(String startDate, String endDate, String userIds, HttpServletRequest request);
+    HttpRespMsg exportUserStatistic(boolean mainProjectColumn, String startDate, String endDate, String userIds, HttpServletRequest request);
 
     HttpRespMsg listAllMemb(HttpServletRequest request,String keyword,String cursor) throws Exception;
 

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

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

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

@@ -0,0 +1,16 @@
+package com.management.platform.service;
+
+import com.management.platform.entity.GroupBudgetReview;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ *  服务类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2023-12-28
+ */
+public interface GroupBudgetReviewService extends IService<GroupBudgetReview> {
+
+}

+ 5 - 3
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/ProjectService.java

@@ -70,7 +70,7 @@ public interface ProjectService extends IService<Project> {
 
     HttpRespMsg getAllMembCost(String startDate, String endDate, Integer projectId, HttpServletRequest request);
 
-    HttpRespMsg exportTimeCost(String exportContent,String startDate, String endDate, Integer projectId,String userIds, Boolean projectSum,Integer type,Integer deptId,Integer stateKey, Integer withPercent, HttpServletRequest request);
+    HttpRespMsg exportTimeCost(Integer withMainProject, String exportContent,String startDate, String endDate, Integer projectId,String userIds, Boolean projectSum,Integer type,Integer deptId,Integer stateKey, Integer withPercent,Integer projectCategoryId, HttpServletRequest request);
 
     HttpRespMsg updateProgress(Integer id, Integer progress, HttpServletRequest request);
 
@@ -92,7 +92,7 @@ public interface ProjectService extends IService<Project> {
 
     HttpRespMsg exportProject(HttpServletRequest request);
 
-    HttpRespMsg getProjectTask(Integer pageIndex, Integer pageSize, Integer projectId, HttpServletRequest request,Integer taskType);
+    HttpRespMsg getProjectTask(Integer pageIndex, Integer pageSize, Integer projectId,Integer groupId, HttpServletRequest request,Integer taskType);
 
     HttpRespMsg exportProjectTask(HttpServletRequest request,Integer taskType);
 
@@ -263,11 +263,13 @@ public interface ProjectService extends IService<Project> {
 
     HttpRespMsg getFunWorkContextList(Integer id);
 
-    HttpRespMsg syncProjectWithSap(String startDate,String endDate);
+    HttpRespMsg syncProjectWithSap(String startDate,String endDate,String projectCodes);
 
     HttpRespMsg getEffectiveLaborHourRate(String startDate, String endDate);
 
     HttpRespMsg getProjectEstimatedWork(Integer pageIndex, Integer pageSize, Integer projectId, HttpServletRequest request);
 
     HttpRespMsg getProjectFillTime(HttpServletRequest request, Integer projectId);
+
+    HttpRespMsg getMembProjectCateRatio(String startDate, String endDate, Integer onlyShowWarning);
 }

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

@@ -139,4 +139,8 @@ public interface ReportService extends IService<Report> {
     HttpRespMsg geProjectTimeCostByThird(String json);
 
     HttpRespMsg getUserTimeCostByThird(String json);
+
+    HttpRespMsg getUserWorkTimeByCategory(Integer categoryId, Integer deptId, String userId, String startDate, String endDate, Integer pageIndex, Integer pageSize);
+
+    HttpRespMsg exportUserWorkTimeByCategory(Integer categoryId, Integer deptId, String userId, String startDate, String endDate);
 }

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

@@ -37,7 +37,7 @@ public interface TaskService extends IService<Task> {
 
     HttpRespMsg exportTask(Integer projectId, Integer taskType);
 
-    HttpRespMsg importTask(Integer projectId, Integer groupId, MultipartFile file, HttpServletRequest request);
+    HttpRespMsg importTask(Integer isMultiProject, Integer projectId, Integer groupId, MultipartFile file, HttpServletRequest request) throws Exception;
 
     HttpRespMsg delete(TaskGroup item);
 

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

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

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

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

+ 144 - 62
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/DepartmentServiceImpl.java

@@ -664,7 +664,7 @@ public class DepartmentServiceImpl extends ServiceImpl<DepartmentMapper, Departm
     }
 
     @Override
-    public HttpRespMsg exportUserStatistic(String startDate, String endDate, String userIds, HttpServletRequest request) {
+    public HttpRespMsg exportUserStatistic(boolean mainProjectColumn,  String startDate, String endDate, String userIds, HttpServletRequest request) {
         HttpRespMsg httpRespMsg = new HttpRespMsg();
         try {
             User targetUser = userMapper.selectById(request.getHeader("Token"));
@@ -710,47 +710,88 @@ public class DepartmentServiceImpl extends ServiceImpl<DepartmentMapper, Departm
 
             List<Map<String, Object>> list = departmentMapper
                     .getCostByUser(deptIds, startDate, endDate, companyId, allUserIds);
-            Map<String, List<Map<String, Object>>> tempMap = new HashMap<>();
-            List<String> names = new ArrayList<>();
+//            Map<String, List<Map<String, Object>>> tempMap = new HashMap<>();
+            List<Map> userListMap = new ArrayList<>();
             BigDecimal totalCostMoney = new BigDecimal(0);
+            double totalTime = 0;
             for (Map<String, Object> map : list) {
-                if (tempMap.containsKey(map.get("id"))) {
-                    //这个名字已经装进数组中了
-                    List<Map<String, Object>> tempList;
-                    tempList = tempMap.get(map.get("id"));
-                    Map<String, Object> dataMap = new HashMap<>();
-                    dataMap.put("project", map.get("project"));
-                    BigDecimal money = (BigDecimal) map.getOrDefault("money", 0);
-                    Double time = (Double) map.getOrDefault("time", 0);
-                    totalCostMoney = totalCostMoney.add(money);
-                    dataMap.put("money", money);
-                    dataMap.put("time", time);
-                    tempList.add(dataMap);
+                String uid = (String) map.get("id");
+                double time = (double) map.getOrDefault("time", 0);
+                BigDecimal money = (BigDecimal) map.getOrDefault("money", 0);
+                totalCostMoney = totalCostMoney.add(money);
+                totalTime += time;
+                Optional<Map> find = userListMap.stream().filter(um -> um.get("id").equals(uid)).findFirst();
+                if (find.isPresent()) {
+                    Map userMap = find.get();
+                    //累加数据
+                    userMap.put("time", ((Double) userMap.get("time")) + time);
+                    userMap.put("money", ((BigDecimal) userMap.get("money")).add(money));
+                    Object data = userMap.get("data");
+                    List<Map<String, Object>> tempList = (List<Map<String, Object>>) data;
+                    tempList.add(map);
                 } else {
-                    names.add((String)map.get("id"));
+                    Map<String, Object> userMap = new HashMap<>();
+                    userMap.put("id", map.get("id"));
+                    userMap.put("name", map.get("user"));
+                    userMap.put("jobNumber", map.get("jobNumber"));
+                    userMap.put("corpwxUserId", "corpwxUserId");
+                    //添加工时和成本
+                    userMap.put("time", time);
+                    userMap.put("money", money);
+                    userListMap.add(userMap);
                     //这个名字尚未装进数组中
                     List<Map<String, Object>> tempList = new ArrayList<>();
-                    if (map.containsKey("project")) {
-                        Map<String, Object> dataMap = new HashMap<>();
-                        dataMap.put("project", map.get("project"));
-                        BigDecimal money = (BigDecimal) map.getOrDefault("money", 0);
-                        Double time = (Double) map.getOrDefault("time", 0);
-                        totalCostMoney = totalCostMoney.add(money);
-                        dataMap.put("money", money);
-                        dataMap.put("time", time);
-                        tempList.add(dataMap);
+                    tempList.add(map);
+                    userMap.put("data", tempList);
+                }
+            }
+            if (mainProjectColumn) {
+                //带主项目的模式,二次处理数据
+                List<Map<String, Object>> finalList = new ArrayList<>();
+                for (Map<String, Object> map : userListMap) {
+                    List<Map<String, Object>> tempList = (List<Map<String, Object>>)map.get("data");
+                    List<Map<String, Object>> mainPList = new ArrayList<>();
+                    //按照主项目进行分类
+                    for (Map<String, Object> membData : tempList) {
+                        Integer projectMainId = (Integer) membData.get("projectMainId") == null?0:(Integer) membData.get("projectMainId");
+                        String projectMainName = membData.get("mainProjectName") == null?"无主项目":(String) membData.get("mainProjectName");
+                        Optional<Map<String, Object>> find = mainPList.stream().filter(mp -> mp.get("projectMainId").equals(projectMainId)).findFirst();
+                        if (find.isPresent()) {
+                            //累加数据
+                            Map<String, Object> mainProject = find.get();
+                            mainProject.put("money", ((BigDecimal) mainProject.get("money")).add((BigDecimal) membData.getOrDefault("money", 0)));
+                            mainProject.put("time", ((Double) mainProject.get("time")) + ((Double) membData.getOrDefault("time", 0)));
+                            List<Map<String, Object>> projectList = (List<Map<String, Object>>) mainProject.get("project");
+                            projectList.add(membData);
+                        } else {
+                            Map<String, Object> mainProject = new HashMap<>();
+                            mainProject.put("projectMainId", projectMainId);
+                            mainProject.put("mainProjectCode", membData.get("mainProjectCode"));
+                            mainProject.put("mainProjectName", projectMainName);
+                            mainProject.put("money", membData.getOrDefault("money", 0));
+                            mainProject.put("time", membData.getOrDefault("time", 0));
+                            List<Map<String, Object>> projectList = new ArrayList<>();
+                            projectList.add(membData);
+                            mainProject.put("project", projectList);
+                            mainPList.add(mainProject);
+                        }
                     }
-                    tempMap.put((String) map.get("id"), tempList);
+                    //添加主项目列表
+                    map.put("mainPList", mainPList);
                 }
             }
-//            Map<String, Object> finalMap = new HashMap<>();
-//            List<Map<String, Object>> finalList = new ArrayList<>();
             DecimalFormat df = new DecimalFormat("#0.00");
             df.setRoundingMode(RoundingMode.HALF_UP);
             List<List<String>> dataList = new ArrayList<List<String>>();
             List<String> titleList =new ArrayList<>();
             //titleList.add("人员");
             titleList.add(MessageUtils.message("entry.personnel"));
+            if (mainProjectColumn) {
+                //titleList.add("项目");
+                titleList.add("主项目编号");
+                titleList.add("主项目名称");
+            }
+            titleList.add("项目编号");
             //titleList.add("项目");
             titleList.add(MessageUtils.message("entry.project"));
             if(functionTimeList.size()>0){
@@ -764,48 +805,84 @@ public class DepartmentServiceImpl extends ServiceImpl<DepartmentMapper, Departm
             dataList.add(titleList);
             BigDecimal totalMoneyCost = BigDecimal.valueOf(0);
             double totalCostTime = 0;
-            for (String key : names) {
-                List<String> nameList = new ArrayList<String>();
+            for (Map userItem : userListMap) {
+                String uid = (String) userItem.get("id");
+
                 String name;
                 if(wxCorpInfo!=null&&wxCorpInfo.getSaasSyncContact()==1){
-                    String corpwxUserId = userList.stream().filter(ul -> ul.getId().equals(key)).findFirst().get().getCorpwxUserid();
+                    String corpwxUserId = userList.stream().filter(ul -> ul.getId().equals(uid)).findFirst().get().getCorpwxUserid();
                     name ="$userName="+ (corpwxUserId==null?"":corpwxUserId) +"$";
                 }else {
-                     name = userList.stream().filter(ul -> ul.getId().equals(key)).findFirst().get().getName();
-                }
-                nameList.add(name);//姓名
-                nameList.add("");//空着
-                List<Map<String, Object>> tempList = tempMap.get(key);
-                //统计个人的时间和成本
-                double tTime = 0;
-                BigDecimal tCost = new BigDecimal(0);
-                for (Map<String, Object> membData : tempList) {
-                    tTime += (double)membData.get("time");
-                    tCost = tCost.add((BigDecimal)membData.get("money"));
+                     name = userList.stream().filter(ul -> ul.getId().equals(uid)).findFirst().get().getName();
                 }
-                totalMoneyCost = totalMoneyCost.add(tCost);
-                totalCostTime += tTime;
-                if(functionTimeList.size()>0){
-                    nameList.add(df.format(tTime));
-                }
-                if(functionCostList.size()>0){
-                    nameList.add(tCost.setScale(2, BigDecimal.ROUND_UP).toString());
-                }
-                dataList.add(nameList);
-                //装载该人员下的项目的工时数据
-                for (Map<String, Object> membData : tempList) {
-                    tTime += (double)membData.get("time");
-                    tCost.add((BigDecimal)membData.get("money"));
-                    List<String> projectDataList = new ArrayList<>();
-                    projectDataList.add("");
-                    projectDataList.add(membData.get("project")+"");
+                if (mainProjectColumn) {
+                    List<Map<String, Object>> mainPList = (List<Map<String, Object>>)userItem.get("mainPList");
+                    for (Map<String, Object> mainP : mainPList) {
+                        List<String> nameList = new ArrayList<String>();
+                        nameList.add(name);//姓名
+                        nameList.add((String)mainP.get("mainProjectCode"));//主项目编号
+                        nameList.add((String)mainP.get("mainProjectName"));//主项目名称
+                        nameList.add("");
+                        nameList.add("");
+                        if(functionTimeList.size()>0){
+                            nameList.add(df.format((double)mainP.get("time")));
+                        }
+                        if(functionCostList.size()>0){
+                            nameList.add(((BigDecimal)mainP.get("money")).setScale(2, BigDecimal.ROUND_UP).toString());
+                        }
+                        dataList.add(nameList);
+                        //添加主项目下的子项目
+                        List<Map<String, Object>> tempList = (List<Map<String, Object>>)mainP.get("project");
+                        for (Map<String, Object> membData : tempList) {
+                            List<String> projectDataList = new ArrayList<>();
+                            projectDataList.add("");
+                            projectDataList.add("");
+                            projectDataList.add("");
+                            projectDataList.add((String)membData.get("projectCode"));
+                            projectDataList.add((String)membData.get("project"));
+                            if(functionTimeList.size()>0){
+                                projectDataList.add(df.format((double)membData.get("time")));
+                            }
+                            if(functionCostList.size()>0){
+                                projectDataList.add(((BigDecimal)membData.get("money")).setScale(2, BigDecimal.ROUND_UP).toString());
+                            }
+                            dataList.add(projectDataList);
+                        }
+                    }
+                } else {
+                    List<String> nameList = new ArrayList<String>();
+                    nameList.add(name);//姓名
+                    nameList.add("");//项目编号
+                    nameList.add("");//项目名称
+                    List<Map<String, Object>> tempList = (List<Map<String, Object>>)userItem.get("data");
+                    //统计个人的时间和成本
+                    double tTime = 0;
+                    BigDecimal tCost = new BigDecimal(0);
+                    for (Map<String, Object> membData : tempList) {
+                        tTime += (double)membData.get("time");
+                        tCost = tCost.add((BigDecimal)membData.get("money"));
+                    }
                     if(functionTimeList.size()>0){
-                        projectDataList.add(df.format((double)membData.get("time"))+"");
+                        nameList.add(df.format(tTime));
                     }
                     if(functionCostList.size()>0){
-                        projectDataList.add(((BigDecimal)membData.get("money")).setScale(2, BigDecimal.ROUND_UP).toString());
+                        nameList.add(tCost.setScale(2, BigDecimal.ROUND_UP).toString());
+                    }
+                    dataList.add(nameList);
+                    //装载该人员下的项目的工时数据
+                    for (Map<String, Object> membData : tempList) {
+                        List<String> projectDataList = new ArrayList<>();
+                        projectDataList.add("");
+                        projectDataList.add(membData.get("projectCode")+"");
+                        projectDataList.add(membData.get("project")+"");
+                        if(functionTimeList.size()>0){
+                            projectDataList.add(df.format((double)membData.get("time"))+"");
+                        }
+                        if(functionCostList.size()>0){
+                            projectDataList.add(((BigDecimal)membData.get("money")).setScale(2, BigDecimal.ROUND_UP).toString());
+                        }
+                        dataList.add(projectDataList);
                     }
-                    dataList.add(projectDataList);
                 }
             }
             String total = totalMoneyCost.setScale(2, BigDecimal.ROUND_UP).toString();
@@ -814,7 +891,12 @@ public class DepartmentServiceImpl extends ServiceImpl<DepartmentMapper, Departm
             //sumRow.add("合计");
             //sumRow.add("合计");
             sumRow.add(MessageUtils.message("entry.total"));
-            sumRow.add("");
+            if (mainProjectColumn) {
+                sumRow.add("");
+                sumRow.add("");
+            }
+            sumRow.add("");//项目编号
+            sumRow.add("");//项目名称
             if(functionTimeList.size()>0){
                 sumRow.add(""+df.format(totalCostTime));
             }

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

@@ -20,6 +20,7 @@ import org.springframework.transaction.annotation.Transactional;
 import javax.annotation.Resource;
 import java.io.File;
 import java.io.FileOutputStream;
+import java.time.LocalDateTime;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -81,14 +82,22 @@ public class ExcelExportServiceImpl implements ExcelExportService {
              * 异步上传转译文件的任务完成时会触发回调,在WeiXinCorpController中的commonDevCallbackPost实现了对回调的处理,存储到corpwxJobResult表中
              * 此处轮询查询本地数据库,检测到有任务的回调数据时继续执行查询操作
              */
-            while (i < 10) {
-                Thread.sleep(300);
+            long t = System.currentTimeMillis();
+            while (i < 30) {
+                if (i < 10) {
+                    Thread.sleep(300);
+                } else {
+                    Thread.sleep(1000);
+                }
+                System.out.println("i=="+i+", "+LocalDateTime.now());
                 CorpwxJobResult corpwxJobResult = corpwxJobCenter.get(jobId);
                 if (corpwxJobResult != null) {
                     if (corpwxJobResult.getErrCode() == 0) {
                         syncTranslationResult = wxCorpInfoService.getSyncTranslationResult(jobId);
                         corpwxJobCenter.remove(jobId);
                     } else {
+                        long t2 = System.currentTimeMillis();
+                        System.out.println("222企业微信转译报错:"+corpwxJobResult.getErrMsg()+",耗时:" + (t2 - t) + "ms");
                         httpRespMsg.setError(corpwxJobResult.getErrMsg());
                         return httpRespMsg;
                     }
@@ -97,6 +106,8 @@ public class ExcelExportServiceImpl implements ExcelExportService {
                 i++;
             }
             if (syncTranslationResult != null) {
+                long t2 = System.currentTimeMillis();
+                System.out.println("企业微信转译文件后地址是:"+syncTranslationResult+",耗时:" + (t2 - t) + "ms");
                 httpRespMsg.data = syncTranslationResult;
             } else {
                 //httpRespMsg.setError("处理超时...");

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

@@ -0,0 +1,20 @@
+package com.management.platform.service.impl;
+
+import com.management.platform.entity.ExpensePayWay;
+import com.management.platform.mapper.ExpensePayWayMapper;
+import com.management.platform.service.ExpensePayWayService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ *  服务实现类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2024-01-09
+ */
+@Service
+public class ExpensePayWayServiceImpl extends ServiceImpl<ExpensePayWayMapper, ExpensePayWay> implements ExpensePayWayService {
+
+}

+ 28 - 12
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ExpenseSheetServiceImpl.java

@@ -119,13 +119,6 @@ public class ExpenseSheetServiceImpl extends ServiceImpl<ExpenseSheetMapper, Exp
                 //项目经理审核,默认为待审核状态
                 sheet.setStatus(1);
             }else if(auditSetting.getAuditType()==2){
-                if(sheet.getFirstCheckerId().equals(user.getId())){
-                    sheet.setReviewProcess(1);
-                    sheet.setStatus(1);
-                }else if(sheet.getFirstCheckerId().equals(user.getId())&&sheet.getSecondCheckerId().equals(user.getId())){
-                    sheet.setReviewProcess(2);
-                    sheet.setStatus(0);
-                }
                 if (sheet.getStatus() == null) {
                     sheet.setStatus(1);//默认提交时为待审核状态
                 }
@@ -152,6 +145,10 @@ public class ExpenseSheetServiceImpl extends ServiceImpl<ExpenseSheetMapper, Exp
                 } else if (auditSetting.getAuditType() == 1) {
                     //项目经理审核,默认为待审核状态
                     sheet.setStatus(1);
+                }else if (auditSetting.getAuditType() == 2) {
+                    if (sheet.getStatus() == null) {
+                        sheet.setStatus(1);//默认提交时为待审核状态
+                    }
                 }
             }
         }
@@ -289,7 +286,9 @@ public class ExpenseSheetServiceImpl extends ServiceImpl<ExpenseSheetMapper, Exp
                 System.out.println("设置状态为待审核"+itemList.size());
                 itemList.forEach(item->item.setStatus(1));
                 expenseItemService.remove(new QueryWrapper<ExpenseItem>().eq("expense_id", sheet.getId()).ne("status", 0));
-                expenseItemService.saveOrUpdateBatch(itemList);
+                if (itemList.size() > 0) {
+                    expenseItemService.saveOrUpdateBatch(itemList);
+                }
             }
         } else {
             //新增时都是待审核
@@ -416,6 +415,7 @@ public class ExpenseSheetServiceImpl extends ServiceImpl<ExpenseSheetMapper, Exp
     @Override
     public HttpRespMsg queryList(ExpenseSheet sheet, String startDate, String endDate, Integer pageIndex, Integer pageSize) {
         QueryWrapper<ExpenseSheet> queryWrapper = new QueryWrapper<ExpenseSheet>();
+        //当前用户
         String token = request.getHeader("TOKEN");
         HttpRespMsg httpRespMsg = new HttpRespMsg();
         queryWrapper.eq("company_id", sheet.getCompanyId()).orderByDesc("id");
@@ -433,8 +433,18 @@ public class ExpenseSheetServiceImpl extends ServiceImpl<ExpenseSheetMapper, Exp
         }
 
         if (expenseAuditSetting == null || expenseAuditSetting.getAuditType() == 0) {
-            if (!StringUtils.isEmpty(sheet.getOwnerId())) {
-                queryWrapper.eq("owner_id", sheet.getOwnerId());
+            if (sheet.getStatus() != null &&  sheet.getStatus() == 1) {
+                //待审核列表,检查是否有权限
+                User user = userMapper.selectById(token);
+                List<SysRichFunction> functionList = sysFunctionMapper.getRoleFunctions(user.getRoleId(), "费用审核");
+                if (functionList.size() == 0) {
+                    //无权查看待审核
+                    queryWrapper.eq("id", -1);
+                }
+            } else {
+                if (!StringUtils.isEmpty(sheet.getOwnerId())) {
+                    queryWrapper.eq("owner_id", sheet.getOwnerId());
+                }
             }
         } else if(expenseAuditSetting.getAuditType() == 1){
             //增加按项目经理审核模式下,项目经理可以查看相关费用报销单的条件
@@ -568,11 +578,11 @@ public class ExpenseSheetServiceImpl extends ServiceImpl<ExpenseSheetMapper, Exp
     public HttpRespMsg getDetail(Integer id) {
         String token = request.getHeader("TOKEN");
         ExpenseSheet expenseSheet = expenseSheetMapper.selectById(id);
-        if(expenseSheet.getFirstCheckerId()!=null){
+        if(!StringUtils.isEmpty(expenseSheet.getFirstCheckerId())){
             User user = userMapper.selectById(expenseSheet.getFirstCheckerId());
             expenseSheet.setFirstCheckerName(user.getName());
         }
-        if(expenseSheet.getSecondCheckerId()!=null){
+        if(!StringUtils.isEmpty(expenseSheet.getSecondCheckerId())){
             User user = userMapper.selectById(expenseSheet.getSecondCheckerId());
             expenseSheet.setSecondCheckerName(user.getName());
         }
@@ -674,6 +684,12 @@ public class ExpenseSheetServiceImpl extends ServiceImpl<ExpenseSheetMapper, Exp
         }else {
             sheet.setStatus(0);
         }
+        //同时审核所有item数据
+        List<ExpenseItem> items = expenseItemMapper.selectList(new LambdaQueryWrapper<ExpenseItem>().eq(ExpenseItem::getExpenseId, sheet.getId()));
+        items.forEach(i->{
+            i.setStatus(0);
+        });
+        expenseItemService.updateBatchById(items);
 
         expenseSheetMapper.updateById(sheet);
 

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

@@ -0,0 +1,20 @@
+package com.management.platform.service.impl;
+
+import com.management.platform.entity.GroupBudgetReview;
+import com.management.platform.mapper.GroupBudgetReviewMapper;
+import com.management.platform.service.GroupBudgetReviewService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ *  服务实现类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2023-12-28
+ */
+@Service
+public class GroupBudgetReviewServiceImpl extends ServiceImpl<GroupBudgetReviewMapper, GroupBudgetReview> implements GroupBudgetReviewService {
+
+}

+ 43 - 11
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/LeaveSheetServiceImpl.java

@@ -473,18 +473,50 @@ public class LeaveSheetServiceImpl extends ServiceImpl<LeaveSheetMapper, LeaveSh
 
     @Override
     public HttpRespMsg getOTAvaiDays(String userId) {
-        //非驳回和撤回状态的都要统计进去
-        List<LeaveSheet> list = leaveSheetMapper.selectList(new QueryWrapper<LeaveSheet>().eq("owner_id", userId).eq("leave_type", exLeaveDay).ne("status", 2).ne("status", 3));
-        double alreadyHours = list.stream().mapToDouble(LeaveSheet::getTimeHours).sum();
-        double overtime = reportMapper.getMyOvertime(userId);
-        double leftHours = overtime - alreadyHours;
-        if (leftHours < 0) {
-            leftHours = 0;
-        }
-        float allDayHours = timeTypeMapper.selectById(userMapper.selectById(userId).getCompanyId()).getAllday();
-        double d = leftHours/allDayHours;
         HttpRespMsg msg = new HttpRespMsg();
-        msg.data = d;
+        String startDate = null;
+        User user = userMapper.selectById(userId);
+
+        if (user.getCompanyId() == 7) {
+            //火石闪信,从2023年8月1日开始计算加班工时
+            startDate = "2023-08-01";
+            //获取startDate之前的,2023年的全部非工作日加班
+            String firstDay = "2023-01-01";
+            String endDate = startDate;
+            List<String> allHolidays = WorkDayCalculateUtils.getAllHolidays(firstDay, endDate);
+            double beforeHours = 0;
+            if (allHolidays.size() > 0) {
+                List<Report> reportList = reportMapper.selectList(new QueryWrapper<Report>().select("IFNULL(sum(overtime_hours),0) as working_time").in("create_date", allHolidays).eq("creator_id", userId));
+                double sum = reportList.stream().mapToDouble(Report::getWorkingTime).sum();
+                beforeHours = sum;
+            }
+
+            //只统计2023年1月1日之后的调休假
+            List<LeaveSheet> list = leaveSheetMapper.selectList(new QueryWrapper<LeaveSheet>()
+                    .eq("owner_id", userId).eq("leave_type", exLeaveDay).ne("status", 2).ne("status", 3).ge("start_date", firstDay));
+            double alreadyHours = list.stream().mapToDouble(LeaveSheet::getTimeHours).sum();
+            double overtime = reportMapper.getMyOvertime(userId, startDate);
+            double leftHours = beforeHours + overtime - alreadyHours;
+            if (leftHours < 0) {
+                leftHours = 0;
+            }
+            float allDayHours = timeTypeMapper.selectById(userMapper.selectById(userId).getCompanyId()).getAllday();
+            double d = leftHours/allDayHours;
+            msg.data = d;
+        } else {
+            //非驳回和撤回状态的都要统计进去
+            List<LeaveSheet> list = leaveSheetMapper.selectList(new QueryWrapper<LeaveSheet>().eq("owner_id", userId).eq("leave_type", exLeaveDay).ne("status", 2).ne("status", 3));
+            double alreadyHours = list.stream().mapToDouble(LeaveSheet::getTimeHours).sum();
+            double overtime = reportMapper.getMyOvertime(userId, startDate);
+            double leftHours = overtime - alreadyHours;
+            if (leftHours < 0) {
+                leftHours = 0;
+            }
+            float allDayHours = timeTypeMapper.selectById(userMapper.selectById(userId).getCompanyId()).getAllday();
+            double d = leftHours/allDayHours;
+            msg.data = d;
+        }
+
         return msg;
     }
 

+ 6 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/PermissionServiceImpl.java

@@ -219,6 +219,9 @@ public class PermissionServiceImpl extends ServiceImpl<PermissionMapper, Permiss
         }
         queryWrapper.orderByAsc("orderitem");
         List<SysModule> moduleList = sysModuleMapper.selectList(queryWrapper);
+        if(companyId!=3092){
+            moduleList=moduleList.stream().filter(m->!m.getName().equals("预估工时审核")).collect(Collectors.toList());
+        }
         //组装层级关系,默认只有两级
         List<SysModule> menuList = new ArrayList<>();
         QueryWrapper<SysFunction> functionQueryWrapper = new QueryWrapper<SysFunction>().and(wrapper->{
@@ -283,6 +286,9 @@ public class PermissionServiceImpl extends ServiceImpl<PermissionMapper, Permiss
             if(timeType.getPushReportData()!=1&&fun.getName().equals("手动推送工时")){
                 resultFunList.remove(fun);
             }
+            if(company.getId()!=3092&&fun.getName().equals("审核预估工时")){
+                resultFunList.remove(fun);
+            }
         }
         for (SysModule module : moduleList) {
             if(timeType.getProjectCustom()==0){

+ 464 - 127
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ProjectServiceImpl.java

@@ -64,6 +64,7 @@ import java.util.*;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
@@ -130,6 +131,8 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
     @Resource
     ProjectBasecostMapper projectBasecostMapper;
     @Resource
+    CategoryRatioTblSettingMapper categoryRatioTblSettingMapper;
+    @Resource
     CompanyMapper companyMapper;
     @Resource
     StagesMapper stagesMapper;
@@ -240,6 +243,8 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
 
     @Value(value = "${upload.path}")
     private String path;
+    @Value("${configEnv.isDev}")
+    public boolean isDev;
     //获取项目列表
     @Override
     public HttpRespMsg getProjectList(Integer forReport, HttpServletRequest request) {
@@ -773,7 +778,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                     }
                     if(timeType.getProjectManDay()==1){
                         project.setManDay(manDay);
-                        if (!StringUtils.isEmpty(planEndDate)) {
+                        if (!StringUtils.isEmpty(manDayStartDate)) {
                             project.setManDayStartDate(LocalDate.parse(manDayStartDate));
                         }
                     }
@@ -1433,7 +1438,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                 String[] split = userIds.split(",");
                 userIdList = Arrays.asList(split);
             }
-            List<Map<String, Object>> list = projectMapper.getTimeCost(companyId, startDate, endDate, projectId, userIdList,deptIds,null, deptRelatedProjectIds, projectIds, inchargeUserIds);
+            List<Map<String, Object>> list = projectMapper.getTimeCost(companyId, startDate, endDate, projectId, userIdList,deptIds,null, deptRelatedProjectIds, projectIds, inchargeUserIds,null);
             BigDecimal totalMoneyCost = BigDecimal.valueOf(0);
             for (Map<String, Object> map : list) {
                 if (!map.containsKey("cost")) {
@@ -1475,14 +1480,152 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
         return httpRespMsg;
     }
 
+    private HashMap fillMainProjectRowData(Integer projectMainId, Integer companyId, String startDate, String endDate, Integer stateKey, List<String> userIdList, List<Map<String, Object>> list,
+                                           List<UserCustom> userCustoms, List<SysRichFunction> functionTimeList, List<SysRichFunction> functionCostList,
+                                           String exportContent, List<User> userList, List<Integer> deptIds, List<Integer> deptRelatedProjectIds,
+                                           List<Integer> filterDeptIds, Boolean projectSum, WxCorpInfo wxCorpInfo) {
+        List<List<String>> allList = new ArrayList<List<String>>();
+        BigDecimal totalMoneyCost = new BigDecimal(0);
+        double totalCostTime = 0;
+        for (Map<String, Object> map : list) {
+            //只查找和当前主项目相关的项目
+            Integer pmid = (Integer)map.get("projectMainId");
+            if (projectMainId == null) {
+                if (pmid != null) {
+                    continue;
+                }
+            } else {
+                if (pmid == null || !pmid.equals(projectMainId)) {
+                    continue;
+                }
+            }
+            if (!map.containsKey("cost")) {
+                map.put("cost", 0);
+            }
+            if (!map.containsKey("costMoney")) {
+                map.put("costMoney", 0);
+            } else {
+                totalMoneyCost = totalMoneyCost.add((BigDecimal)map.get("costMoney"));
+            }
+            totalCostTime += (Double)map.get("cost");
+            List<String> rowData = new ArrayList<String>();
+            //空出两类主项目编号和名称
+            rowData.add("");
+            rowData.add("");
+            rowData.add((String)map.get("projectCode"));
+            rowData.add((String)map.get("project"));
+            rowData.add((String)map.get("categoryName"));
+            rowData.add("");
+            rowData.add("");
+            //针对项目合计行,自定义的字段要空出来
+            for (UserCustom userCustom : userCustoms) {
+                rowData.add("");
+            }
+            if ("hours".equals(exportContent) && functionTimeList.size()>0){
+                rowData.add(((Double)map.get("cost")).toString());
+            }else if ("cost".equals(exportContent) && functionCostList.size()>0){
+                rowData.add(((BigDecimal)map.get("costMoney")).toString());
+            }else {
+                if(functionTimeList.size()>0){
+                    rowData.add(((Double)map.get("cost")).toString());
+                }
+                if (functionCostList.size()>0){
+                    rowData.add(((BigDecimal)map.get("costMoney")).toString());
+                }
+            }
+            if (projectSum != null && projectSum == true) {
+                allList.add(rowData);
+            }
+            //统计每个项目中的人员时间成本投入
+            int curProjectId = (Integer)map.get("id");
+            //判断是否是当前项目的所属部门的主要或者其他负责人
+            List<Integer> finalDeptIds = null;
+            if (deptRelatedProjectIds.contains(curProjectId)) {
+                //有权限看该项目的全部参与人员,不需要按照部门过滤了
+            } else {
+                finalDeptIds = deptIds;
+            }
+            List<Map<String, Object>> membList = projectMapper.getProjectCost(companyId,startDate, endDate, curProjectId,stateKey, userIdList,finalDeptIds,filterDeptIds, true);
+            map.put("membList", membList);
+            for (Map<String, Object> membMap : membList) {
+                double pTotalTime = 0;
+                BigDecimal pTotalMoney = new BigDecimal(0);
+                List<String> membRowData = new ArrayList<String>();
+                if (projectSum == null || projectSum == false) {
+                    membRowData.add("");
+                    membRowData.add("");
+                    membRowData.add((String)map.get("projectCode"));
+                    membRowData.add((String)map.get("project"));
+                    membRowData.add((String)map.get("categoryName"));
+                } else {
+                    membRowData.add("");
+                    membRowData.add("");
+                    membRowData.add("");
+                    membRowData.add("");
+                    membRowData.add("");
+                }
+                if(wxCorpInfo!=null&&wxCorpInfo.getSaasSyncContact()==1){
+                    membRowData.add((String)("$userName="+membMap.get("corpwxUserId")+"$"));
+                    if(membMap.get("departmentName").equals("未分配")){
+                        membRowData.add("未分配");
+                    }else {
+                        membRowData.add((String)("$departmentName="+membMap.get("corpwxDeptId")+"$"));
+                    }
+                }else {
+                    membRowData.add((String)membMap.get("name"));
+                    membRowData.add((String)membMap.get("departmentName"));
+                }
+                String creatorId = (String)membMap.get("creatorId");
+                User us = userList.stream().filter(u->u.getId().equals(creatorId)).findFirst().get();
+                for (int i = 0; i < userCustoms.size(); i++) {
+                    switch (i){
+                        case 0:
+                            membRowData.add(us.getPlate1()==null?"":us.getPlate1());
+                            break;
+                        case 1:
+                            membRowData.add(us.getPlate2()==null?"":us.getPlate2());
+                            break;
+                        case 2:
+                            membRowData.add(us.getPlate3()==null?"":us.getPlate3());
+                            break;
+                        case 3:
+                            membRowData.add(us.getPlate4()==null?"":us.getPlate4());
+                            break;
+                        case 4:
+                            membRowData.add(us.getPlate5()==null?"":us.getPlate5());
+                            break;
+                    }
+                }
+                if ("hours".equals(exportContent) && functionTimeList.size()>0){
+                    membRowData.add(((Double)membMap.get("cost")).toString());
+                }else if ("cost".equals(exportContent) && functionCostList.size()>0){
+                    membRowData.add(((BigDecimal)membMap.get("costMoney")).toString());
+                }else {
+                    if(functionTimeList.size()>0){
+                        membRowData.add(((Double)membMap.get("cost")).toString());
+                    }
+                    if (functionCostList.size()>0){
+                        membRowData.add(((BigDecimal)membMap.get("costMoney")).toString());
+                    }
+                }
+                allList.add(membRowData);
+            }
+        }
+        HashMap map = new HashMap();
+        map.put("totalMoneyCost", totalMoneyCost);
+        map.put("totalCostTime", totalCostTime);
+        map.put("allList", allList);
+        return map;
+    }
+
     //导出查询者所在公司每个项目的工时成本,包括项目人员明细统计
     @Override
-    public HttpRespMsg exportTimeCost(String exportContent,String startDate, String endDate,Integer projectId, String userIds,
-                                        Boolean projectSum,Integer type,Integer deptId, Integer stateKey, Integer withPercent, HttpServletRequest request) {
+    public HttpRespMsg exportTimeCost(Integer withMainProject, String exportContent,String startDate, String endDate,Integer projectId, String userIds,
+                                        Boolean projectSum,Integer type,Integer deptId, Integer stateKey, Integer withPercent,Integer projectCategoryId, HttpServletRequest request) {
         HttpRespMsg httpRespMsg = new HttpRespMsg();
         try {
             User targetUser = userMapper.selectById(request.getHeader("Token"));
-            Integer companyId =targetUser.getCompanyId();
+            Integer companyId = targetUser.getCompanyId();
             WxCorpInfo wxCorpInfo = wxCorpInfoMapper.selectOne(new QueryWrapper<WxCorpInfo>().eq("company_id", companyId));
             Map<String, Object> resultMap = new HashMap<>();
             //当前用户管理部门
@@ -1557,13 +1700,29 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                 String[] split = userIds.split(",");
                 userIdList = Arrays.asList(split);
             }
-            List<Map<String, Object>> list = projectMapper.getTimeCost(companyId, startDate, endDate, projectId, userIdList,deptIds,filterDeptIds,deptRelatedProjectIds, manProjectIds, inchargeUserIds);
+            List<Map<String, Object>> list = projectMapper.getTimeCost(companyId, startDate, endDate, projectId, userIdList,deptIds,filterDeptIds,deptRelatedProjectIds, manProjectIds, inchargeUserIds,projectCategoryId);
             BigDecimal totalMoneyCost = BigDecimal.valueOf(0);
             List<List<String>> allList=null ;
             List<String> sumRow = null;
             List<UserCustom> userCustoms = userCustomMapper.selectList(new QueryWrapper<UserCustom>().eq("company_id", companyId));
-            if(type==0){
+            //按主项目导出时,项目固定在行上
+            if(type==0 || withMainProject == 1){
+                //取主项目
+                List<Integer> mainPidList = list.stream().map(m -> (Integer)m.get("projectMainId")).distinct().collect(Collectors.toList());
+                //查找有没有未分类的
+                boolean hasNoMainProject = list.stream().anyMatch(m -> m.get("projectMainId") == null);
+                List<ProjectMain> mainProjectList = new ArrayList<>();
+                if (mainPidList.size() > 0) {
+                    mainProjectList = projectMainMapper.selectList(new QueryWrapper<ProjectMain>().in("id", mainPidList));
+                }
+
+
                 List<String> headList = new ArrayList<String>();
+                if (withMainProject == 1) {
+                    //增加主项目合计的一行
+                    headList.add("主项目编号");
+                    headList.add("主项目名称");
+                }
                 //headList.add("项目编号");
                 headList.add(MessageUtils.message("entry.projectId"));
                 //headList.add("项目名称");
@@ -1598,119 +1757,165 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                 allList=new ArrayList<>();
                 allList.add(headList);
                 double totalCostTime = 0;
-                for (Map<String, Object> map : list) {
-                    if (!map.containsKey("cost")) {
-                        map.put("cost", 0);
-                    }
-                    if (!map.containsKey("costMoney")) {
-                        map.put("costMoney", 0);
-                    } else {
-                        totalMoneyCost = totalMoneyCost.add((BigDecimal)map.get("costMoney"));
-                    }
-                    totalCostTime += (Double)map.get("cost");
-                    List<String> rowData = new ArrayList<String>();
-                    rowData.add((String)map.get("projectCode"));
-                    rowData.add((String)map.get("project"));
-                    rowData.add((String)map.get("categoryName"));
-                    rowData.add("");
-                    rowData.add("");
-                    //针对项目合计行,自定义的字段要空出来
-                    for (UserCustom userCustom : userCustoms) {
-                        rowData.add("");
-                    }
-                    if ("hours".equals(exportContent) && functionTimeList.size()>0){
-                        rowData.add(((Double)map.get("cost")).toString());
-                    }else if ("cost".equals(exportContent) && functionCostList.size()>0){
-                        rowData.add(((BigDecimal)map.get("costMoney")).toString());
-                    }else {
+                if (withMainProject == 1) {
+                    //主项目模式下的导出数据
+                    //存在无主项目的数据,放在最后
+                    if (hasNoMainProject) {
+                        ProjectMain noMainProject = new ProjectMain();
+                        noMainProject.setName("无主项目");
+                        mainProjectList.add(noMainProject);
+                    }
+                    for (ProjectMain mainP : mainProjectList) {
+                        HashMap sumData = fillMainProjectRowData(mainP.getId(), companyId, startDate, endDate, stateKey, userIdList, list, userCustoms, functionTimeList, functionCostList, exportContent, userList, deptIds, deptRelatedProjectIds, filterDeptIds, projectSum, wxCorpInfo);
+                        totalMoneyCost = totalMoneyCost.add((BigDecimal)sumData.get("totalMoneyCost"));
+                        totalCostTime += (double)sumData.get("totalCostTime");
+                        //增加主项目合计的一行
+                        List<String> mainProjectRowData = new ArrayList<String>();
+                        mainProjectRowData.add(mainP.getCode());
+                        mainProjectRowData.add(mainP.getName());
+                        mainProjectRowData.add("");//项目编号
+                        mainProjectRowData.add("");//项目名称
+                        mainProjectRowData.add("");//项目分类
+                        mainProjectRowData.add("");//姓名
+                        mainProjectRowData.add("");//部门
+                        //针对项目合计行,自定义的字段要空出来
+                        for (UserCustom userCustom : userCustoms) {
+                            mainProjectRowData.add("");
+                        }
+
                         if(functionTimeList.size()>0){
-                            rowData.add(((Double)map.get("cost")).toString());
+                            mainProjectRowData.add(((Double)sumData.get("totalCostTime")).toString());
                         }
                         if (functionCostList.size()>0){
-                            rowData.add(((BigDecimal)map.get("costMoney")).toString());
+                            mainProjectRowData.add(((BigDecimal)sumData.get("totalMoneyCost")).toString());
                         }
+                        allList.add(mainProjectRowData);
+                        //增加主项目下的项目列表
+                        allList.addAll((List<List<String>>)sumData.get("allList"));
                     }
-                    if (projectSum != null && projectSum == true) {
-                        allList.add(rowData);
-                    }
-                    //统计每个项目中的人员时间成本投入
-                    int curProjectId = (Integer)map.get("id");
-                    //判断是否是当前项目的所属部门的主要或者其他负责人
-                    List<Integer> finalDeptIds = null;
-                    if (deptRelatedProjectIds.contains(curProjectId)) {
-                        //有权限看该项目的全部参与人员,不需要按照部门过滤了
-                    } else {
-                        finalDeptIds = deptIds;
-                    }
-                    List<Map<String, Object>> membList = projectMapper.getProjectCost(companyId,startDate, endDate, curProjectId,stateKey, userIdList,finalDeptIds,filterDeptIds, true);
-                    map.put("membList", membList);
-                    for (Map<String, Object> membMap : membList) {
-                        double pTotalTime = 0;
-                        BigDecimal pTotalMoney = new BigDecimal(0);
-                        List<String> membRowData = new ArrayList<String>();
-                        if (projectSum == null || projectSum == false) {
-                            membRowData.add((String)map.get("projectCode"));
-                            membRowData.add((String)map.get("project"));
-                            membRowData.add((String)map.get("categoryName"));
-
+                } else {
+                    //常规项目的工时导出
+                    for (Map<String, Object> map : list) {
+                        if (!map.containsKey("cost")) {
+                            map.put("cost", 0);
+                        }
+                        if (!map.containsKey("costMoney")) {
+                            map.put("costMoney", 0);
                         } else {
-                            membRowData.add("");
-                            membRowData.add("");
-                            membRowData.add("");
-
+                            totalMoneyCost = totalMoneyCost.add((BigDecimal)map.get("costMoney"));
                         }
-                        if(wxCorpInfo!=null&&wxCorpInfo.getSaasSyncContact()==1){
-                            membRowData.add((String)("$userName="+membMap.get("corpwxUserId")+"$"));
-                            if(membMap.get("departmentName").equals("未分配")){
-                                membRowData.add("未分配");
-                            }else {
-                                membRowData.add((String)("$departmentName="+membMap.get("corpwxDeptId")+"$"));
-                            }
-                        }else {
-                            membRowData.add((String)membMap.get("name"));
-                            membRowData.add((String)membMap.get("departmentName"));
-                        }
-                        String creatorId = (String)membMap.get("creatorId");
-                        User us = userList.stream().filter(u->u.getId().equals(creatorId)).findFirst().get();
-                        for (int i = 0; i < userCustoms.size(); i++) {
-                            switch (i){
-                                case 0:
-                                    membRowData.add(us.getPlate1()==null?"":us.getPlate1());
-                                    break;
-                                case 1:
-                                    membRowData.add(us.getPlate2()==null?"":us.getPlate2());
-                                    break;
-                                case 2:
-                                    membRowData.add(us.getPlate3()==null?"":us.getPlate3());
-                                    break;
-                                case 3:
-                                    membRowData.add(us.getPlate4()==null?"":us.getPlate4());
-                                    break;
-                                case 4:
-                                    membRowData.add(us.getPlate5()==null?"":us.getPlate5());
-                                    break;
-                            }
+                        totalCostTime += (Double)map.get("cost");
+                        List<String> rowData = new ArrayList<String>();
+                        rowData.add((String)map.get("projectCode"));
+                        rowData.add((String)map.get("project"));
+                        rowData.add((String)map.get("categoryName"));
+                        rowData.add("");
+                        rowData.add("");
+                        //针对项目合计行,自定义的字段要空出来
+                        for (UserCustom userCustom : userCustoms) {
+                            rowData.add("");
                         }
                         if ("hours".equals(exportContent) && functionTimeList.size()>0){
-                            membRowData.add(((Double)membMap.get("cost")).toString());
+                            rowData.add(((Double)map.get("cost")).toString());
                         }else if ("cost".equals(exportContent) && functionCostList.size()>0){
-                            membRowData.add(((BigDecimal)membMap.get("costMoney")).toString());
+                            rowData.add(((BigDecimal)map.get("costMoney")).toString());
                         }else {
                             if(functionTimeList.size()>0){
-                                membRowData.add(((Double)membMap.get("cost")).toString());
+                                rowData.add(((Double)map.get("cost")).toString());
                             }
                             if (functionCostList.size()>0){
-                                membRowData.add(((BigDecimal)membMap.get("costMoney")).toString());
+                                rowData.add(((BigDecimal)map.get("costMoney")).toString());
                             }
                         }
+                        if (projectSum != null && projectSum == true) {
+                            allList.add(rowData);
+                        }
+                        //统计每个项目中的人员时间成本投入
+                        int curProjectId = (Integer)map.get("id");
+                        //判断是否是当前项目的所属部门的主要或者其他负责人
+                        List<Integer> finalDeptIds = null;
+                        if (deptRelatedProjectIds.contains(curProjectId)) {
+                            //有权限看该项目的全部参与人员,不需要按照部门过滤了
+                        } else {
+                            finalDeptIds = deptIds;
+                        }
+                        List<Map<String, Object>> membList = projectMapper.getProjectCost(companyId,startDate, endDate, curProjectId,stateKey, userIdList,finalDeptIds,filterDeptIds, true);
+                        map.put("membList", membList);
+                        for (Map<String, Object> membMap : membList) {
+                            double pTotalTime = 0;
+                            BigDecimal pTotalMoney = new BigDecimal(0);
+                            List<String> membRowData = new ArrayList<String>();
+                            if (projectSum == null || projectSum == false) {
+                                membRowData.add((String)map.get("projectCode"));
+                                membRowData.add((String)map.get("project"));
+                                membRowData.add((String)map.get("categoryName"));
 
-                        allList.add(membRowData);
+                            } else {
+                                membRowData.add("");
+                                membRowData.add("");
+                                membRowData.add("");
+
+                            }
+                            if(wxCorpInfo!=null&&wxCorpInfo.getSaasSyncContact()==1){
+                                membRowData.add((String)("$userName="+membMap.get("corpwxUserId")+"$"));
+                                if(membMap.get("departmentName").equals("未分配")){
+                                    membRowData.add("未分配");
+                                }else {
+                                    membRowData.add((String)("$departmentName="+membMap.get("corpwxDeptId")+"$"));
+                                }
+                            }else {
+                                membRowData.add((String)membMap.get("name"));
+                                membRowData.add((String)membMap.get("departmentName"));
+                            }
+                            String creatorId = (String)membMap.get("creatorId");
+                            User us = userList.stream().filter(u->u.getId().equals(creatorId)).findFirst().get();
+                            for (int i = 0; i < userCustoms.size(); i++) {
+                                switch (i){
+                                    case 0:
+                                        membRowData.add(us.getPlate1()==null?"":us.getPlate1());
+                                        break;
+                                    case 1:
+                                        membRowData.add(us.getPlate2()==null?"":us.getPlate2());
+                                        break;
+                                    case 2:
+                                        membRowData.add(us.getPlate3()==null?"":us.getPlate3());
+                                        break;
+                                    case 3:
+                                        membRowData.add(us.getPlate4()==null?"":us.getPlate4());
+                                        break;
+                                    case 4:
+                                        membRowData.add(us.getPlate5()==null?"":us.getPlate5());
+                                        break;
+                                }
+                            }
+                            if ("hours".equals(exportContent) && functionTimeList.size()>0){
+                                membRowData.add(((Double)membMap.get("cost")).toString());
+                            }else if ("cost".equals(exportContent) && functionCostList.size()>0){
+                                membRowData.add(((BigDecimal)membMap.get("costMoney")).toString());
+                            }else {
+                                if(functionTimeList.size()>0){
+                                    membRowData.add(((Double)membMap.get("cost")).toString());
+                                }
+                                if (functionCostList.size()>0){
+                                    membRowData.add(((BigDecimal)membMap.get("costMoney")).toString());
+                                }
+                            }
+
+                            allList.add(membRowData);
+                        }
                     }
                 }
+
+
                 //合计
                 sumRow=new ArrayList<>();
                 //sumRow.add("合计");
                 sumRow.add(MessageUtils.message("entry.total"));
+                if (withMainProject == 1) {
+                    //多两列
+                    sumRow.add("");
+                    sumRow.add("");
+                }
                 sumRow.add("");
                 sumRow.add("");
                 sumRow.add("");
@@ -1891,7 +2096,13 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
             }
             //生成excel文件导出
             //String fileName = "项目成本工时统计_"+System.currentTimeMillis();
-            String fileName = MessageUtils.message("fileName.projectCost")+System.currentTimeMillis();
+            String fileName = null;
+            if (withMainProject == 1) {
+                fileName = "主项目成本工时统计"+System.currentTimeMillis();
+            } else {
+                fileName = MessageUtils.message("fileName.projectCost")+System.currentTimeMillis();
+            }
+
             return excelExportService.exportGeneralExcelByTitleAndList(wxCorpInfo,fileName , allList, path);
         } catch (NullPointerException e) {
             e.printStackTrace();
@@ -2488,7 +2699,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
     }
 
     @Override
-    public HttpRespMsg getProjectTask(Integer pageIndex, Integer pageSize, Integer projectId, HttpServletRequest request,Integer taskType) {
+    public HttpRespMsg getProjectTask(Integer pageIndex, Integer pageSize, Integer projectId,Integer groupId, HttpServletRequest request,Integer taskType) {
         User user = userMapper.selectById(request.getHeader("Token"));
         Integer companyId = user.getCompanyId();
         int pageStart = (pageIndex -1) * pageSize;
@@ -2509,8 +2720,25 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                 inchagerIds.add(-1);
             }
         }
-        int total = taskMapper.getProjectTaskCount(companyId, projectId,taskType,inchagerIds);
-        List projectTask = taskMapper.getProjectTask(companyId, pageStart, pageSize, projectId,taskType,inchagerIds);
+        int total = taskMapper.getProjectTaskCount(companyId, projectId,groupId,taskType,inchagerIds);
+        List<Map<String,Object>> projectTask = taskMapper.getProjectTask(companyId, pageStart, pageSize, projectId,groupId,taskType,inchagerIds);
+        if(companyId==3092){
+            List<Integer> groupIds = projectTask.stream().map(p -> Integer.valueOf(String.valueOf(p.get("groupId")))).distinct().collect(Collectors.toList());
+            groupIds.add(-1);
+            List<Report> reportList = reportMapper.selectList(new LambdaQueryWrapper<Report>().select(Report::getGroupId, Report::getWorkingTime).in(Report::getGroupId, groupIds));
+            List<TaskGroup> taskGroupList = taskGroupMapper.selectList(new LambdaQueryWrapper<TaskGroup>().in(TaskGroup::getId, groupIds));
+            for (Map<String, Object> p : projectTask) {
+                Optional<TaskGroup> group = taskGroupList.stream().filter(t -> t.getId().equals(Integer.valueOf(String.valueOf(p.get("groupId"))))).findFirst();
+                p.put("group_plan_hours",0);
+                if(group.isPresent()){
+                    p.put("group_plan_hours",0);
+                }
+                List<Report> reports = reportList.stream().filter(r -> r.getGroupId().equals(Integer.valueOf(String.valueOf(p.get("groupId"))))).collect(Collectors.toList());
+                BigDecimal reduce = reports.stream().map(r -> new BigDecimal(r.getWorkingTime())).reduce(BigDecimal.ZERO, BigDecimal::add);
+                reduce = reduce.setScale(2, BigDecimal.ROUND_HALF_UP);
+                p.put("group_real_hours",reduce.doubleValue());
+            }
+        }
         HttpRespMsg httpRespMsg = new HttpRespMsg();
         Map<String, Object> map = new HashMap<>();
         map.put("records", projectTask);
@@ -2546,7 +2774,24 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                 inchagerIds.add(-1);
             }
         }
-        List<Map> projectList = taskMapper.getProjectTask(companyId, null, null, null,taskType,inchagerIds);
+        List<Map<String,Object>> projectList = taskMapper.getProjectTask(companyId, null, null, null,null,taskType,inchagerIds);
+        if(companyId==3092){
+            List<Integer> groupIds = projectList.stream().map(p -> Integer.valueOf(String.valueOf(p.get("groupId")))).distinct().collect(Collectors.toList());
+            groupIds.add(-1);
+            List<Report> reportList = reportMapper.selectList(new LambdaQueryWrapper<Report>().select(Report::getGroupId, Report::getWorkingTime).in(Report::getGroupId, groupIds));
+            List<TaskGroup> taskGroupList = taskGroupMapper.selectList(new LambdaQueryWrapper<TaskGroup>().in(TaskGroup::getId, groupIds));
+            for (Map<String, Object> p : projectList) {
+                Optional<TaskGroup> group = taskGroupList.stream().filter(t -> t.getId().equals(Integer.valueOf(String.valueOf(p.get("groupId"))))).findFirst();
+                p.put("group_plan_hours",0);
+                if(group.isPresent()){
+                    p.put("group_plan_hours",0);
+                }
+                List<Report> reports = reportList.stream().filter(r -> r.getGroupId().equals(Integer.valueOf(String.valueOf(p.get("groupId"))))).collect(Collectors.toList());
+                BigDecimal reduce = reports.stream().map(r -> new BigDecimal(r.getWorkingTime())).reduce(BigDecimal.ZERO, BigDecimal::add);
+                reduce = reduce.setScale(2, BigDecimal.ROUND_HALF_UP);
+                p.put("group_real_hours",reduce.doubleValue());
+            }
+        }
         List<ProjectVO> list = new ArrayList<>();
         //String[] statusNames = {"进行中","已完成","已撤销"};
         String[] statusNames = {MessageUtils.message("excel.onGoing"),MessageUtils.message("excel.complete"),MessageUtils.message("excel.revoke")};
@@ -2555,11 +2800,19 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
         List<List<String>> exportList = new ArrayList<>();
         //String[] titles = {"项目编号", "项目名称", "任务名称", "执行人","计划工时(h)", "实际工时(h)","状态", "类型", "截止日期"};
         String[] titles = {MessageUtils.message("entry.projectId"), MessageUtils.message("entry.projectName"), MessageUtils.message("entry.taskName"), MessageUtils.message("excel.executor"),MessageUtils.message("excel.plannedWork"), MessageUtils.message("excel.actualWork"),MessageUtils.message("leave.status"), MessageUtils.message("excel.type"), MessageUtils.message("entry.endDate")};
+        if(companyId==3092){
+            titles = new String[]{"项目编号", "项目名称","任务分组","分组预估工时","分组实际工时", "任务名称", "执行人","计划工时(h)", "实际工时(h)","状态", "类型", "截止日期"};
+        }
         exportList.add(Lists.list(titles));
         for (Map task : projectList) {
             List<String> data = new ArrayList<>();
             data.add(task.get("project_code") == null?"":task.get("project_code").toString());
             data.add(task.get("project_name") == null?"":task.get("project_name").toString());
+            if(companyId==3092){
+                data.add(task.get("groupName") == null?"":task.get("groupName").toString());
+                data.add(task.get("group_plan_hours") == null?"":task.get("group_plan_hours").toString());
+                data.add(task.get("group_real_hours") == null?"":task.get("group_real_hours").toString());
+            }
             data.add(task.get("name") != null?task.get("name").toString():"");
             if(wxCorpInfo!=null&&wxCorpInfo.getSaasSyncContact()==1){
                 String userName = "";
@@ -10942,13 +11195,9 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
         }
         long total  = 0;
         List<Map<String,Object>> resultList = null;
-        List<Integer> branchDepartment =null;
-        //若用户传入departmentId参数,则查询该部门所有子部门,添加到branchDepartment集合中
-//        if(departmentId!=null){
-//            branchDepartment = getBranchDepartment(departmentId, allDepartmentList);
-//        }
         String startDate = null;
         String endDate = null;
+        System.out.println("month==="+month);
         LocalDate time = LocalDate.parse(month, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
         startDate = time.with(TemporalAdjusters.firstDayOfMonth()).toString();
         endDate = time.with(TemporalAdjusters.lastDayOfMonth()).toString();
@@ -10958,10 +11207,10 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
         if(pageIndex!=null&&pageSize!=null){
             Integer size=pageSize;
             Integer start=(pageIndex-1)*size;
-            resultList=projectMapper.getFTEData(targetUser.getCompanyId(),startDate,endDate,start,size,area,branchDepartment,deptIds);
-            total=projectMapper.getFTEData(targetUser.getCompanyId(),startDate,endDate,null,null,area,branchDepartment,deptIds).size();
+            resultList=projectMapper.getFTEData(targetUser.getCompanyId(),startDate,endDate,start,size,area,null,deptIds);
+            total=projectMapper.getFTEData(targetUser.getCompanyId(),startDate,endDate,null,null,area,null,deptIds).size();
         }else{
-            resultList=projectMapper.getFTEData(targetUser.getCompanyId(),startDate,endDate,null,null,area,branchDepartment,deptIds);
+            resultList=projectMapper.getFTEData(targetUser.getCompanyId(),startDate,endDate,null,null,area,null,deptIds);
         }
         for (Map<String, Object> map : resultList) {
             map.put("FTE",Float.parseFloat(map.get("workTime") == null?"0":map.get("workTime").toString())/monthTime);
@@ -11378,21 +11627,15 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
     }
 
     @Override
-    public HttpRespMsg syncProjectWithSap(String startDate,String endDate) {
+    public HttpRespMsg syncProjectWithSap(String startDate,String endDate,String projectCodes) {
         HttpRespMsg msg=new HttpRespMsg();
         Integer companyId = userMapper.selectById(request.getHeader("token")).getCompanyId();
         //获取SAP项目服务数据 ----> 工时管家任务分组下阶段作为项目服务数据
-        if(StringUtils.isEmpty(startDate)||StringUtils.isEmpty(endDate)){
-            //没设置开始或者结束日期 同步当天新增的项目数据
-            DateTimeFormatter df=DateTimeFormatter.ofPattern("yyyy-MM-dd");
-            startDate=df.format(LocalDate.now());
-            endDate=df.format(LocalDate.now());
-        }
-        XmlResponseData projectServiceData= SyncSapUtils.syncServiceData("2020-01-01", endDate, companyId);
+        XmlResponseData projectServiceData= SyncSapUtils.syncServiceData("2020-01-01", endDate, companyId,isDev);
         //已有的项目分类
         List<ProjectCategory> allProjectCategoryList = projectCategoryMapper.selectList(new QueryWrapper<ProjectCategory>().eq("company_id", companyId));
         List<Project> projectList = projectMapper.selectList(new QueryWrapper<Project>().eq("company_id", companyId));
-        XmlResponseData xmlResponseData = SyncSapUtils.syncProjectFromSap(startDate, endDate);
+        XmlResponseData xmlResponseData = SyncSapUtils.syncProjectFromSap(startDate, endDate,projectCodes,isDev);
         List<ProjectQueryResponse> projectQueryResponses = xmlResponseData.getProjectQueryResponses();
         List<Map<String,Object>> idsMapList=new ArrayList<>();
         LocalDate localDate=LocalDate.now();
@@ -11473,6 +11716,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                     List<String> stagesUUIDList = stagesList.stream().map(ProjectTask::getUUID).collect(Collectors.toList());
                     //抽调出最末级
                     List<ProjectTask> taskList = projectTasks.stream().filter(p ->p.getParentTaskUUID() != null &&stagesUUIDList.contains(p.getParentTaskUUID())&&(p.getSummaryTaskIndicator()==null||(p.getSummaryTaskIndicator()!=null && !p.getSummaryTaskIndicator().equals("true")))).collect(Collectors.toList());
+                    List<Task> tasks=new ArrayList<>();
                     if(taskGroupList!=null && taskGroupList.size()>0){
                         for (ProjectTask group : taskGroupList) {
                             //如果作为第二层数据是不存在下级数据的 把当前数据作为第四层数据 手动添加阶段数据 作为该数据的上级数据
@@ -11507,7 +11751,8 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                                 if(three!=null){
                                     task.setId(three.getId());
                                 }
-                                taskService.saveOrUpdate(task);
+//                                taskService.saveOrUpdate(task);
+                                tasks.add(task);
                             }else {
                                 TaskGroup taskGroup=new TaskGroup();
                                 taskGroup.setProjectId(project.getId());
@@ -11556,7 +11801,8 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                                 if(two!=null){
                                     task.setId(two.getId());
                                 }
-                                taskService.saveOrUpdate(task);
+//                                taskService.saveOrUpdate(task);
+                                tasks.add(task);
                             }else {
                                 Stages stage = new Stages();
                                 stage.setSequence(1);
@@ -11594,8 +11840,20 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                             if(one!=null){
                                 task.setId(one.getId());
                             }
-                            taskService.saveOrUpdate(task);
+//                            taskService.saveOrUpdate(task);
+                            tasks.add(task);
+                        }
+                    }
+                    if(tasks.size()>0){
+                        Map<Integer, List<Task>> listMap = tasks.stream().collect(Collectors.groupingBy(t -> t.getStagesId()));
+                        List<Integer> list = tasks.stream().map(Task::getStagesId).collect(Collectors.toList());
+                        for (Integer id : list) {
+                            List<Task> subList = listMap.get(id);
+                            for (int i = 0; i < subList.size(); i++) {
+                                subList.get(i).setSeq(i);
+                            }
                         }
+                        taskService.saveOrUpdateBatch(tasks);
                     }
                 }
             }
@@ -11607,21 +11865,23 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
             List<ServiceProduct> serviceProducts = projectServiceData.getServiceProducts();
             if(serviceProducts!=null&&serviceProducts.size()>0){
                 for (ServiceProduct serviceProduct : serviceProducts) {
-                    if(serviceProduct.getProductCategoryID().equals("901")&&serviceProduct.getBaseMeasureUnitCode().equals("HUR")){
+                    if(serviceProduct.getProductCategoryID().equals("901")&&serviceProduct.getBaseMeasureUnitCode().equals("HUR")&&serviceProduct.getSales()!=null&&serviceProduct.getSales().getLifeCycleStatusCode().equals("2")){
                         SapProjectService sapProjectService=new SapProjectService();
                         sapProjectService.setServiceCode(serviceProduct.getInternalID());
                         sapProjectService.setServiceName(serviceProduct.getDescription().getDescription());
                         sapProjectService.setCompanyId(companyId);
-                        boolean match = serviceList.stream().anyMatch(s -> s.getServiceCode().equals(serviceProduct.getInternalID()));
-                        if(!match){
-                            sapProjectServiceList.add(sapProjectService);
+                        sapProjectService.setStatus(Integer.valueOf(serviceProduct.getSales().getLifeCycleStatusCode()));
+                        Optional<SapProjectService> first = serviceList.stream().filter(s -> s.getServiceCode().equals(serviceProduct.getInternalID())).findFirst();
+                        if(first.isPresent()){
+                            sapProjectService.setId(first.get().getId());
                         }
+                        sapProjectServiceList.add(sapProjectService);
                     }
                 }
             }
         }
         if(sapProjectServiceList.size()>0){
-            sapProjectServiceService.saveBatch(sapProjectServiceList);
+            sapProjectServiceService.saveOrUpdateBatch(sapProjectServiceList);
         }
         msg.setData(xmlResponseData);
         return msg;
@@ -11760,6 +12020,83 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
         return msg;
     }
 
+    @Override
+    public HttpRespMsg getMembProjectCateRatio(String startDate, String endDate, Integer onlyShowWarning) {
+        HttpRespMsg msg = new HttpRespMsg();
+        Integer companyId = userMapper.selectById(request.getHeader("token")).getCompanyId();
+        List<UserCateTimeVo> timeList = projectMapper.getMembProjectCateTime(companyId, startDate, endDate);
+        CategoryRatioTblSetting categoryRatioTblSetting = categoryRatioTblSettingMapper.selectById(companyId);
+        //把timeList按照用户分组
+        Map<String, List<UserCateTimeVo>> userMap = timeList.stream().collect(Collectors.groupingBy(UserCateTimeVo::getUserId));
+        List<ProjectCategory> categoryList = projectCategoryMapper.selectList(new QueryWrapper<ProjectCategory>().eq("company_id", companyId));
+        List<Map> retList = new ArrayList();
+        for (Map.Entry<String, List<UserCateTimeVo>> entry : userMap.entrySet()) {
+            Map<String, Object> map = new HashMap<>();
+            map.put("userId", entry.getKey());
+            List<UserCateTimeVo> value = entry.getValue();
+            map.put("userName", value.get(0).getName());
+            map.put("cateTimeList", value);
+            //计算这个人的总工时
+            double sum = value.stream().mapToDouble(UserCateTimeVo::getWorkingTime).sum();
+            map.put("workingTime", sum);
+            //计算占比
+            value.forEach(v->{
+                if (sum > 0) {
+                    double v1 = v.getWorkingTime() * 100 / sum;
+                    v.setPercent(v1);
+                } else {
+                    v.setPercent(0.0);
+                }
+                if (categoryRatioTblSetting != null && categoryRatioTblSetting.getRatio() != null) {
+                    UserCateTimeVo userCateTimeVo = v;
+                    //获取用户的总工时预警
+                    int ratio = categoryRatioTblSetting.getRatio();
+                    if (categoryRatioTblSetting.getMoreOrLess() == 1) {
+                        //大于预设比例的需要预警
+                        if (userCateTimeVo.getPercent() > ratio) {
+                            v.setWarning(true);
+                        }
+                    } else {
+                        //小于预设比例的需要预警;
+                        if (userCateTimeVo.getPercent() < ratio) {
+                            v.setWarning(true);
+                        }
+                    }
+                }
+            });
+
+            //是否仅达到预警的用户列表
+            if (onlyShowWarning == 1) {
+                //获取用户的总工时
+                if (categoryRatioTblSetting != null && categoryRatioTblSetting.getRatio() != null) {
+                    Optional<UserCateTimeVo> first = value.stream().filter(v -> categoryRatioTblSetting.getMonitorCategoryId().equals(v.getCategory())).findFirst();
+                    if (first.isPresent()) {
+                        UserCateTimeVo userCateTimeVo = first.get();
+                        //获取用户的总工时预警
+                        int ratio = categoryRatioTblSetting.getRatio();
+                        if (categoryRatioTblSetting.getMoreOrLess() == 1) {
+                            //大于预设比例的需要预警,小于等于则跳过
+                            if (userCateTimeVo.getWorkingTime() <= sum * ratio / 100) {
+                                continue;
+                            }
+                        } else {
+                            //小于预设比例的需要预警;大于等于则跳过
+                            if (userCateTimeVo.getWorkingTime() >= sum * ratio / 100) {
+                                continue;
+                            }
+                        }
+                    }
+                }
+            }
+            retList.add(map);
+        }
+        HashMap retMap = new HashMap();
+        retMap.put("categoryList", categoryList);
+        retMap.put("userList", retList);
+        msg.data = retMap;
+        return msg;
+    }
+
 
 //    public void setDeptIdList(Integer departmentId,List<Integer> deptIds){
 //        LambdaQueryWrapper<Department> lqw = new LambdaQueryWrapper<>();

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

@@ -22,6 +22,7 @@ import org.apache.commons.io.FileUtils;
 import org.apache.poi.EncryptedDocumentException;
 import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
 import org.apache.poi.ss.usermodel.*;
+import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.http.*;
@@ -36,6 +37,7 @@ import org.springframework.web.client.RestTemplate;
 import org.springframework.web.multipart.MultipartFile;
 
 import javax.annotation.Resource;
+import javax.print.DocFlavor;
 import javax.servlet.http.HttpServletRequest;
 import java.io.*;
 import java.math.BigDecimal;
@@ -52,6 +54,7 @@ import java.time.temporal.TemporalAdjusters;
 import java.util.*;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.stream.Collectors;
 
@@ -1859,16 +1862,25 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                     List<Integer> projectIds = reportList.stream().map(Report::getProjectId).collect(Collectors.toList());
 
                     List<ProjectProfession> myProfessionList = projectProfessionMapper.selectList(new QueryWrapper<ProjectProfession>().eq("incharger_id", user.getId()).in("project_id", projectIds));
-                    if (myProfessionList.size() == 0) {
+                    if (myProfessionList.size() == 0 && !user.getRoleName().equals("超级管理员")) {
                         //httpRespMsg.setError("只有专业负责人才能进行专业审核");
                         httpRespMsg.setError(MessageUtils.message("finance.masterProfessional"));
+                        return httpRespMsg;
                     } else {
                         List<Integer> collect = myProfessionList.stream().map(ProjectProfession::getProfessionId).collect(Collectors.toList());
                         oneReport = reportList.get(0);
                         ReportProfessionProgress item = new ReportProfessionProgress();
                         item.setAuditState(1);
-                        reportProfessionProgressService.update(item, new QueryWrapper<ReportProfessionProgress>().in("report_id", ids).in("profession_id", collect));
-
+                        boolean passAll = false;
+                        if (user.getRoleName().equals("超级管理员")) {
+                            //超级管理员,可以审核非自己担任专业负责人的
+                            passAll = true;
+                        }
+                        if (passAll) {
+                            reportProfessionProgressService.update(item, new QueryWrapper<ReportProfessionProgress>().in("report_id", ids));
+                        } else {
+                            reportProfessionProgressService.update(item, new QueryWrapper<ReportProfessionProgress>().in("report_id", ids).in("profession_id", collect));
+                        }
                         //全部的专业都审核通过的情况下,更新部门待审核状态
                         int count = reportProfessionProgressService.count(new QueryWrapper<ReportProfessionProgress>().in("report_id", ids).ne("audit_state", 1));
                         if (count == 0) {
@@ -5050,6 +5062,8 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
     public HttpRespMsg exportReport(@RequestParam String startDate, @RequestParam String endDate, Integer projectId,Integer stateKey,Integer departmentId, HttpServletRequest request) {
         HttpRespMsg httpRespMsg = new HttpRespMsg();
         DateFormat timeDf = new SimpleDateFormat("yyyy-MM-dd");
+        long t0 = System.currentTimeMillis();
+        long fetchDataTime = 0;
         try {
             String userId = request.getHeader("Token");
             User user = userMapper.selectById(userId);
@@ -5059,6 +5073,7 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
             Integer companyId = company.getId();
             List<UserCustom> userCustomList = userCustomMapper.selectList(new QueryWrapper<UserCustom>().eq("company_id", companyId));
             WxCorpInfo wxCorpInfo = wxCorpInfoMapper.selectOne(new QueryWrapper<WxCorpInfo>().eq("company_id", companyId));
+            boolean needCorpWxTranslate = (wxCorpInfo!=null&&wxCorpInfo.getSaasSyncContact()==1);
             SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
             List<List<String>> dataList=new ArrayList<>();
             List<String> titles = new ArrayList<String>();
@@ -5134,6 +5149,7 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
 //                titles.add("审核流程");
                 titles.add(MessageUtils.message("excel.fillTime"));
                 titles.add(MessageUtils.message("excel.proReviewer"));
+                titles.add("项目经理");
                 titles.add(MessageUtils.message("excel.auditTime"));
                 titles.add(MessageUtils.message("excel.auditProcess"));
 //                logDetails = reportLogDetailMapper.selectList(new QueryWrapper<ReportLogDetail>().select("report_id, msg, operator_id, operate_date").eq("company_id", company.getId()).between("work_date", startDate, endDate));
@@ -5159,6 +5175,7 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
             List<SysRichFunction> functionList = sysFunctionMapper.getRoleFunctions(user.getRoleId(), "查看全公司工时");
             //获取部门的所有子部门
             List<Department> departments = departmentMapper.selectList(new QueryWrapper<Department>().eq("company_id",companyId));
+            Department[] deptArray = departments.toArray(new Department[0]);
             List<Integer> branchDepartment = null;
             if(departmentId != null){
                 branchDepartment = departmentService.getBranchDepartment(departmentId,departments);
@@ -5210,11 +5227,15 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
             }
             else {
                 //看公司所有人的
+                long t1 = System.currentTimeMillis();
                 if (timeType.getShowFillauditTime() == 1) {
                     allReportByDate = reportMapper.getAllReportByDateWithReportLog(startDate, user.getCompanyId(), null, endDate, projectId,stateKey,branchDepartment);
                 } else {
                     allReportByDate = reportMapper.getAllReportByDate(startDate, user.getCompanyId(), null, endDate, projectId,stateKey,branchDepartment);
                 }
+                long t2 = System.currentTimeMillis();
+                fetchDataTime = (t2-t1);
+                System.out.println("查数据库耗时:"+(t2-t1)/1000+"s");
             }
             //获取企业微信考勤数据
             List<UserCorpwxTime> userCorpwxTimeList = new ArrayList<>();
@@ -5296,9 +5317,9 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                 }
             }
             List<User> userList = userMapper.selectList(new QueryWrapper<User>().eq("company_id", companyId));
-            long t1 = System.currentTimeMillis();
             DateTimeFormatter dft = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
             for (Map<String, Object> map : allReportByDate) {
+                long p1 = System.currentTimeMillis();
                 List<String> item=new ArrayList<>();
                 item.add(String.valueOf(rowNum));
                 item.add((String) map.get("jobNumber"));
@@ -5319,20 +5340,22 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                     item.add(value);
                 }
                 Department dept = null;
-                for (Department department : departments) {
-                    if (map.containsKey("departmentId") && department.getDepartmentId().toString().equals(map.get("departmentId").toString())){
-                        dept = department;
-                        break;
+                Department targetDept = new Department();
+                if (map.get("departmentId") != null) {
+                    targetDept.setDepartmentId(Integer.valueOf(map.get("departmentId").toString()));
+                    int index = Arrays.binarySearch(deptArray, targetDept, Comparator.comparing(Department::getDepartmentId));
+                    if (index >= 0) {
+                        dept = deptArray[index];
                     }
                 }
-                if(wxCorpInfo!=null&&wxCorpInfo.getSaasSyncContact()==1){
+
+                if(needCorpWxTranslate){
                     item.add("$userName="+(map.get("corpwxUserId")==null?"":map.get("corpwxUserId"))+"$");
                     item.add(departmentService.exportWxDepartment(dept,departments));
                 }else {
                     item.add((String) map.get("name"));
                     item.add(departmentService.getSupDepartment(dept,departments));
                 }
-
                 item.add((String) map.get("projectCode"));
                 item.add((String) map.get("project"));
                 if(companyId==936){
@@ -5395,12 +5418,18 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                 }
                 if (timeType.getShowFillauditTime() == 1) {
                     item.add(sdf.format((Date)map.get("time")));
-                    if(wxCorpInfo!=null&&wxCorpInfo.getSaasSyncContact()==1){
+                    if(needCorpWxTranslate){
                         String projectAuditorName ="$userName="+String.valueOf(map.get("projectAuditorCorpwxUserId"))+"$";
                         item.add(projectAuditorName);
                     }else {
                         item.add((String)map.get("projectAuditorName"));
                     }
+                    if(needCorpWxTranslate){
+                        String projectManagerName ="$userName="+String.valueOf(map.get("projectManagerCorpwxUserId"))+"$";
+                        item.add(projectManagerName);
+                    }else {
+                        item.add((String)map.get("projectManagerName"));
+                    }
                     //分组审核通过或者项目审核通过都显示
                     if (map.get("projectAuditTime") != null && ((Integer)map.get("projectAuditState") == 1 || (Integer)map.get("groupAuditState") == 1)) {
                         item.add(sdf.format((Date)map.get("projectAuditTime")));
@@ -5427,7 +5456,7 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                             }
                             String time = dtf.format(operateDate);
                             String msg= "";
-                            if(wxCorpInfo!=null&&wxCorpInfo.getSaasSyncContact()==1){
+                            if(needCorpWxTranslate){
                                 Optional<User> first = userList.stream().filter(ul -> ul.getId().equals(audit.getOperatorId())).findFirst();
                                 if(first.isPresent()){
                                     if(audit.getMsg().contains("提交了")){
@@ -5457,7 +5486,6 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                     }
                     item.add(sb.toString());
                 }
-                item.add((String) map.get("content"));
                 if(stateKey==1){
                     Integer state = (Integer) map.get("state");
                     switch (state){
@@ -5498,7 +5526,7 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                             String departmentName = map.get("departmentName") + "";
                             for (User userItem : userList) {
                                 if (userItem.getId().equals(deptAuditorId)){
-                                    if(wxCorpInfo!=null&&wxCorpInfo.getSaasSyncContact()==1){
+                                    if(needCorpWxTranslate){
                                         String deptAuditorName ="$userName="+ userItem.getCorpwxRealUserid() +"$";
                                         departmentName = "$departmentName=" + departmentName + "$";
                                         if(timeType.getReportAuditType()==4){
@@ -5515,18 +5543,16 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                                         }else {
                                             item.add("待" + departmentName + "(" + userItem.getName() + ")审核");
                                         }
-
                                     }
                                     break;
                                 }
-
                             }
                         }else {
                             //项目审核或分组审核
                             if (String.valueOf(map.get("projectAuditState")).equals("0") || String.valueOf(map.get("groupAuditState")).equals("0")){
                                 String projectAuditorName = map.get("projectAuditorName")+"";
                                 String projectAuditorId = map.get("projectAuditorId")+"";
-                                if(wxCorpInfo!=null&&wxCorpInfo.getSaasSyncContact()==1){
+                                if(needCorpWxTranslate){
                                     for (User userItem : userList) {
                                         if (userItem.getId().equals(projectAuditorId)){
                                             projectAuditorName ="$userName="+ userItem.getCorpwxUserid() +"$";
@@ -7448,21 +7474,19 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
     }
 
     @Override
-    public HttpRespMsg pushProjectReportToSap(String yearMonth) {
+    public HttpRespMsg pushProjectReportToSap(String pushDate) {
         HttpRespMsg httpRespMsg =new HttpRespMsg();
-        String dateStr = yearMonth+"-01";
-        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd");
-        LocalDate start = LocalDate.parse(dateStr,df);
-        LocalDate end =start.plusMonths(1).minusDays(1);
-        List<SapSyncLog> sapSyncLogs=new ArrayList<>();
         LocalDateTime localDateTime=LocalDateTime.now();
         User user = userMapper.selectById(request.getHeader("token"));
         Integer companyId = user.getCompanyId();
-        List<Map<String,Object>> resultList=reportMapper.getPushProjectReportToSap(companyId,df.format(start),df.format(end),null);
+        List<Map<String,Object>> resultList=reportMapper.getPushProjectReportToSap(companyId,pushDate,pushDate,null);
+        //过滤服务code为空的数据
+        resultList=resultList.stream().filter(r->r.get("ProjectElementID")!=null && !StringUtils.isEmpty(String.valueOf(r.get("ProjectElementID")))).collect(Collectors.toList());
+        List<Integer> projectIds = resultList.stream().map(r -> Integer.valueOf(String.valueOf(r.get("ProjectId")))).distinct().collect(Collectors.toList());
+        projectIds.add(-1);
         //提前推送项目工时(工时管家相关项目任务分组阶段下任务作为SAP服务 预算工时数据推送到SAP)
-        List<Map<String, Object>> pushProjectPlanHour = reportMapper.getProjectPlanData(companyId,null,null);
-        List<SapSyncLog> projectPlanSyncLogs = SyncSapUtils.pushProjectPlanToSap(pushProjectPlanHour, user.getCompanyId(), user.getJobNumber());
-        sapSyncLogs.addAll(projectPlanSyncLogs);
+        //只推送需要推送日报参与的部分就可以了
+        List<Map<String, Object>> pushProjectPlanHour = reportMapper.getProjectPlanData(companyId,projectIds,null,null);
         //配置xml请求参数
         XmlRequestData xmlRequestData=new XmlRequestData();
         xmlRequestData.setBasicMessageHeader("");
@@ -7471,97 +7495,123 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
         workDescriptionText.setLanguageCode("ZH");
         SapPeriod datePeriod=new SapPeriod();
         SapPeriod timePeriod=new SapPeriod();
-        List<ReportPushLog> addList=new ArrayList<>();
-        long sTime = System.currentTimeMillis();
-        for (Map<String, Object> map : resultList) {
-            ReportPushLog one = reportPushLogService.getOne(new LambdaQueryWrapper<ReportPushLog>().eq(ReportPushLog::getCompanyId, companyId).eq(ReportPushLog::getReportId, map.get("ReportId")).eq(ReportPushLog::getTargetSystem,"SAP"));
-            if(one!=null){
-                continue;
-            }
-            employeeTime.setEmployeeID(String.valueOf(map.get("EmployeeID")));
-            employeeTime.setActionCode("01");
-            if(map.get("StartDate")!=null){
-                datePeriod.setStartDate(String.valueOf(map.get("StartDate")));
-            }
-            if(map.get("EndDate")!=null){
-                datePeriod.setEndDate(String.valueOf(map.get("EndDate")));
-            }
-            if(map.get("StartTime")!=null){
-                timePeriod.setStartTime(String.valueOf(map.get("StartTime"))+":00");
-            }
-            if(map.get("EndTime")!=null){
-                timePeriod.setEndTime(String.valueOf(map.get("EndTime"))+":00");
-            }
-            employeeTime.setDatePeriod(datePeriod);
-            employeeTime.setTimePeriod(timePeriod);
-            employeeTime.setItemTypeCode("CN0001");
-            employeeTime.setDuration(map.get("Duration")==null?"0":String.valueOf(map.get("Duration")));
-            if(map.get("ProjectElementID")==null||map.get("ServiceProductInternalID")==null){
-                continue;
-            }
-            employeeTime.setProjectElementID(String.valueOf(map.get("ProjectElementID")));
-            employeeTime.setServiceProductInternalID(String.valueOf(map.get("ServiceProductInternalID")));
-            if(map.get("WorkDescriptionText")!=null){
-                workDescriptionText.setWorkDescriptionText(String.valueOf(map.get("WorkDescriptionText")));
-                employeeTime.setWorkDescriptionText(workDescriptionText);
-            }
-            xmlRequestData.setEmployeeTime(employeeTime);
-            String xml = CommonUtils.convertToXml(xmlRequestData);
-            System.out.println(xml);
-            xml=xml.substring(xml.indexOf("<XMLDATA>")+9,xml.lastIndexOf("</XMLDATA>"));
-            StringBuffer sb = new StringBuffer();
-            sb.append("<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:glob=\"http://sap.com/xi/SAPGlobal20/Global\">\n" +
-                    "   <soapenv:Header/>\n" +
-                    "   <soapenv:Body>\n" +
-                    "      <glob:EmployeeTimeAsBundleMaintainRequest_sync>\n");
-            sb.append(xml);
-            sb.append("      </glob:EmployeeTimeAsBundleMaintainRequest_sync>\n" +
-                    "   </soapenv:Body>\n" +
-                    "</soapenv:Envelope>");
-            System.out.println(sb.toString());
-            String result = "";
-            try {
-                result = WebServiceUtils.requestByXml("https://my602728.sapbyd.cn/sap/bc/srt/scs/sap/manageemployeetimein?sap-vhost=my602728.sapbyd.cn", sb.toString(), 0, "_BYDHOST", "Welcome1");
-            } catch (Exception e) {
-                e.printStackTrace();
-            }
-            if(!StringUtils.isEmpty(result)) {
-                result = result.substring(result.indexOf("<soap-env:Body>")+15, result.lastIndexOf("</soap-env:Body>"));
-                result = result.substring(result.indexOf(">")+1, result.lastIndexOf("</n0:EmployeeTimeAsBundleMaintainConfirmation_sync>"));
-                result="<XMLDATA>"+result+"</XMLDATA>";
-            }
-            System.out.println(result);
-            XmlResponseData xmlResponseData = (XmlResponseData) CommonUtils.convertXmlStrToObject(XmlResponseData.class, result);
-            SapSyncLog sapSyncLog=new SapSyncLog();
-            sapSyncLog.setOperator(user.getJobNumber());
-            sapSyncLog.setCompanyId(companyId);
-            sapSyncLog.setRemark("日报数据推送");
-            sapSyncLog.setSyncType("手动推送");
-            sapSyncLog.setSyncTime(localDateTime);
-            if(StringUtils.isEmpty(xmlResponseData.getEmployeeTime())){
-                log.error("推送失败===》工号:"+employeeTime.getEmployeeID());
-                sapSyncLog.setResult("员工工号["+employeeTime.getEmployeeID()+"]"+datePeriod.getStartDate()+"日报推送失败");
-                sapSyncLog.setResultRemark(xmlResponseData.getLog()!=null?xmlResponseData.getLog().getItem()!=null?xmlResponseData.getLog().getItem().getNote():"":"");
-            }else {
-                sapSyncLog.setResult("工号["+employeeTime.getEmployeeID()+"]"+datePeriod.getStartDate()+"日报推送成功");
-                //推送成功 日报数据打上标记
-                ReportPushLog reportPushLog=new ReportPushLog();
-                reportPushLog.setCompanyId(companyId);
-                reportPushLog.setReportId(Integer.valueOf(String.valueOf(map.get("ReportId"))));
-                reportPushLog.setTargetSystem("SAP");
-                reportPushLog.setUuid(xmlResponseData.getEmployeeTime().getUUID());
-                addList.add(reportPushLog);
+        Map<String, List<Map<String, Object>>> listGroupEmployeeID = resultList.stream().collect(Collectors.groupingBy(r -> String.valueOf(r.get("EmployeeID"))));
+        List<String> employeeIDList = resultList.stream().map(r -> String.valueOf(r.get("EmployeeID"))).distinct().collect(Collectors.toList());
+        //按照人员集合长度来创建多个个线程来处理
+        int threadNum = employeeIDList.size();
+        //多加一个作为预算工时推送
+        ExecutorService executor = Executors.newFixedThreadPool(threadNum+1);
+        /*execute()让线程池中的线程来执行业务,每次调用都会将一个线程加入到就绪队列*/
+        executor.execute(new Runnable() {
+            @Override
+            public void run() {
+                List<SapSyncLog> projectPlanSyncLogs = SyncSapUtils.pushProjectPlanToSap(pushProjectPlanHour, user.getCompanyId(), user.getJobNumber(),isDev);
+                if(projectPlanSyncLogs.size()>0){
+                    sapSyncLogService.saveBatch(projectPlanSyncLogs);
+                }
             }
-            sapSyncLogs.add(sapSyncLog);
-        }
-        if(addList.size()>0){
-            reportPushLogService.saveBatch(addList);
-        }
-        if(sapSyncLogs.size()>0){
-            sapSyncLogService.saveBatch(sapSyncLogs);
+        });
+        for (int i = 0; i <employeeIDList.size() ; i++) {
+            List<Map<String, Object>> mapList = listGroupEmployeeID.get(employeeIDList.get(i));
+            executor.execute(new Runnable() {
+                @Override
+                public void run() {
+                    for (Map<String, Object> map : mapList) {
+                        ReportPushLog one = reportPushLogService.getOne(new LambdaQueryWrapper<ReportPushLog>().eq(ReportPushLog::getCompanyId, companyId).eq(ReportPushLog::getReportId, map.get("ReportId")).eq(ReportPushLog::getTargetSystem,"SAP"));
+                        if(one!=null){
+                            continue;
+                        }
+                        employeeTime.setEmployeeID(String.valueOf(map.get("EmployeeID")));
+                        employeeTime.setActionCode("01");
+                        if(map.get("StartDate")!=null){
+                            datePeriod.setStartDate(String.valueOf(map.get("StartDate")));
+                        }
+                        if(map.get("EndDate")!=null){
+                            datePeriod.setEndDate(String.valueOf(map.get("EndDate")));
+                        }
+                        if(map.get("StartTime")!=null){
+                            timePeriod.setStartTime(String.valueOf(map.get("StartTime"))+":00");
+                        }
+                        if(map.get("EndTime")!=null){
+                            timePeriod.setEndTime(String.valueOf(map.get("EndTime"))+":00");
+                        }
+                        employeeTime.setDatePeriod(datePeriod);
+                        if(map.get("StartTime")!=null&&map.get("EndTime")!=null){
+                            employeeTime.setTimePeriod(timePeriod);
+                        }
+                        employeeTime.setItemTypeCode("CN0001");
+                        String duration=map.get("Duration")==null?"0":String.valueOf(map.get("Duration"))+"";
+                        String hour = duration.substring(0, duration.indexOf("."));
+                        String min = "0"+duration.substring(duration.indexOf("."));
+                        BigDecimal minBigDecimal = new BigDecimal(min);
+                        minBigDecimal=minBigDecimal.multiply(new BigDecimal(60)).setScale(0,BigDecimal.ROUND_HALF_UP);
+                        employeeTime.setDuration("PT"+hour+"H"+minBigDecimal.intValue()+"M");
+                        if(map.get("ProjectElementID")==null||map.get("ServiceProductInternalID")==null){
+                            continue;
+                        }
+                        employeeTime.setProjectElementID(String.valueOf(map.get("ProjectElementID")));
+                        employeeTime.setServiceProductInternalID(String.valueOf(map.get("ServiceProductInternalID")));
+                        if(map.get("WorkDescriptionText")!=null){
+                            workDescriptionText.setWorkDescriptionText(String.valueOf(map.get("WorkDescriptionText")));
+                            employeeTime.setWorkDescriptionText(workDescriptionText);
+                        }
+                        xmlRequestData.setEmployeeTime(employeeTime);
+                        String xml = CommonUtils.convertToXml(xmlRequestData);
+                        xml=xml.substring(xml.indexOf("<XMLDATA>")+9,xml.lastIndexOf("</XMLDATA>"));
+                        StringBuffer sb = new StringBuffer();
+                        sb.append("<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:glob=\"http://sap.com/xi/SAPGlobal20/Global\">\n" +
+                                "   <soapenv:Header/>\n" +
+                                "   <soapenv:Body>\n" +
+                                "      <glob:EmployeeTimeAsBundleMaintainRequest_sync>\n");
+                        sb.append(xml);
+                        sb.append("      </glob:EmployeeTimeAsBundleMaintainRequest_sync>\n" +
+                                "   </soapenv:Body>\n" +
+                                "</soapenv:Envelope>");
+                        String result = "";
+                        try {
+                            if(isDev){
+                                result = WebServiceUtils.requestByXml("https://my602728.sapbyd.cn/sap/bc/srt/scs/sap/manageemployeetimein?sap-vhost=my602728.sapbyd.cn", sb.toString(), 0, "_BYDHOST", "Welcome1");
+                            }else {
+                                result = WebServiceUtils.requestByXml("https://my601432.sapbyd.cn/sap/bc/srt/scs/sap/manageemployeetimein?sap-vhost=my601432.sapbyd.cn", sb.toString(), 0, "_BYDHOST", "Welcome1");
+                            }
+                        } catch (Exception e) {
+                            e.printStackTrace();
+                        }
+                        if(!StringUtils.isEmpty(result)) {
+                            result = result.substring(result.indexOf("<soap-env:Body>")+15, result.lastIndexOf("</soap-env:Body>"));
+                            result = result.substring(result.indexOf(">")+1, result.lastIndexOf("</n0:EmployeeTimeAsBundleMaintainConfirmation_sync>"));
+                            result="<XMLDATA>"+result+"</XMLDATA>";
+                        }
+                        System.out.println(result);
+                        XmlResponseData xmlResponseData = (XmlResponseData) CommonUtils.convertXmlStrToObject(XmlResponseData.class, result);
+                        SapSyncLog sapSyncLog=new SapSyncLog();
+                        sapSyncLog.setOperator(user.getJobNumber());
+                        sapSyncLog.setCompanyId(companyId);
+                        sapSyncLog.setRemark("日报数据推送");
+                        sapSyncLog.setSyncType("手动推送");
+                        sapSyncLog.setSyncTime(localDateTime);
+                        if(StringUtils.isEmpty(xmlResponseData.getEmployeeTime())){
+                            log.error("推送失败===》员工工号:"+employeeTime.getEmployeeID());
+                            sapSyncLog.setResult("员工工号["+employeeTime.getEmployeeID()+"]"+datePeriod.getStartDate()+"日报推送失败");
+                            sapSyncLog.setResultRemark(xmlResponseData.getLog()!=null?xmlResponseData.getLog().getItem()!=null?xmlResponseData.getLog().getItem().getNote():"":"");
+                        }else {
+                            sapSyncLog.setResult("员工工号["+employeeTime.getEmployeeID()+"]"+datePeriod.getStartDate()+"日报推送成功");
+                            //推送成功 日报数据打上标记
+                            ReportPushLog reportPushLog=new ReportPushLog();
+                            reportPushLog.setCompanyId(companyId);
+                            reportPushLog.setReportId(Integer.valueOf(String.valueOf(map.get("ReportId"))));
+                            reportPushLog.setTargetSystem("SAP");
+                            reportPushLog.setUuid(xmlResponseData.getEmployeeTime().getUUID());
+                            reportPushLogService.save(reportPushLog);
+                        }
+                        sapSyncLogService.save(sapSyncLog);
+                        System.out.println("线程:"+Thread.currentThread().getName()+"正在操作"+map.get("ReportId"));
+                    }
+                }
+            });
         }
-        long eTime = System.currentTimeMillis();
-        httpRespMsg.setData("推送完成 耗时:"+(eTime-sTime)+"ms");
+        httpRespMsg.setData("推送正在进行...待推送完成可查看工时日志");
+        executor.shutdown();
         return httpRespMsg;
     }
 
@@ -7593,7 +7643,7 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                     System.out.println(sb.toString());
                     String result = "";
                     try {
-                        result = WebServiceUtils.requestByXml("https://my602728.sapbyd.cn/sap/bc/srt/scs/sap/yyatr5vf6y_deleteemployeetime?sap-vhost=my602728.sapbyd.cn", sb.toString(), 0, "_BYDHOST", "Welcome1");
+                        result = WebServiceUtils.requestByXml("https://my601432.sapbyd.cn/sap/bc/srt/scs/sap/yyatr5vf6y_deleteemployeetime?sap-vhost=my601432.sapbyd.cn", sb.toString(), 0, "_BYDHOST", "Welcome1");
                     } catch (Exception e) {
                         e.printStackTrace();
                     }
@@ -7683,6 +7733,9 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
             map.put("realityTime",workingTime.doubleValue());
             map.put("isOver",bigDecimal.doubleValue()<0?"是":"否");
             map.put("remaining",bigDecimal.doubleValue()>0?bigDecimal.doubleValue():0);
+            String participations = String.valueOf(map.get("participations"));
+            String[] split = participations.split(",");
+            map.put("participations",split);
         }
         projectTimeCostList.forEach(pt->{
             List<Map<String, Object>> mapList = taskGroupPlanTimeList.stream().filter(t -> t.get("projectId").equals(pt.get("projectId"))).collect(Collectors.toList());
@@ -7697,6 +7750,9 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                     break;
             }
             pt.put("projectGroupData",mapList);
+            String participations = String.valueOf(pt.get("participations"));
+            String[] split = participations.split(",");
+            pt.put("participations",split);
         });
         responseData.put("projectArrays",projectTimeCostList);
         msg.setData(responseData);
@@ -8002,4 +8058,258 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
         httpRespMsg.setData(responseData);
         return httpRespMsg;
     }
+
+    @Override
+    public HttpRespMsg getUserWorkTimeByCategory(Integer categoryId, Integer deptId, String userId, String startDate, String endDate, Integer pageIndex, Integer pageSize) {
+        HttpRespMsg httpRespMsg=new HttpRespMsg();
+        if(categoryId==0){
+            categoryId=null;
+        }
+        User user = userMapper.selectById(request.getHeader("token"));
+        List<UserCustom> userCustomList = userCustomMapper.selectList(new LambdaQueryWrapper<UserCustom>().eq(UserCustom::getCompanyId, user.getCompanyId()));
+        DateTimeFormatter dtf=DateTimeFormatter.ofPattern("yyyy-MM-dd");
+        List<LocalDate> dates = getDays(LocalDate.parse(startDate, dtf), LocalDate.parse(endDate, dtf));
+        List<Map<String,Object>> headerStringList=new ArrayList<>();
+        List<Map<String,Object>> customStringList=new ArrayList<>();
+//        Map<String,Object> map1=new HashMap();
+//        Map<String,Object> map2=new HashMap();
+//        Map<String,Object> map3=new HashMap();
+//        Map<String,Object> map4=new HashMap();
+//        Map<String,Object> map5=new HashMap();
+//        map1.put("titleIndex","");
+//        map1.put("titleName","生产项目号");
+//        map2.put("titleIndex","");
+//        map2.put("titleName","姓名");
+//        map3.put("titleIndex","");
+//        map3.put("titleName","部门");
+//        headerStringList.add(map1);
+//        headerStringList.add(map2);
+//        headerStringList.add(map3);
+        for (int i = 0; i < userCustomList.size(); i++) {
+            Map<String,Object> map=new HashMap();
+            switch (i){
+                case 0: map.put("titleIndex","plate1");
+                    break;
+                case 1: map.put("titleIndex","plate2");
+                    break;
+                case 2: map.put("titleIndex","plate3");
+                    break;
+                case 3: map.put("titleIndex","plate4");
+                    break;
+                case 4: map.put("titleIndex","plate5");
+                    break;
+            }
+            map.put("titleName", userCustomList.get(i).getName());
+            customStringList.add(map);
+        }
+//        map4.put("titleIndex","allWorkingTime");
+//        map4.put("titleName","总工时");
+//        map5.put("titleIndex","targetWorkingTime");
+//        map5.put("titleName","生产工时");
+//        headerStringList.add(map4);
+//        headerStringList.add(map5);
+        for (LocalDate localDate : dates) {
+            Map<String,Object> map=new HashMap();
+            map.put("titleIndex",localDate.format(dtf));
+            map.put("titleName",localDate.format(dtf));
+            headerStringList.add(map);
+        }
+        List<Department> allDeptList = departmentMapper.selectList(new LambdaQueryWrapper<Department>().eq(Department::getCompanyId, user.getCompanyId()));
+        Integer size=null;
+        Integer start=null;
+        if(pageIndex!=null&&pageSize!=null){
+            size=pageSize;
+            start=(pageIndex-1)*size;
+        }
+        boolean viewAll = sysFunctionService.hasPriviledge(user.getRoleId(), "分类全部工时明细表");
+        boolean viewIncharge = sysFunctionService.hasPriviledge(user.getRoleId(), "分类负责部门工时明细表");
+        //判断是否有查看全部的权限
+        List<Map<String,Object>> resultList;
+        if(!viewAll){
+            //判断是否有查看负责部门的权限
+            if(!viewIncharge){
+                //只能查看与本人有关的数据
+                resultList=reportMapper.getUserWorkTimeByCategory(categoryId,user.getId(),user.getCompanyId(),null,deptId,startDate,endDate);
+            }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=reportMapper.getUserWorkTimeByCategory(categoryId,userId,user.getCompanyId(),deptIds,deptId,startDate,endDate);
+            }
+        }else {
+            //查看全部
+            resultList=reportMapper.getUserWorkTimeByCategory(categoryId,userId,user.getCompanyId(),null,deptId,startDate,endDate);
+        }
+
+        List<String> projectIdList = resultList.stream().map(m -> String.valueOf(m.get("projectId"))).distinct().collect(Collectors.toList());
+
+        Map<String, List<Map<String, Object>>> listMapGroupByProject = resultList.stream().collect(Collectors.groupingBy(r -> String.valueOf(r.get("projectId"))));
+        List<Map<String,Object>> lastList=new ArrayList<>();
+        for (String targetProjectId : projectIdList) {
+            List<Map<String, Object>> maps = listMapGroupByProject.get(targetProjectId);
+            Optional<Map<String, Object>> first = resultList.stream().filter(r -> String.valueOf(r.get("projectId")).equals(targetProjectId)).findFirst();
+            Map<String, List<Map<String, Object>>> listMapGroupByUser = maps.stream().collect(Collectors.groupingBy(r -> String.valueOf(r.get("userId"))));
+            List<String> userIdList = maps.stream().map(m -> String.valueOf(m.get("userId"))).distinct().collect(Collectors.toList());
+            for (String targetUserId : userIdList) {
+                if(first.isPresent()){
+                    Map<String, Object> map = first.get();
+                    Map<String,Object> item=new HashMap<>();
+                    item.put("userId",String.valueOf(map.get("userId")));
+                    item.put("projectCode",String.valueOf(map.get("projectCode")));
+                    item.put("deptName",String.valueOf(map.get("deptName")));
+                    item.put("userName",String.valueOf(map.get("userName")));
+                    item.put("deptId",String.valueOf(map.get("deptId")));
+                    item.put("targetWorkingTime",String.valueOf(map.get("targetWorkingTime")));
+                    item.put("allWorkingTime",String.valueOf(map.get("allWorkingTime")));
+                    item.put("plate1",map.get("plate1")==null?"":String.valueOf(map.get("plate1")));
+                    item.put("plate2",map.get("plate2")==null?"":String.valueOf(map.get("plate2")));
+                    item.put("plate3",map.get("plate3")==null?"":String.valueOf(map.get("plate3")));
+                    item.put("plate4",map.get("plate4")==null?"":String.valueOf(map.get("plate4")));
+                    item.put("plate5",map.get("plate5")==null?"":String.valueOf(map.get("plate5")));
+                    if(map.get("corpWxUserId")!=null){
+                        item.put("corpWxUserId",String.valueOf(map.get("corpWxUserId")));
+                    }
+                    if(map.get("corpWxDeptId")!=null){
+                        item.put("corpWxDeptId",String.valueOf(map.get("corpWxDeptId")));
+                    }
+                    List<Map<String, Object>> mapList = listMapGroupByUser.get(targetUserId);
+                    item.put("dataList",mapList);
+                    lastList.add(item);
+                }
+            }
+        }
+
+
+        if(start!=null&&size!=null){
+            if(lastList.size()<size){
+                size=lastList.size();
+            }
+            if(lastList.size()<start){
+                start=0;
+            }
+            lastList=lastList.subList(start,size);
+        }
+        Map<String,Object> resultMap=new HashMap<>();
+        resultMap.put("record",lastList);
+        resultMap.put("total",lastList.size());
+        resultMap.put("header",headerStringList);
+        resultMap.put("custom",customStringList);
+        httpRespMsg.setData(resultMap);
+        return httpRespMsg;
+    }
+
+    @Override
+    public HttpRespMsg exportUserWorkTimeByCategory(Integer categoryId, Integer deptId, String userId, String startDate, String endDate) {
+        HttpRespMsg msg = getUserWorkTimeByCategory(categoryId, deptId, userId, startDate, endDate, null, null);
+        Integer companyId = userMapper.selectById(request.getHeader("token")).getCompanyId();
+
+        WxCorpInfo wxCorpInfo = wxCorpInfoMapper.selectOne(new QueryWrapper<WxCorpInfo>().eq("company_id", companyId));
+        DateTimeFormatter dtf=DateTimeFormatter.ofPattern("yyyy-MM-dd");
+        List<LocalDate> dates = getDays(LocalDate.parse(startDate, dtf), LocalDate.parse(endDate, dtf));
+        List<UserCustom> userCustomList = userCustomMapper.selectList(new LambdaQueryWrapper<UserCustom>().eq(UserCustom::getCompanyId, companyId));
+        Map<String,Object> data = (Map<String, Object>) msg.getData();
+        List<List<String>> dataList=new ArrayList<>();
+        List<String> titleList=new ArrayList<>();
+        if(categoryId!=null){
+            ProjectCategory projectCategory = projectCategoryMapper.selectById(categoryId);
+            titleList.add(projectCategory.getName()+"项目号");
+        }else {
+            titleList.add("未分配");
+        }
+        titleList.add("姓名");
+        titleList.add("部门");
+        List<Map<String,Object>> headerList= (List<Map<String, Object>>) data.get("header");
+        List<Map<String,Object>> customList= (List<Map<String, Object>>) data.get("custom");
+        for (Map<String, Object> custom : customList) {
+            titleList.add(String.valueOf(custom.get("titleName")));
+        }
+        titleList.add("总工时");
+        if(categoryId!=null){
+            ProjectCategory projectCategory = projectCategoryMapper.selectById(categoryId);
+            titleList.add(projectCategory.getName()+"工时");
+        }else {
+            titleList.add("未分配工时");
+        }
+        for (Map<String, Object> header : headerList) {
+            titleList.add(String.valueOf(header.get("titleName")));
+        }
+        dataList.add(titleList);
+        List<Map<String,Object>> records = (List<Map<String, Object>>) data.get("record");
+        for (Map<String, Object> record : records) {
+            List<String> item=new ArrayList<>();
+            item.add(String.valueOf(record.get("projectCode")));
+            if(wxCorpInfo!=null&&wxCorpInfo.getSaasSyncContact()==1){
+                item.add("$userName="+String.valueOf(record.get("corpWxUserId"))+"$");
+                item.add("$departmentName="+String.valueOf(record.get("corpWxDeptId"))+"$");
+            }else {
+                item.add(String.valueOf(record.get("userName")));
+                item.add(String.valueOf(record.get("deptName")));
+            }
+            for (int i = 0; i < userCustomList.size(); i++) {
+                switch (i){
+                    case 0:item.add(record.get("plate1")==null?"":String.valueOf(record.get("plate1")));
+                        break;
+                    case 1:item.add(record.get("plate2")==null?"":String.valueOf(record.get("plate2")));
+                        break;
+                    case 2:item.add(record.get("plate3")==null?"":String.valueOf(record.get("plate3")));
+                        break;
+                    case 3:item.add(record.get("plate4")==null?"":String.valueOf(record.get("plate4")));
+                        break;
+                    case 4:item.add(record.get("plate5")==null?"":String.valueOf(record.get("plate5")));
+                        break;
+                }
+            }
+            item.add(String.valueOf(record.get("allWorkingTime")));
+            item.add(String.valueOf(record.get("targetWorkingTime")));
+            List<Map<String,Object>> details = (List<Map<String, Object>>) record.get("dataList");
+            for (LocalDate localDate : dates) {
+                String date = dtf.format(localDate);
+                Optional<Map<String, Object>> first = details.stream().filter(d -> String.valueOf(d.get("createDate")).equals(date)).findFirst();
+                if(first.isPresent()){
+                    item.add(String.valueOf(first.get().get("workingTime")));
+                }else {
+                    item.add("");
+                }
+            }
+            dataList.add(item);
+        }
+        String fileName = "分类工时明细表"+"_"+System.currentTimeMillis();
+        try {
+            return excelExportService.exportGeneralExcelByTitleAndList(wxCorpInfo, fileName, dataList, path);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return msg;
+    }
+
+    private List<Integer> getBranchDepartment(Integer departmentId, List<Department> departmentList) {
+        List<Integer> list = new ArrayList<>();
+        list.add(departmentId);
+        //搜到子部门进行添加
+        for (Department department : departmentList) {
+            if (departmentId.equals(department.getSuperiorId())) {
+                list.addAll(getBranchDepartment(department.getDepartmentId(), departmentList));
+            }
+        }
+        return list;
+    }
+
+    private  List<LocalDate> getDays(LocalDate start, LocalDate end) {
+        List<LocalDate> result = new ArrayList();
+        while (start.isBefore(end)) {
+            result.add(start);
+            start=start.plusDays(1);
+        }
+        result.add(start);
+        return result;
+    }
 }

+ 98 - 37
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/TaskServiceImpl.java

@@ -386,7 +386,7 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
     }
 
     @Override
-    public HttpRespMsg importTask(Integer projectId, Integer groupId, MultipartFile multipartFile, HttpServletRequest request) {
+    public HttpRespMsg importTask(Integer isMultiProject, Integer projectId, Integer groupId, MultipartFile multipartFile, HttpServletRequest request) throws Exception {
         HttpRespMsg httpRespMsg = new HttpRespMsg();
 
         //首先先搞到公司id
@@ -394,6 +394,13 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
         User creator = userMapper.selectById(userId);
         Integer companyId = creator.getCompanyId();
         WxCorpInfo wxCorpInfo = wxCorpInfoMapper.selectOne(new QueryWrapper<WxCorpInfo>().eq("company_id",companyId));
+        List<Project> allProjectList = null;
+        List<TaskGroup> allGroupList = null;
+        if (isMultiProject == 1) {
+            allProjectList = projectMapper.selectList(new QueryWrapper<Project>().select("id, project_code, project_name").eq("company_id", companyId));
+            //全部任务分组
+            allGroupList = taskGroupMapper.selectList(new QueryWrapper<TaskGroup>().select("id, name, project_id").in("project_id", allProjectList.stream().map(Project::getId).collect(Collectors.toList())));
+        }
         List<User> allUserList = userMapper.selectList(new QueryWrapper<User>().eq("company_id", companyId));
         HashMap<String, Integer> taskTypeMap = new HashMap<>();
         //taskTypeMap.put("任务", 0);
@@ -433,6 +440,8 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
             //要插入的账号列表
             List<Task> taskList = new ArrayList<>();
             List<String> userNameList=new ArrayList<>();
+            //Excel列下标从1开始
+            int taskListNameIndex = isMultiProject==0?0:3;//项目编号,项目名称,任务分组,任务列表; 在项目内导入时,任务列表作为第一列
             for (int rowIndex = 0; rowIndex <= sheet.getLastRowNum(); rowIndex++) {
                 XSSFRow row = sheet.getRow(rowIndex);
                 if (row == null) {
@@ -442,12 +451,12 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
                     continue;
                 }
                 System.out.println("rowIndex==="+rowIndex);
-                XSSFCell nameCell = row.getCell(1);
+                XSSFCell nameCell = row.getCell(taskListNameIndex+1);
                 if (nameCell == null) {
                     break;
                 }
                 System.out.println("name==="+nameCell.getStringCellValue());
-                XSSFCell executorCell = row.getCell(3);
+                XSSFCell executorCell = row.getCell(taskListNameIndex + 3);
                 if (executorCell != null) {
                     String[] executorNameArray = executorCell.getStringCellValue().split(",");
                     for (String s : executorNameArray) {
@@ -461,7 +470,9 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
             }
             System.out.println("参与搜素的人员列表"+userNameList + userNameList.size());
             HttpRespMsg respMsg=new HttpRespMsg();
+            boolean isCorpWxUser = false;
             if(wxCorpInfo!=null&&wxCorpInfo.getSaasSyncContact()==1&&userNameList.size()>0){
+                isCorpWxUser = true;
                 respMsg = wxCorpInfoService.getBatchSearchUserInfo(wxCorpInfo, userNameList,null);
                 if(respMsg.code.equals("0")){
                     httpRespMsg.setError("姓名为["+String.valueOf(respMsg.data)+"]的人员存在重复,请使用工号!");
@@ -476,34 +487,95 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
                 if (row == null) {
                     continue;
                 }
-                //此处新建账号 默认密码为000000 默认 姓名第一列 手机号第二列 月薪第三列
-                XSSFCell stagesCell = row.getCell(0);
-                XSSFCell nameCell = row.getCell(1);
+
+                XSSFCell stagesCell = row.getCell(taskListNameIndex);
+                XSSFCell nameCell = row.getCell(taskListNameIndex + 1);
                 if (nameCell == null || stagesCell == null) {
                     break;
                 }
-                XSSFCell typeCell = row.getCell(2);
-                XSSFCell executorCell = row.getCell(3);
-                XSSFCell levelCell = row.getCell(4);
-                XSSFCell startDateCell = row.getCell(5);
-                XSSFCell endDateCell = row.getCell(6);
-                XSSFCell planHoursCell = row.getCell(7);
-                XSSFCell descCell = row.getCell(8);
+                XSSFCell typeCell = row.getCell(taskListNameIndex + 2);
+                XSSFCell executorCell = row.getCell(taskListNameIndex + 3);
+                XSSFCell levelCell = row.getCell(taskListNameIndex + 4);
+                XSSFCell startDateCell = row.getCell(taskListNameIndex + 5);
+                XSSFCell endDateCell = row.getCell(taskListNameIndex + 6);
+                XSSFCell planHoursCell = row.getCell(taskListNameIndex + 7);
+                XSSFCell descCell = row.getCell(taskListNameIndex + 8);
                 nameCell.setCellType(CellType.STRING);
                 stagesCell.setCellType(CellType.STRING);
-                typeCell.setCellType(CellType.STRING);
-                endDateCell.setCellType(CellType.NUMERIC);
+
+                String type = "任务";//默认类型
+                if (typeCell != null) {
+                    typeCell.setCellType(CellType.STRING);
+                    type = typeCell.getStringCellValue();
+                }
+                if (endDateCell != null) {
+                    endDateCell.setCellType(CellType.NUMERIC);
+                }
                 if(planHoursCell!=null){
                     planHoursCell.setCellType(CellType.STRING);
                 }
                 String name = nameCell.getStringCellValue();
-                String type = typeCell.getStringCellValue();
+
                 //忽略表头
                 if ((name.equals("任务内容") || name.equals("Task content")) && (type.equals("类型") || type.equals("type")) && rowIndex == 0) {
                     continue;
                 }
                 Task task = new Task();
                 task.setCompanyId(companyId);
+                //多项目下任务导入和单项目下任务导入,两种模式的taskListNameIndex值不一样
+                String projectCode = null;
+                String projectName = null;
+                String taskGroupName = null;
+                //设置所属项目和任务分组ID
+                if (isMultiProject == 1) {
+                    XSSFCell codeCell = row.getCell(0);
+                    XSSFCell pnameCell = row.getCell(1);
+                    XSSFCell tgoupNameCell = row.getCell(2);
+                    if (codeCell != null) {
+                        codeCell.setCellType(CellType.STRING);
+                        projectCode = codeCell.getStringCellValue().trim();
+                    }
+                    if (pnameCell != null) {
+                        pnameCell.setCellType(CellType.STRING);
+                        projectName = pnameCell.getStringCellValue().trim();
+                    }
+                    if (tgoupNameCell != null) {
+                        tgoupNameCell.setCellType(CellType.STRING);
+                        taskGroupName = tgoupNameCell.getStringCellValue().trim();
+                    }
+
+                    //定位项目
+                    projectId = null;
+                    if (!StringUtil.isEmpty(projectCode)) {
+                        final String code = projectCode;
+                        Optional<Project> first = allProjectList.stream().filter(project -> code.equals(project.getProjectCode())).findFirst();
+                        if (first.isPresent()) {
+                            projectId = first.get().getId();
+                        }
+                    } else if (!StringUtil.isEmpty(projectName)) {
+                        final String pname = projectName;
+                        Optional<Project> first = allProjectList.stream().filter(project -> pname.equals(project.getProjectName())).findFirst();
+                        if (first.isPresent()) {
+                            projectId = first.get().getId();
+                        }
+                    }
+                    if (projectId == null) {
+                        throw new Exception("项目不存在:(编号:"+projectCode+",名称:"+projectName+")");
+                    }
+                    //任务分组
+                    groupId = null;//先清空
+                    if (!StringUtil.isEmpty(taskGroupName)) {
+                        final String groupName = taskGroupName;
+                        final int pid = projectId;
+                        Optional<TaskGroup> first = allGroupList.stream().filter(group -> groupName.equals(group.getName()) && group.getProjectId().equals(pid)).findFirst();
+                        if (first.isPresent()) {
+                            groupId = first.get().getId();
+                        }
+                    }
+                    if (groupId == null) {
+                        throw new Exception("任务分组不存在:"+taskGroupName);
+                    }
+                }
                 task.setProjectId(projectId);
                 task.setGroupId(groupId);
                 if(executorCell!=null){
@@ -514,8 +586,14 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
                     String executorColorString="";
                     for (int i=0;i<executorNameList.size();i++) {
                         String executorName = executorNameList.get(i);
-                        Optional<User> optional = targetUserList.stream().filter(tl -> tl.getName().equals(executorName)).findFirst();
-                        Optional<User> first = allUserList.stream().filter(u ->optional.isPresent()&&u.getCorpwxUserid().equals(optional.get().getCorpwxUserid())).findFirst();
+                        Optional<User> first = null;
+                        if (isCorpWxUser) {
+                            Optional<User> optional = targetUserList.stream().filter(tl -> tl.getName().equals(executorName)).findFirst();
+                            first = allUserList.stream().filter(u->(optional.isPresent()&&u.getCorpwxUserid().equals(optional.get().getCorpwxUserid()))).findFirst();
+                        } else {
+                            first = allUserList.stream().filter(u ->u.getName().equals(executorName)).findFirst();
+                        }
+
                         if (first.isPresent()) {
                             User find = first.get();
                             if(i==executorNameList.size()-1){
@@ -559,14 +637,14 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
                 if(levelCell!=null){
                     task.setTaskLevel(taskLevelMap.get(levelCell.getStringCellValue()));
                 }
-                if(startDateCell.getDateCellValue()!=null){
+                if(startDateCell != null && startDateCell.getDateCellValue()!=null){
                     Date dateCellValue = startDateCell.getDateCellValue();
                     System.out.println("日期=="+dateCellValue.toString());
                     String formatValue = new SimpleDateFormat("yyyy-MM-dd").format(dateCellValue);
                     LocalDate startDate = LocalDate.parse(formatValue, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
                     task.setStartDate(startDate);
                 }
-                if(endDateCell.getDateCellValue()!=null){
+                if(endDateCell != null && endDateCell.getDateCellValue()!=null){
                     Date dateCellValue = endDateCell.getDateCellValue();
                     System.out.println("日期=="+dateCellValue.toString());
                     String formatValue = new SimpleDateFormat("yyyy-MM-dd").format(dateCellValue);
@@ -598,29 +676,12 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
                 for (List<TaskExecutor> executorList : executorListAll) {
                     taskExecutorService.saveBatch(executorList);
                 }
-
             }
-            //最后删掉这个文件
-//            if (!file.delete()) {
-//                System.out.println("临时文件" + file.getName() + "删除失败");
-//            }
-            //校验是否有重复账号
-
         } catch (IOException e) {
             e.printStackTrace();
             //httpRespMsg.setError("文件处理出错");
             httpRespMsg.setError(MessageUtils.message("file.error"));
             return httpRespMsg;
-        } catch (NullPointerException e) {
-            e.printStackTrace();
-            //httpRespMsg.setError("数据格式有误或存在空数据 导入失败");
-            httpRespMsg.setError(MessageUtils.message("file.dataFormatError"));
-            return httpRespMsg;
-        } catch (Exception e) {
-            e.printStackTrace();
-            //httpRespMsg.setError("发生其他错误");
-            httpRespMsg.setError(MessageUtils.message("other.error"));
-            return httpRespMsg;
         } finally {
             //关闭流
             try {

+ 37 - 11
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/UserServiceImpl.java

@@ -3,6 +3,7 @@ package com.management.platform.service.impl;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.aliyun.dysmsapi20170525.models.SendSmsResponse;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@@ -1980,7 +1981,9 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
         try {
             String userId = request.getHeader("Token");
             User user = userMapper.selectById(userId);
+            TimeType timeType = timeTypeMapper.selectById(user.getCompanyId());
             WxCorpInfo wxCorpInfo = wxCorpInfoMapper.selectOne(new QueryWrapper<WxCorpInfo>().eq("company_id", user.getCompanyId()));
+            List<User> userList = userMapper.selectList(new LambdaQueryWrapper<User>().select(User::getId, User::getName, User::getCorpwxUserid).eq(User::getCompanyId, user.getCompanyId()));
             List<UserCustom> userCustomList = userCustomMapper.selectList(new QueryWrapper<UserCustom>().eq("company_id", user.getCompanyId()));
             //查看当前用户是否有人员成本的查看权限
             boolean canViewCost = sysFunctionService.hasPriviledge(user.getRoleId(), "人员成本管理");
@@ -2029,30 +2032,36 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
             //headCell.setCellValue("部门");
             headCell.setCellValue(MessageUtils.message("excel.department"));
             headCell.setCellStyle(headStyle);
+            if(timeType.getReportAuditType() == 5 || timeType.getReportAuditType() == 6){
+                headCell = headRow.createCell(5);
+                //headCell.setCellValue("部门");
+                headCell.setCellValue("直属审核人");
+                headCell.setCellStyle(headStyle);
+            }
 
             int minusIndex = -2;
             if (canViewCost) {
-                headCell = headRow.createCell(5);
+                headCell = headRow.createCell(6);
                 //headCell.setCellValue("月薪");
                 headCell.setCellValue(MessageUtils.message("excel.MonSalary"));
                 headCell.setCellStyle(headStyle);
-                headCell = headRow.createCell(6);
+                headCell = headRow.createCell(7);
                 //headCell.setCellValue("时薪");
                 headCell.setCellValue(MessageUtils.message("excel.hourlyWage"));
                 headCell.setCellStyle(headStyle);
                 minusIndex = 0;
             }
 
-            headCell = headRow.createCell(7+minusIndex);
+            headCell = headRow.createCell(8+minusIndex);
             //headCell.setCellValue("证书");
             headCell.setCellValue(MessageUtils.message("excel.certificate"));
             headCell.setCellStyle(headStyle);
             for (int i = 0; i < userCustomList.size(); i++) {
-                headCell = headRow.createCell(minusIndex+8+i);
+                headCell = headRow.createCell(minusIndex+9+i);
                 headCell.setCellValue(userCustomList.get(i).getName());
                 headCell.setCellStyle(headStyle);
             }
-            headCell = headRow.createCell(minusIndex+8+userCustomList.size());
+            headCell = headRow.createCell(minusIndex+9+userCustomList.size());
             //headCell.setCellValue("状态");
             headCell.setCellValue(MessageUtils.message("leave.status"));
             headCell.setCellStyle(headStyle);
@@ -2096,9 +2105,26 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
                 }else {
                     row.createCell(4).setCellValue(item.getDepartmentName());
                 }
+                if(timeType.getReportAuditType()==5||timeType.getReportAuditType()==6){
+                    if(item.getSuperiorId()!=null){
+                        Optional<User> first = userList.stream().filter(u ->u.getId().equals(item.getSuperiorId())).findFirst();
+                        if(first.isPresent()){
+                            if(wxCorpInfo!=null&&wxCorpInfo.getSaasSyncContact()==1){
+                                row.createCell(5).setCellValue("$userName="+(first.get().getCorpwxUserid()==null?" ":first.get().getCorpwxUserid())+"$");
+                            }else {
+                                row.createCell(5).setCellValue(first.get().getName());
+                            }
+                        }else {
+                            row.createCell(5).setCellValue("");
+                        }
+                    }else {
+                        row.createCell(5).setCellValue("");
+                    }
+
+                }
                 if (canViewCost) {
-                    row.createCell(5).setCellValue(item.getMonthCost()==null? 0 : item.getMonthCost().intValue());
-                    row.createCell(6).setCellValue(item.getCost() == null?0.0 : item.getCost().doubleValue());
+                    row.createCell(6).setCellValue(item.getMonthCost()==null? 0 : item.getMonthCost().intValue());
+                    row.createCell(7).setCellValue(item.getCost() == null?0.0 : item.getCost().doubleValue());
                 }
                 List<UserCert> certList = userCertList.stream().distinct().filter(uc -> uc.getUserId().equals(item.getId())).collect(Collectors.toList());
                 if(certList.size()>0){
@@ -2110,9 +2136,9 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
                             s+=certList.get(i).getCertName()+" "+certList.get(i).getCertDate();
                         }
                     }
-                    row.createCell(7+minusIndex).setCellValue(s);
+                    row.createCell(8+minusIndex).setCellValue(s);
                 }else {
-                    row.createCell(7+minusIndex).setCellValue("");
+                    row.createCell(8+minusIndex).setCellValue("");
                 }
                 for (int i = 0; i < userCustomList.size(); i++) {
                     String value="";
@@ -2128,9 +2154,9 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
                         case 4:value=item.getPlate5()==null?"":item.getPlate5();
                             break;
                     }
-                    row.createCell(8+i+minusIndex).setCellValue(value);
+                    row.createCell(9+i+minusIndex).setCellValue(value);
                 }
-                row.createCell(8+userCustomList.size()+minusIndex).setCellValue(item.getIsActive()==1?MessageUtils.message("excel.normal"):MessageUtils.message("access.deactivated"));
+                row.createCell(9+userCustomList.size()+minusIndex).setCellValue(item.getIsActive()==1?MessageUtils.message("excel.normal"):MessageUtils.message("access.deactivated"));
                 rowNum++;
             }
             //生成Excel文件

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

@@ -0,0 +1,20 @@
+package com.management.platform.service.impl;
+
+import com.management.platform.entity.UserWithBeisen;
+import com.management.platform.mapper.UserWithBeisenMapper;
+import com.management.platform.service.UserWithBeisenService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ *  服务实现类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2024-01-09
+ */
+@Service
+public class UserWithBeisenServiceImpl extends ServiceImpl<UserWithBeisenMapper, UserWithBeisen> implements UserWithBeisenService {
+
+}

+ 119 - 49
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/task/TimingTask.java

@@ -49,9 +49,7 @@ import java.time.temporal.TemporalAccessor;
 import java.time.temporal.TemporalAdjusters;
 import java.time.temporal.WeekFields;
 import java.util.*;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.Executor;
-import java.util.concurrent.Executors;
+import java.util.concurrent.*;
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
 
@@ -174,6 +172,8 @@ public class TimingTask {
     private SapProjectServiceService sapProjectServiceService;
     @Resource
     private SapSyncLogService sapSyncLogService;
+    @Resource
+    private UserWithBeisenService userWithBeisenService;
 
 
     private static final List<Integer> VALID_TOKEN_CHARS = new ArrayList<>();
@@ -516,7 +516,8 @@ public class TimingTask {
                     leaveSheet.setLeaveType(leaveType);
                     leaveSheet.setProcinstId(String.valueOf(map.get("id")));
                     leaveSheet.setGmtFinished(String.valueOf(map.get("gmtFinished")));
-                    Optional<LeaveSheet> first = oldLeaveSheetList.stream().filter(ol -> ol.getStartDate().isEqual(leaveSheet.getStartDate())&&ol.getEndDate().isEqual(leaveSheet.getEndDate())&& ol.getOwnerId().equals(leaveSheet.getOwnerId())&&(ol.getProcinstId()!=null&& ol.getProcinstId().equals(leaveSheet.getProcinstId()))).findFirst();
+                    //看看是否已经存在:同一个人,同一段时间,同样的请假时长则视为同一条记录
+                    Optional<LeaveSheet> first = oldLeaveSheetList.stream().filter(ol -> ol.getStartDate().isEqual(leaveSheet.getStartDate())&&ol.getEndDate().isEqual(leaveSheet.getEndDate())&& ol.getOwnerId().equals(leaveSheet.getOwnerId())&&ol.getTimeHours().equals(leaveSheet.getTimeHours())).findFirst();
                     if(first.isPresent()){
                         leaveSheet.setId(first.get().getId());
                     }
@@ -1699,45 +1700,66 @@ public class TimingTask {
         LocalDateTime localDateTime=LocalDateTime.now();
         for (TimeType timeType : timeTypeList) {
             Integer companyId = timeType.getCompanyId();
-            List<SapSyncLog> sapSyncLogs=new ArrayList<>();
             //提前推送项目工时(工时管家相关项目任务分组阶段下任务作为SAP服务 预算工时数据推送到SAP)
-            List<Map<String, Object>> pushProjectPlanHour = reportMapper.getProjectPlanData(companyId,null,null);
-            List<SapSyncLog> projectPlanSapSyncLogs = SyncSapUtils.pushProjectPlanToSap(pushProjectPlanHour, companyId, "");
-            sapSyncLogs.addAll(projectPlanSapSyncLogs);
             List<Map<String, Object>> mapList = reportMapper.getPushProjectReportToSap(companyId,df.format(date.minusDays(1)),df.format(date.minusDays(1)), null);
-            List<ReportPushLog> addList=new ArrayList<>();
-            for (Map<String, Object> map : mapList) {
-                ReportPushLog one = reportPushLogService.getOne(new LambdaQueryWrapper<ReportPushLog>().eq(ReportPushLog::getCompanyId, companyId).eq(ReportPushLog::getReportId, map.get("ReportId")).eq(ReportPushLog::getTargetSystem,"SAP"));
-                if(one!=null){
-                    continue;
-                }
-                XmlResponseData xmlResponseData = SyncSapUtils.pushReportToSap(map);
-                SapSyncLog sapSyncLog=new SapSyncLog();
-                sapSyncLog.setCompanyId(companyId);
-                sapSyncLog.setRemark("日报数据推送");
-                sapSyncLog.setSyncType("定时任务推送");
-                sapSyncLog.setSyncTime(localDateTime);
-                if(StringUtils.isEmpty(xmlResponseData.getEmployeeTime())){
-                    log.error("推送失败===》工号:"+map.get("EmployeeID"));
-                    sapSyncLog.setResult("员工工号["+map.get("EmployeeID")+"]"+map.get("StartDate")+"日报推送失败");
-                    sapSyncLog.setResultRemark(xmlResponseData.getLog()!=null?xmlResponseData.getLog().getItem()!=null?xmlResponseData.getLog().getItem().getNote():"":"");
-                }else {
-                    sapSyncLog.setResult("工号["+map.get("EmployeeID")+"]"+map.get("StartDate")+"日报推送成功");
-                    //推送成功 日报数据打上标记
-                    ReportPushLog reportPushLog=new ReportPushLog();
-                    reportPushLog.setCompanyId(companyId);
-                    reportPushLog.setReportId(Integer.valueOf(String.valueOf(map.get("ReportId"))));
-                    reportPushLog.setTargetSystem("SAP");
-                    reportPushLog.setUuid(xmlResponseData.getEmployeeTime().getUUID());
-                    addList.add(reportPushLog);
+            //过滤服务code为空的数据
+            mapList=mapList.stream().filter(r->r.get("ProjectElementID")!=null && !StringUtils.isEmpty(String.valueOf(r.get("ProjectElementID")))).collect(Collectors.toList());
+            List<Integer> projectIds = mapList.stream().map(r -> Integer.valueOf(String.valueOf(r.get("ProjectId")))).distinct().collect(Collectors.toList());
+            projectIds.add(-1);
+            List<Map<String, Object>> pushProjectPlanHour = reportMapper.getProjectPlanData(companyId,projectIds,null,null);
+//            List<SapSyncLog> projectPlanSapSyncLogs = SyncSapUtils.pushProjectPlanToSap(pushProjectPlanHour, companyId, "");
+//            if(projectPlanSapSyncLogs.size()>0){
+//                sapSyncLogService.saveBatch(projectPlanSapSyncLogs);
+//            }
+            Map<String, List<Map<String, Object>>> listGroupEmployeeID = mapList.stream().collect(Collectors.groupingBy(r -> String.valueOf(r.get("EmployeeID"))));
+            List<String> employeeIDList = mapList.stream().map(r -> String.valueOf(r.get("EmployeeID"))).distinct().collect(Collectors.toList());
+            //按照人员集合长度来创建多个个线程来处理
+            int threadNum = employeeIDList.size();
+            //多加一个作为预算工时推送
+            ExecutorService executor = Executors.newFixedThreadPool(threadNum+1);
+            executor.execute(new Runnable() {
+                @Override
+                public void run() {
+                    List<SapSyncLog> projectPlanSyncLogs = SyncSapUtils.pushProjectPlanToSap(pushProjectPlanHour, companyId, "",isDev);
+                    if(projectPlanSyncLogs.size()>0){
+                        sapSyncLogService.saveBatch(projectPlanSyncLogs);
+                    }
                 }
-                sapSyncLogs.add(sapSyncLog);
-            }
-            if(addList.size()>0){
-                reportPushLogService.saveBatch(addList);
-            }
-            if(sapSyncLogs.size()>0){
-                sapSyncLogService.saveBatch(sapSyncLogs);
+            });
+            for (int i = 0; i <employeeIDList.size() ; i++) {
+                List<Map<String, Object>> targetList = listGroupEmployeeID.get(employeeIDList.get(i));
+                executor.execute(new Runnable() {
+                    @Override
+                    public void run() {
+                        for (Map<String, Object> map : targetList) {
+                            ReportPushLog one = reportPushLogService.getOne(new LambdaQueryWrapper<ReportPushLog>().eq(ReportPushLog::getCompanyId, companyId).eq(ReportPushLog::getReportId, map.get("ReportId")).eq(ReportPushLog::getTargetSystem,"SAP"));
+                            if(one!=null){
+                                continue;
+                            }
+                            XmlResponseData xmlResponseData = SyncSapUtils.pushReportToSap(map,isDev);
+                            SapSyncLog sapSyncLog=new SapSyncLog();
+                            sapSyncLog.setCompanyId(companyId);
+                            sapSyncLog.setRemark("日报数据推送");
+                            sapSyncLog.setSyncType("定时任务推送");
+                            sapSyncLog.setSyncTime(localDateTime);
+                            if(StringUtils.isEmpty(xmlResponseData.getEmployeeTime())){
+                                log.error("推送失败===》工号:"+map.get("EmployeeID"));
+                                sapSyncLog.setResult("员工工号["+map.get("EmployeeID")+"]"+map.get("StartDate")+"日报推送失败");
+                                sapSyncLog.setResultRemark(xmlResponseData.getLog()!=null?xmlResponseData.getLog().getItem()!=null?xmlResponseData.getLog().getItem().getNote():"":"");
+                            }else {
+                                sapSyncLog.setResult("员工工号["+map.get("EmployeeID")+"]"+map.get("StartDate")+"日报推送成功");
+                                //推送成功 日报数据打上标记
+                                ReportPushLog reportPushLog=new ReportPushLog();
+                                reportPushLog.setCompanyId(companyId);
+                                reportPushLog.setReportId(Integer.valueOf(String.valueOf(map.get("ReportId"))));
+                                reportPushLog.setTargetSystem("SAP");
+                                reportPushLog.setUuid(xmlResponseData.getEmployeeTime().getUUID());
+                                reportPushLogService.save(reportPushLog);
+                            }
+                            sapSyncLogService.save(sapSyncLog);
+                        }
+                    }
+                });
             }
         }
     }
@@ -1754,11 +1776,11 @@ public class TimingTask {
         for (TimeType timeType : timeTypeList) {
             Integer companyId = timeType.getCompanyId();
             //获取SAP项目服务数据 ----> 工时管家任务分组下阶段作为项目服务数据
-            XmlResponseData projectServiceData= SyncSapUtils.syncServiceData(df.format(date.minusDays(1)), null, companyId);
+            XmlResponseData projectServiceData= SyncSapUtils.syncServiceData(df.format(date.minusDays(1)), null, companyId,isDev);
             //已有的项目分类
             List<ProjectCategory> allProjectCategoryList = projectCategoryMapper.selectList(new QueryWrapper<ProjectCategory>().eq("company_id", companyId));
             List<Project> projectList = projectMapper.selectList(new QueryWrapper<Project>().eq("company_id", companyId));
-            XmlResponseData xmlResponseData = SyncSapUtils.syncProjectFromSap(df.format(date.minusDays(1)), df.format(date.minusDays(1)));
+            XmlResponseData xmlResponseData = SyncSapUtils.syncProjectFromSap(df.format(date.minusDays(1)), df.format(date.minusDays(1)),null,isDev);
             List<ProjectQueryResponse> projectQueryResponses = xmlResponseData.getProjectQueryResponses();
             List<Map<String,Object>> idsMapList=new ArrayList<>();
             LocalDate localDate=LocalDate.now();
@@ -1838,6 +1860,7 @@ public class TimingTask {
                         List<String> stagesUUIDList = stagesList.stream().map(ProjectTask::getUUID).collect(Collectors.toList());
                         //抽调出最末级
                         List<ProjectTask> taskList = projectTasks.stream().filter(p ->p.getParentTaskUUID() != null &&stagesUUIDList.contains(p.getParentTaskUUID())&&(p.getSummaryTaskIndicator()==null||(p.getSummaryTaskIndicator()!=null && !p.getSummaryTaskIndicator().equals("true")))).collect(Collectors.toList());
+                        List<Task> tasks=new ArrayList<>();
                         if(taskGroupList!=null && taskGroupList.size()>0){
                             for (ProjectTask group : taskGroupList) {
                                 //如果作为第二层数据是不存在下级数据的 把当前数据作为第四层数据 手动添加阶段数据 作为该数据的上级数据
@@ -1872,7 +1895,8 @@ public class TimingTask {
                                     if(three!=null){
                                         task.setId(three.getId());
                                     }
-                                    taskService.saveOrUpdate(task);
+//                                taskService.saveOrUpdate(task);
+                                    tasks.add(task);
                                 }else {
                                     TaskGroup taskGroup=new TaskGroup();
                                     taskGroup.setProjectId(project.getId());
@@ -1921,7 +1945,8 @@ public class TimingTask {
                                     if(two!=null){
                                         task.setId(two.getId());
                                     }
-                                    taskService.saveOrUpdate(task);
+//                                taskService.saveOrUpdate(task);
+                                    tasks.add(task);
                                 }else {
                                     Stages stage = new Stages();
                                     stage.setSequence(1);
@@ -1959,9 +1984,21 @@ public class TimingTask {
                                 if(one!=null){
                                     task.setId(one.getId());
                                 }
-                                taskService.saveOrUpdate(task);
+//                            taskService.saveOrUpdate(task);
+                                tasks.add(task);
                             }
                         }
+                        if(tasks.size()>0){
+                            Map<Integer, List<Task>> listMap = tasks.stream().collect(Collectors.groupingBy(t -> t.getStagesId()));
+                            List<Integer> list = tasks.stream().map(Task::getStagesId).collect(Collectors.toList());
+                            for (Integer id : list) {
+                                List<Task> subList = listMap.get(id);
+                                for (int i = 0; i < subList.size(); i++) {
+                                    subList.get(i).setSeq(i);
+                                }
+                            }
+                            taskService.saveOrUpdateBatch(tasks);
+                        }
                     }
                 }
             }
@@ -1977,18 +2014,51 @@ public class TimingTask {
                             sapProjectService.setServiceCode(serviceProduct.getInternalID());
                             sapProjectService.setServiceName(serviceProduct.getDescription().getDescription());
                             sapProjectService.setCompanyId(companyId);
-                            boolean match = serviceList.stream().anyMatch(s -> s.getServiceCode().equals(serviceProduct.getInternalID()));
-                            if(!match){
-                                sapProjectServiceList.add(sapProjectService);
+                            Optional<SapProjectService> first = serviceList.stream().filter(s -> s.getServiceCode().equals(serviceProduct.getInternalID())).findFirst();
+                            if(first.isPresent()){
+                                sapProjectService.setId(first.get().getId());
                             }
+                            sapProjectServiceList.add(sapProjectService);
                         }
                     }
                 }
             }
             if(sapProjectServiceList.size()>0){
-                sapProjectServiceService.saveBatch(sapProjectServiceList);
+                sapProjectServiceService.saveOrUpdateBatch(sapProjectServiceList);
+            }
+        }
+    }
+
+    //每天凌晨  2:30 获取前一天时间增量的人员数据  BeiSenHR---->工时管家  针对威派格
+    @Scheduled(cron = "0 30 2 ? * *")
+    public void getByTimeWindow(){
+        List<UserWithBeisen> allBeisenList = userWithBeisenService.list(new LambdaQueryWrapper<UserWithBeisen>().eq(UserWithBeisen::getCompanyId, 936));
+        List<UserWithBeisen> userWithBeisenList=new ArrayList<>();
+        LocalDate now=LocalDate.now();
+        DateTimeFormatter df=DateTimeFormatter.ofPattern("yyyy-MM-dd");
+        String time=df.format(now.plusDays(1));
+        List<JSONArray> byTimeWindow = BeiSenUtils.getByTimeWindow("",time,time);
+        for (JSONArray array : byTimeWindow) {
+            for (int i = 0; i < array.size(); i++) {
+                UserWithBeisen userWithBeisen=new UserWithBeisen();
+                JSONObject targetItem = array.getJSONObject(i);
+                JSONObject employeeInfo = targetItem.getJSONObject("employeeInfo");
+                JSONObject recordInfo = targetItem.getJSONObject("recordInfo");
+                userWithBeisen.setCompanyId(936);
+                userWithBeisen.setJobNumber(recordInfo.getString("jobNumber"));
+                userWithBeisen.setMobilePhone(employeeInfo.getString("mobilePhone"));
+                userWithBeisen.setName(employeeInfo.getString("name"));
+                userWithBeisen.setUserId(employeeInfo.getString("userID"));
+                Optional<UserWithBeisen> first = allBeisenList.stream().filter(a -> a.getUserId().equals(employeeInfo.getString("userID"))).findFirst();
+                if(first.isPresent()){
+                    userWithBeisen.setId(first.get().getId());
+                }
+                userWithBeisenList.add(userWithBeisen);
             }
         }
+        if(userWithBeisenList.size()>0){
+            userWithBeisenService.saveOrUpdateBatch(userWithBeisenList);
+        }
     }
 
 }

+ 103 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/util/BeiSenUtils.java

@@ -0,0 +1,103 @@
+package com.management.platform.util;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.MapperFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import com.management.platform.entity.FeishuInfo;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.util.EntityUtils;
+import org.springframework.http.*;
+import org.springframework.util.StringUtils;
+import org.springframework.web.client.RestTemplate;
+
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.sql.Timestamp;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+
+public class BeiSenUtils {
+    static String port="10.1.10.41:20170";
+
+    public static void main(String[] args) {
+        BeiSenUtils dockWithMLD=new BeiSenUtils();
+        JSONObject jsonObject=new JSONObject();
+        LocalDateTime startDate=LocalDateTime.parse("2022-08-01 00:00:00",DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+        LocalDateTime endDate=LocalDateTime.parse("2022-08-31 00:00:00",DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+        jsonObject.put("startDate",startDate);
+        jsonObject.put("endDate",endDate);
+        String jsonString = jsonObject.toJSONString();
+//        dockWithMLD.getResult("http://"+port+"/api/cube/restful/interface/getModeDataPageList/getTravelRecord",jsonString);
+    }
+
+    public static String getToken(){
+        String result="";
+        String url = "https://openapi.italent.cn/token";
+        HttpHeaders headers = new HttpHeaders();
+        RestTemplate restTemplate = new RestTemplate();
+        MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
+        headers.setContentType(type);
+        JSONObject requestMap = new JSONObject();
+        requestMap.put("grant_type","client_credentials");
+        requestMap.put("app_key","0AE887ADF87148EABF38B64BBE5B6BA6");
+        requestMap.put("app_secret","23054CE7CBAF4B1A8BA5FC878077A35A5BF7FF3AAC4D4A828CC7043E8017FF5A");
+        HttpEntity<JSONObject> entity = new HttpEntity<>(requestMap, headers);
+        ResponseEntity<String> ResponseEntity = restTemplate.postForEntity(url, entity, String.class);
+        if (ResponseEntity.getStatusCode() == HttpStatus.OK) {
+            String resp = ResponseEntity.getBody();
+            JSONObject respJson = JSONObject.parseObject(resp);
+            result=respJson.getString("access_token");
+        }
+        return result;
+    }
+
+    public static List<JSONArray> getByTimeWindow(String scrollId,String startTime,String stopTime){
+        List<JSONArray> resultList=new ArrayList<>();
+        String url = "https://openapi.italent.cn/TenantBaseExternal/api/v5/Employee/GetByTimeWindow";
+        HttpHeaders headers = new HttpHeaders();
+        RestTemplate restTemplate = new RestTemplate();
+        MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
+        headers.setContentType(type);
+        String accessToken = getToken();
+        System.out.println("--------Bearer TOKEN--------"+accessToken);
+        headers.add("Authorization","Bearer "+accessToken);
+        JSONObject requestMap = new JSONObject();
+        requestMap.put("timeWindowQueryType",1);
+        requestMap.put("startTime",startTime+"T00:00:00");
+        requestMap.put("stopTime",stopTime+"T23:59:59");
+        System.out.println("--------headers请求头数据-------"+headers);
+        System.out.println("--------requestMap请求参数-------"+requestMap);
+        if(!StringUtils.isEmpty(scrollId)){
+            requestMap.put("scrollId",scrollId);
+        }
+        HttpEntity<JSONObject> entity = new HttpEntity<>(requestMap, headers);
+        ResponseEntity<String> ResponseEntity = restTemplate.postForEntity(url, entity, String.class);
+        if (ResponseEntity.getStatusCode() == HttpStatus.OK) {
+            String resp= ResponseEntity.getBody();
+            JSONObject respJson = JSONObject.parseObject(resp);
+            if(respJson.getIntValue("code")==200){
+                resultList.add(respJson.getJSONArray("data"));
+                String nextScrollId = respJson.getString("scrollId");
+                if(!StringUtils.isEmpty(nextScrollId)&&respJson.getJSONArray("data").size()>0){
+                    List<JSONArray> byTimeWindow = getByTimeWindow(nextScrollId,startTime,stopTime);
+                    resultList.addAll(byTimeWindow);
+                }
+                return resultList;
+            }
+        }
+        return resultList;
+    }
+
+}

+ 70 - 43
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/util/SyncSapUtils.java

@@ -9,6 +9,7 @@ import com.management.platform.service.ReportService;
 import com.management.platform.service.SapSyncLogService;
 import com.management.platform.webservice.po.*;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.util.StringUtils;
 
 import javax.annotation.Resource;
@@ -21,12 +22,9 @@ import java.util.stream.Collectors;
 @Slf4j
 public class SyncSapUtils {
 
-    @Resource
-    private SapSyncLogService sapSyncLogService;
-
 
     //工时管家推送项目任务计划工时数据到SAP
-    public static List<SapSyncLog> pushProjectPlanToSap(List<Map<String, Object>> mapList, Integer companyId, String operator) {
+    public static List<SapSyncLog> pushProjectPlanToSap(List<Map<String, Object>> mapList, Integer companyId, String operator,boolean isDev) {
         //根据项目分组 按照项目推送
         //获取当前数据中的所有项目编号
         List<String> projectIds = mapList.stream().map(m -> String.valueOf(m.get("ProjectID"))).distinct().collect(Collectors.toList());
@@ -73,7 +71,6 @@ public class SyncSapUtils {
             zManageProjectTaskWork.setTasks(tasks);
             xmlRequestData.setZManageProjectTaskWork(zManageProjectTaskWork);
             String xml = CommonUtils.convertToXml(xmlRequestData);
-            System.out.println(xml);
             xml=xml.substring(xml.indexOf("<XMLDATA>")+9,xml.lastIndexOf("</XMLDATA>"));
             StringBuffer sb = new StringBuffer();
             sb.append("<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:glob=\"http://sap.com/xi/SAPGlobal20/Global\">\n" +
@@ -84,10 +81,13 @@ public class SyncSapUtils {
             sb.append("      </glob:ZManageProjectTaskWorkCreateRequest_sync>\n" +
                     "   </soapenv:Body>\n" +
                     "</soapenv:Envelope>");
-            System.out.println(sb.toString());
             String result = "";
             try {
-                result = WebServiceUtils.requestByXml("https://my602728.sapbyd.cn/sap/bc/srt/scs/sap/yyatr5vf6y_manageprojecttaskwo?sap-vhost=my602728.sapbyd.cn", sb.toString(), 0, "_BYDHOST", "Welcome1");
+                if(isDev){
+                    result = WebServiceUtils.requestByXml("https://my602728.sapbyd.cn/sap/bc/srt/scs/sap/yyatr5vf6y_manageprojecttaskwo?sap-vhost=my602728.sapbyd.cn", sb.toString(), 0, "_BYDHOST", "Welcome1");
+                }else {
+                    result = WebServiceUtils.requestByXml("https://my601432.sapbyd.cn/sap/bc/srt/scs/sap/yyatr5vf6y_manageprojecttaskwo?sap-vhost=my601432.sapbyd.cn", sb.toString(), 0, "_BYDHOST", "Welcome1");
+                }
             } catch (Exception e) {
                 e.printStackTrace();
             }
@@ -107,6 +107,7 @@ public class SyncSapUtils {
             if(StringUtils.isEmpty(xmlResponseData.getZManageProjectTaskWork())){
                 log.error("推送失败===》项目编号:"+zManageProjectTaskWork.getProjectID());
                 sapSyncLog.setResult("项目编号["+zManageProjectTaskWork.getProjectID()+"]预算工时推送失败");
+                sapSyncLog.setResultRemark(xmlResponseData.getLog()!=null?xmlResponseData.getLog().getItem()!=null?xmlResponseData.getLog().getItem().getNote():"":"");
             }else {
                 sapSyncLog.setResult("项目编号["+zManageProjectTaskWork.getProjectID()+"]预算工时推送成功");
             }
@@ -116,7 +117,7 @@ public class SyncSapUtils {
     }
 
     //推送工时管家填报考勤数据到SAP
-    public static XmlResponseData pushReportToSap(Map<String,Object> map){
+    public static XmlResponseData pushReportToSap(Map<String,Object> map,boolean isDev){
         //配置xml请求参数
         XmlRequestData xmlRequestData=new XmlRequestData();
         EmployeeTime employeeTime=new EmployeeTime();
@@ -139,9 +140,11 @@ public class SyncSapUtils {
             timePeriod.setEndTime(String.valueOf(map.get("EndTime")));
         }
         employeeTime.setDatePeriod(datePeriod);
-        employeeTime.setTimePeriod(timePeriod);
+        if(map.get("StartTime")!=null&&map.get("EndTime")!=null){
+            employeeTime.setTimePeriod(timePeriod);
+        }
         employeeTime.setItemTypeCode("CN0001");
-        employeeTime.setDuration(map.get("Duration")==null?"0":String.valueOf(map.get("Duration")));
+        employeeTime.setDuration("PT"+(map.get("Duration")==null?"0":String.valueOf(map.get("Duration")))+"H");
         if(map.get("ProjectElementID")==null||map.get("ServiceProductInternalID")==null){
             return new XmlResponseData();
         }
@@ -153,7 +156,6 @@ public class SyncSapUtils {
         }
         xmlRequestData.setEmployeeTime(employeeTime);
         String xml = CommonUtils.convertToXml(xmlRequestData);
-        System.out.println(xml);
         xml=xml.substring(xml.indexOf("<XMLDATA>")+9,xml.lastIndexOf("</XMLDATA>"));
         StringBuffer sb = new StringBuffer();
         sb.append("<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:glob=\"http://sap.com/xi/SAPGlobal20/Global\">\n" +
@@ -164,47 +166,66 @@ public class SyncSapUtils {
         sb.append("      </glob:EmployeeTimeAsBundleMaintainRequest_sync>\n" +
                 "   </soapenv:Body>\n" +
                 "</soapenv:Envelope>");
-        System.out.println(sb.toString());
         String result = "";
+        XmlResponseData xmlResponseData = new XmlResponseData();
         try {
-            result = WebServiceUtils.requestByXml("https://my602728.sapbyd.cn/sap/bc/srt/scs/sap/manageemployeetimein?sap-vhost=my602728.sapbyd.cn", sb.toString(), 0, "_BYDHOST", "Welcome1");
+            if(isDev){
+                result = WebServiceUtils.requestByXml("https://my602728.sapbyd.cn/sap/bc/srt/scs/sap/manageemployeetimein?sap-vhost=my602728.sapbyd.cn", sb.toString(), 0, "_BYDHOST", "Welcome1");
+            }else {
+                result = WebServiceUtils.requestByXml("https://my601432.sapbyd.cn/sap/bc/srt/scs/sap/manageemployeetimein?sap-vhost=my601432.sapbyd.cn", sb.toString(), 0, "_BYDHOST", "Welcome1");
+            }
+            if(!StringUtils.isEmpty(result)) {
+                result = result.substring(result.indexOf("<soap-env:Body>")+15, result.lastIndexOf("</soap-env:Body>"));
+                result = result.substring(result.indexOf(">")+1, result.lastIndexOf("</n0:EmployeeTimeAsBundleMaintainConfirmation_sync>"));
+                result="<XMLDATA>"+result+"</XMLDATA>";
+            }
+            System.out.println(result);
+            xmlResponseData = (XmlResponseData) CommonUtils.convertXmlStrToObject(XmlResponseData.class, result);
         } catch (Exception e) {
             e.printStackTrace();
         }
-        if(!StringUtils.isEmpty(result)) {
-            result = result.substring(result.indexOf("<soap-env:Body>")+15, result.lastIndexOf("</soap-env:Body>"));
-            result = result.substring(result.indexOf(">")+1, result.lastIndexOf("</n0:EmployeeTimeAsBundleMaintainConfirmation_sync>"));
-            result="<XMLDATA>"+result+"</XMLDATA>";
-        }
-        System.out.println(result);
-        XmlResponseData xmlResponseData = (XmlResponseData) CommonUtils.convertXmlStrToObject(XmlResponseData.class, result);
+
         return xmlResponseData;
     }
 
 
     //同步SAP项目数据到工时管家
-    public static XmlResponseData syncProjectFromSap(String startDate, String endDate) {
+    public static XmlResponseData syncProjectFromSap(String startDate, String endDate,String projectCodes,boolean isDev) {
         //配置请求xml
         XmlRequestData xmlRequestData=new XmlRequestData();
         ProcessingConditions processingConditions=new ProcessingConditions();
-        processingConditions.setQueryHitsUnlimitedIndicator("true");
-        xmlRequestData.setProcessingConditions(processingConditions);
-        ProjectSelectionByElement projectSelectionByElement=new ProjectSelectionByElement();
-        //todo:根据时间范围
-        SelectionByLastChangeDateTime selectionByLastChangeDateTime=new SelectionByLastChangeDateTime();
-        selectionByLastChangeDateTime.setInclusionExclusionCode("I");
-        selectionByLastChangeDateTime.setIntervalBoundaryTypeCode("3");
-        selectionByLastChangeDateTime.setLowerBoundaryLastChangeDateTime(startDate+"T00:00:00Z");
-        selectionByLastChangeDateTime.setUpperBoundaryLastChangeDateTime(endDate+"T00:00:00Z");
-        projectSelectionByElement.setSelectionByLastChangeDateTime(selectionByLastChangeDateTime);
-        //todo:根据编号
-//        SelectionByProjectID selectionByProjectID=new SelectionByProjectID();
-//        selectionByProjectID.setInclusionExclusionCode("I");
-//        selectionByProjectID.setIntervalBoundaryTypeCode("1");
-//        selectionByProjectID.setLowerBoundaryProjectID("CPSP2250001");
-//        projectSelectionByElement.setSelectionByProjectID(selectionByProjectID);
         List<ProjectSelectionByElement> list=new ArrayList<>();
-        list.add(projectSelectionByElement);
+        if(!StringUtils.isEmpty(startDate)&&!StringUtils.isEmpty(endDate)){
+            processingConditions.setQueryHitsUnlimitedIndicator("true");
+            ProjectSelectionByElement projectSelectionByElement=new ProjectSelectionByElement();
+            //todo:根据时间范围
+            SelectionByLastChangeDateTime selectionByLastChangeDateTime=new SelectionByLastChangeDateTime();
+            selectionByLastChangeDateTime.setInclusionExclusionCode("I");
+            selectionByLastChangeDateTime.setIntervalBoundaryTypeCode("3");
+            selectionByLastChangeDateTime.setLowerBoundaryLastChangeDateTime(startDate+"T00:00:00Z");
+            selectionByLastChangeDateTime.setUpperBoundaryLastChangeDateTime(endDate+"T23:59:59Z");
+            projectSelectionByElement.setSelectionByLastChangeDateTime(selectionByLastChangeDateTime);
+            list.add(projectSelectionByElement);
+        }else if(!StringUtils.isEmpty(projectCodes)){
+            String[] projectCodeArray = projectCodes.split(",");
+            processingConditions.setQueryHitsUnlimitedIndicator("false");
+            processingConditions.setQueryHitsMaximumNumberValue(String.valueOf(projectCodeArray.length));
+            //todo:根据编号
+            ProjectSelectionByElement projectSelectionByElement=new ProjectSelectionByElement();
+            List<SelectionByProjectID> selectionByProjectIDS=new ArrayList<>();
+            for (String projectCode : projectCodeArray) {
+                SelectionByProjectID selectionByProjectID=new SelectionByProjectID();
+                selectionByProjectID.setInclusionExclusionCode("I");
+                selectionByProjectID.setIntervalBoundaryTypeCode("1");
+                selectionByProjectID.setLowerBoundaryProjectID(projectCode);
+                selectionByProjectIDS.add(selectionByProjectID);
+            }
+            projectSelectionByElement.setSelectionByProjectID(selectionByProjectIDS);
+            list.add(projectSelectionByElement);
+        }else {
+            return new XmlResponseData();
+        }
+        xmlRequestData.setProcessingConditions(processingConditions);
         xmlRequestData.setProjectSelectionByElements(list);
         String xml = CommonUtils.convertToXml(xmlRequestData);
         xml=xml.substring(xml.indexOf("<XMLDATA>")+9,xml.lastIndexOf("</XMLDATA>"));
@@ -217,10 +238,13 @@ public class SyncSapUtils {
         sb.append("      </glob:ProjectByElementsQuery>\n" +
                 "   </soapenv:Body>\n" +
                 "</soapenv:Envelope>");
-        System.out.println(sb.toString());
         String result = "";
         try {
-            result = WebServiceUtils.requestByXml("https://my602728.sapbyd.cn/sap/bc/srt/scs/sap/queryprojectin?sap-vhost=my602728.sapbyd.cn", sb.toString(), 0, "_BYDHOST", "Welcome1");
+            if(isDev){
+                result = WebServiceUtils.requestByXml("https://my602728.sapbyd.cn/sap/bc/srt/scs/sap/queryprojectin?sap-vhost=my602728.sapbyd.cn", sb.toString(), 0, "_BYDHOST", "Welcome1");
+            }else {
+                result = WebServiceUtils.requestByXml("https://my601432.sapbyd.cn/sap/bc/srt/scs/sap/queryprojectin?sap-vhost=my601432.sapbyd.cn", sb.toString(), 0, "_BYDHOST", "Welcome1");
+            }
         } catch (Exception e) {
             e.printStackTrace();
         }
@@ -236,7 +260,7 @@ public class SyncSapUtils {
 
 
     //同步SAP项目服务数据到工时管家
-    public static XmlResponseData syncServiceData(String startDate, String endDate, Integer companyId) {
+    public static XmlResponseData syncServiceData(String startDate, String endDate, Integer companyId,boolean isDev) {
         //配置请求xml
         XmlRequestData xmlRequestData=new XmlRequestData();
         ProcessingConditions processingConditions=new ProcessingConditions();
@@ -256,10 +280,13 @@ public class SyncSapUtils {
         sb.append("      </glob:ServiceProductByElementsQuery_sync>\n" +
                 "   </soapenv:Body>\n" +
                 "</soapenv:Envelope>");
-        System.out.println(sb.toString());
         String result = "";
         try {
-            result = WebServiceUtils.requestByXml("https://my602728.sapbyd.cn/sap/bc/srt/scs/sap/queryserviceproductin?sap-vhost=my602728.sapbyd.cn", sb.toString(), 0, "_BYDHOST", "Welcome1");
+            if(isDev){
+                result = WebServiceUtils.requestByXml("https://my602728.sapbyd.cn/sap/bc/srt/scs/sap/queryserviceproductin?sap-vhost=my602728.sapbyd.cn", sb.toString(), 0, "_BYDHOST", "Welcome1");
+            }else {
+                result = WebServiceUtils.requestByXml("https://my601432.sapbyd.cn/sap/bc/srt/scs/sap/queryserviceproductin?sap-vhost=my601432.sapbyd.cn", sb.toString(), 0, "_BYDHOST", "Welcome1");
+            }
         } catch (Exception e) {
             e.printStackTrace();
         }

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

@@ -47,7 +47,8 @@ public class WebServiceUtils {
             outObject.write(sendMsg.getBytes("UTF-8"));
 
             if (200 != (httpConn.getResponseCode())) {
-                throw new Exception("HTTP Request is not success, Response code is " + httpConn.getResponseCode());
+                throw new Exception("HTTP Request is not success, Response code is " + httpConn.getResponseCode()+" Response msg is "+httpConn.getResponseMessage());
+
             }
             // 获取HTTP响应数据
             isr = new InputStreamReader(

+ 37 - 15
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/util/WorkDayCalculateUtils.java

@@ -75,21 +75,6 @@ public class WorkDayCalculateUtils {
         });
         YEAR_DEFINE.put("2022", map2022);
 
-//        HashMap<String, String[]> map2023 = new HashMap<>();
-//        //除了周末的特殊工作日
-//        map2023.put(KEY_SPECIAL_WORK_DAYS, new String[]{"2022-01-29","2022-01-30","2022-04-02","2022-04-24","2022-05-07","2022-10-08","2022-10-09",});
-//        //除了周末的特殊休息日,例如国庆中秋春节
-//        map2023.put(KEY_SPECIAL_REST_DAYS, new String[]{
-//                "2022-01-03",//元旦
-//                "2022-01-31", "2022-02-01", "2022-02-02", "2022-02-03", "2022-02-04",//春节
-//                "2022-04-04","2022-04-05",//清明节
-//                "2022-05-02","2022-05-03","2022-05-04",//劳动节
-//                "2022-06-03",//端午节
-//                "2022-09-20","2022-09-21",//中秋节
-//                "2022-10-01", "2022-10-02","2022-10-03","2022-10-04","2022-10-05","2022-10-06","2022-10-07",//国庆节
-//        });
-//        YEAR_DEFINE.put("2023", map2023);
-
         HashMap<String, String[]> map2023 = new HashMap<>();
         //除了周末的特殊工作日
         map2023.put(KEY_SPECIAL_WORK_DAYS, new String[]{"2023-01-28","2023-01-29","2023-04-23","2023-05-06","2023-06-25","2023-10-07","2023-10-08",});
@@ -104,6 +89,26 @@ public class WorkDayCalculateUtils {
         });
         YEAR_DEFINE.put("2023", map2023);
 
+        HashMap<String, String[]> map2024 = new HashMap<>();
+        //除了周末的特殊工作日
+        map2024.put(KEY_SPECIAL_WORK_DAYS, new String[]{"2024-02-04",//春节
+                "2024-02-18",//春节
+                "2024-04-07",//清明节
+                "2024-04-28","2024-05-11",//劳动节
+                "2024-09-14",//中秋节
+                "2024-09-29","2024-10-12",//国庆节
+                });
+        //除了周末的特殊休息日,例如国庆中秋春节
+        map2024.put(KEY_SPECIAL_REST_DAYS, new String[]{
+                "2024-01-01",//元旦
+                "2024-02-12", "2024-02-13", "2024-02-14", "2024-02-15", "2024-02-16",//春节
+                "2024-04-04","2024-04-05",//清明节
+                "2024-05-01","2024-05-02","2024-05-03",//劳动节
+                "2024-06-10",//端午节
+                "2024-09-16","2024-09-17",//中秋节
+                "2024-10-01","2024-10-02","2024-10-03","2024-10-04","2024-10-07",//国庆节
+        });
+        YEAR_DEFINE.put("2024", map2024);
     }
 
     /**
@@ -316,4 +321,21 @@ public class WorkDayCalculateUtils {
 //        System.out.println(sameWeek(date1, date2));
 //        System.out.println(sameMonth(date1, date2));
     }
+
+    public static List<String> getAllHolidays(String firstDay, String endDate) {
+        List<String> dateList = new ArrayList<>();
+        LocalDate localStartDate = LocalDate.parse(firstDay, dateTimeFormatter);
+        LocalDate localEndDate = LocalDate.parse(endDate, dateTimeFormatter);
+        while(true) {
+            localStartDate = localStartDate.plusDays(1);
+            if (!isWorkDay(localStartDate)) {
+                dateList.add(localStartDate.format(dateTimeFormatter));
+            }
+            //到达结束日期,结束计算
+            if (localStartDate.isEqual(localEndDate)) {
+                break;
+            }
+        }
+        return dateList;
+    }
 }

+ 6 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/webservice/po/ProcessingConditions.java

@@ -9,12 +9,18 @@ public class ProcessingConditions {
 
     private String queryHitsUnlimitedIndicator;
     private String returnedQueryHitsNumberValue;
+    private String queryHitsMaximumNumberValue;
 
     @XmlElement(name = "QueryHitsUnlimitedIndicator")
     public String getQueryHitsUnlimitedIndicator() {
         return queryHitsUnlimitedIndicator;
     }
 
+    @XmlElement(name = "QueryHitsMaximumNumberValue")
+    public String getQueryHitsMaximumNumberValue(){
+        return queryHitsMaximumNumberValue;
+    }
+
     //返回的项目条数
     @XmlElement(name = "ReturnedQueryHitsNumberValue")
     public String getReturnedQueryHitsNumberValue() {

+ 4 - 2
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/webservice/po/ProjectSelectionByElement.java

@@ -3,12 +3,14 @@ package com.management.platform.webservice.po;
 import lombok.Data;
 
 import javax.xml.bind.annotation.XmlElement;
+import java.util.List;
 
 @Data
 public class ProjectSelectionByElement {
 
     private SelectionByLastChangeDateTime selectionByLastChangeDateTime;
-    private SelectionByProjectID selectionByProjectID;
+//    private SelectionByProjectID selectionByProjectID;
+    private List<SelectionByProjectID> selectionByProjectID;
 
     @XmlElement(name = "SelectionByLastChangeDateTime")
     public SelectionByLastChangeDateTime getSelectionByLastChangeDateTime() {
@@ -16,7 +18,7 @@ public class ProjectSelectionByElement {
     }
 
     @XmlElement(name = "SelectionByProjectID")
-    public SelectionByProjectID getSelectionByProjectID() {
+    public List<SelectionByProjectID> getSelectionByProjectIDs() {
         return selectionByProjectID;
     }
 }

+ 17 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/webservice/po/Sales.java

@@ -0,0 +1,17 @@
+package com.management.platform.webservice.po;
+
+import lombok.Data;
+
+import javax.xml.bind.annotation.XmlElement;
+
+@Data
+public class Sales {
+
+    private String lifeCycleStatusCode;
+
+
+    @XmlElement(name = "LifeCycleStatusCode")
+    public String getLifeCycleStatusCode() {
+        return lifeCycleStatusCode;
+    }
+}

+ 6 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/webservice/po/ServiceProduct.java

@@ -12,6 +12,7 @@ public class ServiceProduct {
     private String productCategoryID;
     private Description description;
     private String baseMeasureUnitCode;
+    private Sales sales;
 
     @XmlElement(name = "ChangeStateID")
     public String getChangeStateID() {
@@ -37,4 +38,9 @@ public class ServiceProduct {
     public String getBaseMeasureUnitCode() {
         return baseMeasureUnitCode;
     }
+
+    @XmlElement(name = "Sales")
+    public Sales getSales() {
+        return sales;
+    }
 }

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

@@ -146,7 +146,7 @@ referer:
     - mldmobworktime.ttkuaiban.com
     - mldworktime.ttkuaiban.com
     - 47.101.180.183
-excludeUrls: /wxcorp/*,/wxcorp/*/*,/dingding/*,/feishu-info/*,/error,/testClient,/corpWXAuth,/corpWXScanningAuth,/corpInsideWXAuth,/wx-corp-info/*,/clean/*,/innerRoles/*,/project/getProjectListByToken,/project/getTimeCostByToken,/report/getReportListByToken,/report/getProcessErrorData,/project/synchronizationProject,/user/updateUserDeptHierarchy
+excludeUrls: /wxcorp/*,/wxcorp/*/*,/dingding/*,/feishu-info/*,/error,/testClient,/corpWXAuth,/corpWXScanningAuth,/corpInsideWXAuth,/wx-corp-info/*,/clean/*,/innerRoles/*,/project/getProjectListByToken,/project/getTimeCostByToken,/report/getReportListByToken,/report/getProcessErrorData,/project/synchronizationProject,/user/updateUserDeptHierarchy,/report/getUserTimeCostByThird,/report/getProjectTimeCostByThird
 
 #企业微信相关参数
 suitId: ww4e237fd6abb635af

+ 18 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/CategoryRatioTblSettingMapper.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.CategoryRatioTblSettingMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.management.platform.entity.CategoryRatioTblSetting">
+        <id column="company_id" property="companyId" />
+        <result column="monitor_category_id" property="monitorCategoryId" />
+        <result column="ratio" property="ratio" />
+        <result column="more_or_less" property="moreOrLess" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        company_id, monitor_category_id, ratio, more_or_less
+    </sql>
+
+</mapper>

+ 2 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/CompanyMapper.xml

@@ -23,11 +23,12 @@
         <result column="is_international" property="isInternational" />
         <result column="create_date" property="createDate" />
         <result column="reg_from" property="regFrom" />
+        <result column="non_project_simple" property="nonProjectSimple" />
     </resultMap>
 
     <!-- 通用查询结果列 -->
     <sql id="Base_Column_List">
-        id, company_name, staff_count_max, expiration_date, set_meal, package_worktime, package_project, package_contract, package_oa, package_etimecard, package_expense, package_customer, package_engineering, package_simple, package_finance, package_provider, is_international, create_date, reg_from
+        id, company_name, staff_count_max, expiration_date, set_meal, package_worktime, package_project, package_contract, package_oa, package_etimecard, package_expense, package_customer, package_engineering, package_simple, package_finance, package_provider, is_international, create_date, reg_from, non_project_simple
     </sql>
 
 </mapper>

+ 2 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/DepartmentMapper.xml

@@ -40,11 +40,12 @@
 
     <!--根据人员获取成本-->
     <select id="getCostByUser" resultType="java.util.Map">
-        SELECT a.id as id, a.name AS user,a.corpwx_userid as corpwxUserId, a.job_number as jobNumber, c.project_name AS project, SUM(b.working_time) AS time, SUM(b.cost) AS
+        SELECT a.id as id, a.name AS user,a.corpwx_userid as corpwxUserId, a.job_number as jobNumber, c.project_name AS project,c.project_code as projectCode, c.project_main_id as projectMainId, project_main.code as mainProjectCode, project_main.name as mainProjectName, ifnull(SUM(b.working_time),0) AS time, ifnull(SUM(b.cost),0) AS
         money
         FROM user AS a
         LEFT JOIN report AS b ON a.id = b.creator_id
         LEFT JOIN project AS c ON b.project_id = c.id
+        left join project_main on project_main.id = c.project_main_id
         WHERE b.state = 1
         <if test="departmentIds != null and departmentIds.size()>0">
             AND b.dept_id IN

+ 7 - 4
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/ExpenseItemMapper.xml

@@ -34,6 +34,8 @@
         <result column="status" property="status" />
         <result column="username" property="username" />
         <result column="department_name" property="departmentName" />
+        <result column="corpwxUserId" property="corpwxUserId" />
+        <result column="corpwxDeptId" property="corpwxDeptId" />
     </resultMap>
     <!-- 通用查询结果列 -->
     <sql id="Base_Column_List">
@@ -41,10 +43,11 @@
     </sql>
     <select id="getUserExpenseDetail" resultMap="UserBaseResultMap">
         select a.id, a.expense_id, a.project_id, a.happen_date, a.invoice_type, a.tax_percent, a.tax_value, a.amount, a.remark, a.expense_type, a.pic,a.status,
-               user.name as username, department.department_name
-        from expense_item a left join expense_sheet b on a.expense_id = b.id
-                            left join user on user.id = b.owner_id
-                            left join department on department.department_id = user.department_id
+        user.name as username,user.corpwx_userid as corpwxUserId, department.department_name,department.corpwx_deptid as corpwxDeptId
+        from expense_item a
+        left join expense_sheet b on a.expense_id = b.id
+        left join user on user.id = b.owner_id
+        left join department on department.department_id = user.department_id
         where a.project_id = #{projectId} order by a.happen_date desc
     </select>
 

+ 17 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/ExpensePayWayMapper.xml

@@ -0,0 +1,17 @@
+<?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.ExpensePayWayMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.management.platform.entity.ExpensePayWay">
+        <id column="id" property="id" />
+        <result column="company_id" property="companyId" />
+        <result column="name" property="name" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, company_id, name
+    </sql>
+
+</mapper>

+ 3 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/ExpenseSheetMapper.xml

@@ -21,11 +21,13 @@
         <result column="first_checker_id" property="firstCheckerId" />
         <result column="second_checker_id" property="secondCheckerId" />
         <result column="review_process" property="reviewProcess" />
+        <result column="pay_way_id" property="payWayId" />
+        <result column="pay_way_name" property="payWayName" />
     </resultMap>
 
     <!-- 通用查询结果列 -->
     <sql id="Base_Column_List">
-        id, code, company_id, owner_id, owner_name, create_date, ticket_num, type, status, remark, total_amount, operator_id, deny_reason, send_state, first_checker_id, second_checker_id, review_process
+        id, code, company_id, owner_id, owner_name, create_date, ticket_num, type, status, remark, total_amount, operator_id, deny_reason, send_state, first_checker_id, second_checker_id, review_process, pay_way_id, pay_way_name
     </sql>
 
 </mapper>

+ 28 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/GroupBudgetReviewMapper.xml

@@ -0,0 +1,28 @@
+<?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.GroupBudgetReviewMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.management.platform.entity.GroupBudgetReview">
+        <id column="id" property="id" />
+        <result column="group_id" property="groupId" />
+        <result column="old_man_day" property="oldManDay" />
+        <result column="change_man_day" property="changeManDay" />
+        <result column="now_man_day" property="nowManDay" />
+        <result column="status" property="status" />
+        <result column="create_time" property="createTime" />
+        <result column="company_id" property="companyId" />
+        <result column="creator_id" property="creatorId" />
+        <result column="group_name" property="groupName" />
+        <result column="creator" property="creator" />
+        <result column="project_id" property="projectId" />
+        <result column="project_name" property="projectName" />
+        <result column="remark" property="remark" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, group_id, old_man_day, change_man_day, now_man_day, status, create_time, company_id, creator_id, group_name, creator, project_id, project_name, remark
+    </sql>
+
+</mapper>

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

@@ -145,7 +145,7 @@
     </select>
     <!--获取查询者所在公司每个项目的工时成本-->
     <select id="getTimeCost" resultType="java.util.Map">
-        SELECT a.id, a.project_code as projectCode, a.project_name AS project, SUM(b.working_time) AS cost, SUM(b.cost) AS costMoney,a.category_name as categoryName
+        SELECT a.id, a.project_main_id as projectMainId, a.project_code as projectCode, a.project_name AS project, SUM(b.working_time) AS cost, SUM(b.cost) AS costMoney,a.category_name as categoryName
         FROM project AS a
         LEFT JOIN report AS b ON b.project_id = a.id
         JOIN user AS c ON b.creator_id = c.id
@@ -153,6 +153,9 @@
         <if test="projectId != null">
             AND a.id = #{projectId}
         </if>
+        <if test="categoryId != null">
+            AND a.category = #{categoryId}
+        </if>
         <if test="projectIds != null">
             and a.id in
             <foreach collection="projectIds" open="(" close=")" separator="," item="item">
@@ -260,7 +263,7 @@
 
     <!--获取查询者所在公司每个项目的工时成本-->
     <select id="getTimeCostByMainProject" resultType="java.util.Map">
-        SELECT SUM(b.working_time) AS cost, SUM(b.cost) AS costMoney,a.category_name as categoryName,IFNULL(pm.name,'未分类') as mainProjectName
+        SELECT SUM(b.working_time) AS cost, SUM(b.cost) AS costMoney,a.category_name as categoryName,IFNULL(pm.name,'无主项目') as mainProjectName
         FROM project AS a
         LEFT JOIN report AS b ON b.project_id = a.id
         JOIN user AS c ON b.creator_id = c.id
@@ -1734,13 +1737,13 @@
             and u.plate1 = #{area}
         </if>
         <if test="branchDepartment!=null and branchDepartment.size()>0">
-            and us.department_id in
+            and u.department_id in
             <foreach collection="branchDepartment" open="(" close=")" separator="," item="item">
                 #{item}
             </foreach>
         </if>
         <if test="deptIds!=null and deptIds.size()>0">
-            and us.department_id in
+            and u.department_id in
             <foreach collection="deptIds" open="(" item="item" close=")" separator=",">
                 #{item}
             </foreach>
@@ -1765,4 +1768,14 @@
         GROUP BY a.id,b.creator_id
         ORDER BY a.id ASC
     </select>
+    <!--获取员工的项目分类工时统计数据 -->
+    <select id="getMembProjectCateTime" resultType="com.management.platform.entity.vo.UserCateTimeVo">
+        SELECT user.id AS userId, user.`name`, project.`category`, project.`category_name` AS categoryName, SUM(report.`working_time`) AS workingTime FROM report LEFT JOIN `user` ON user.id = report.`creator_id`
+        LEFT JOIN project ON project.id = report.`project_id`
+        WHERE report.`company_id` = #{companyId}
+        AND report.`create_date` BETWEEN #{startDate} and #{endDate}
+        AND report.state = 1
+        GROUP BY user.id, project.`category`
+    </select>
+
 </mapper>

+ 61 - 5
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/ReportMapper.xml

@@ -69,6 +69,7 @@
         , reject_reason as rejectReason, reject_username as rejectUsername, reject_userid as rejectUserid, degree_id as degree_id,report_extra_degree.name as degreeName,task_group.name as groupName,a.group_id as groupId,a.custom_data as customData
         ,u.name as projectAuditorName,u.corpwx_userid as projectAuditorCorpwxUserId, a.project_auditor_id as projectAuditorId, department.department_name as departmentName,dp2.department_name as buDepartmentName,department.department_id as departmentId, a.overtime_hours as overtimeHours, a.custom_text as customText,a.project_audit_time  as projectAuditTime,project_main.name as projectMainName,
         a.extra_field1 as extraField1,a.extra_field2 as extraField2,a.extra_field3 as extraField3, a.batch_id as batchId,a.sap_service_id as sapServiceId,b.status as projectStatus,DATE_FORMAT(b.finish_date,'%Y-%m-%d') as finishDate,ps.project_category_sub as projectCategorySub
+        ,u2.name as projectManagerName,u2.corpwx_userid as projectManagerCorpwxUserId
         FROM report AS a
         JOIN project AS b ON a.project_id=b.id
         LEFT JOIN project_separate AS ps on b.id=ps.id
@@ -78,6 +79,7 @@
         left join report_extra_degree on report_extra_degree.id = a.degree_id
         left join task_group on task_group.id = a.group_id
         left join user u on u.id = a.project_auditor_id
+        left join user u2 on u2.id = b.incharger_id
         left join department on department.department_id = c.department_id
         left join department dp2 on dp2.department_id = b.bu_id
         left join project_main on b.project_main_id=project_main.id
@@ -123,6 +125,7 @@
         , reject_reason as rejectReason, reject_username as rejectUsername, reject_userid as rejectUserid, degree_id as degree_id,report_extra_degree.name as degreeName,task_group.name as groupName,a.group_id as groupId,a.custom_data as customData
         ,u.name as projectAuditorName,u.corpwx_userid as projectAuditorCorpwxUserId, a.project_auditor_id as projectAuditorId, department.department_name as departmentName,dp2.department_name as buDepartmentName,department.department_id as departmentId, a.overtime_hours as overtimeHours, a.custom_text as customText,a.project_audit_time  as projectAuditTime,project_main.name as projectMainName,
         GROUP_CONCAT(rlog.operator_id,'@', rlog.operate_date,'@', rlog.msg SEPARATOR '❤') AS logMsg,a.extra_field1 as extraField1,a.extra_field2 as extraField2,a.extra_field3 as extraField3,b.status as projectStatus,DATE_FORMAT(b.finish_date,'%Y-%m-%d') as finishDate,ps.project_category_sub as projectCategorySub
+        ,u2.name as projectManagerName,u2.corpwx_userid as projectManagerCorpwxUserId
         FROM report AS a
         JOIN project AS b ON a.project_id=b.id
         LEFT JOIN project_separate AS ps on b.id=ps.id
@@ -132,6 +135,7 @@
         left join report_extra_degree on report_extra_degree.id = a.degree_id
         left join task_group on task_group.id = a.group_id
         left join user u on u.id = a.project_auditor_id
+        left join user u2 on u2.id = b.incharger_id
         left join department on department.department_id = c.department_id
         left join department dp2 on dp2.department_id = b.bu_id
         left join project_main on b.project_main_id=project_main.id
@@ -204,6 +208,7 @@
         departmentName,dp2.department_name as buDepartmentName,department.department_id as departmentId, a.overtime_hours as overtimeHours, a.custom_text as customText, a.project_audit_time as
         projectAuditTime,project_main.name as projectMainName,a.extra_field1 as extraField1,a.extra_field2 as extraField2,a.extra_field3 as extraField3, a.batch_id as batchId,a.sap_service_id as sapServiceId,b.status as projectStatus,
         DATE_FORMAT(b.finish_date,'%Y-%m-%d') as finishDate,ps.project_category_sub as projectCategorySub
+        ,u2.name as projectManagerName,u2.corpwx_userid as projectManagerCorpwxUserId
         FROM report AS a
         JOIN project AS b ON a.project_id=b.id
         LEFT JOIN project_separate AS ps on b.id=ps.id
@@ -213,6 +218,7 @@
         left join report_extra_degree on report_extra_degree.id = a.degree_id
         left join task_group on task_group.id = a.group_id
         left join user u on u.id = a.project_auditor_id
+        left join user u2 on u2.id = b.incharger_id
         left join department on department.department_id = c.department_id
         left join department dp2 on dp2.department_id = b.bu_id
         left join project_main on project_main.id=b.project_main_id
@@ -270,6 +276,7 @@
         departmentName,dp2.department_name as buDepartmentName,department.department_id as departmentId, a.overtime_hours as overtimeHours, a.custom_text as customText, a.project_audit_time as
         projectAuditTime,project_main.name as projectMainName,b.status as projectStatus,DATE_FORMAT(b.finish_date,'%Y-%m-%d') as finishDate,ps.project_category_sub as projectCategorySub,
         GROUP_CONCAT(rlog.operator_id,'@', rlog.operate_date,'@', rlog.msg SEPARATOR '❤') AS logMsg,a.extra_field1 as extraField1,a.extra_field2 as extraField2,a.extra_field3 as extraField3
+        ,u2.name as projectManagerName,u2.corpwx_userid as projectManagerCorpwxUserId
         FROM report AS a
         JOIN project AS b ON a.project_id=b.id
         LEFT JOIN project_separate AS ps on b.id=ps.id
@@ -279,6 +286,7 @@
         left join report_extra_degree on report_extra_degree.id = a.degree_id
         left join task_group on task_group.id = a.group_id
         left join user u on u.id = a.project_auditor_id
+        left join user u2 on u2.id = b.incharger_id
         left join department on department.department_id = c.department_id
         left join department dp2 on dp2.department_id = b.bu_id
         left join project_main on project_main.id=b.project_main_id
@@ -331,6 +339,7 @@
         , reject_reason as rejectReason, reject_username as rejectUsername, reject_userid as rejectUserid, degree_id as degree_id,report_extra_degree.name as degreeName,task_group.name as groupName,a.group_id as groupId, a.custom_data as customData
         ,u.name as projectAuditorName,u.corpwx_userid as projectAuditorCorpwxUserId, a.project_auditor_id as projectAuditorId, department.department_name as departmentName,dp2.department_name as buDepartmentName,department.department_id as departmentId, a.overtime_hours as overtimeHours, a.custom_text as customText, a.project_audit_time as projectAuditTime,project_main.name as projectMainName
         ,a.extra_field1 as extraField1,a.extra_field2 as extraField2,a.extra_field3 as extraField3, a.batch_id as batchId,a.sap_service_id as sapServiceId,b.status as projectStatus,DATE_FORMAT(b.finish_date,'%Y-%m-%d') as finishDate,ps.project_category_sub as projectCategorySub
+        ,u2.name as projectManagerName,u2.corpwx_userid as projectManagerCorpwxUserId
         FROM report AS a
         JOIN project AS b ON a.project_id=b.id
         LEFT JOIN project_separate AS ps on b.id=ps.id
@@ -340,6 +349,7 @@
         left join report_extra_degree on report_extra_degree.id = a.degree_id
         left join task_group on task_group.id = a.group_id
         left join user u on u.id = a.project_auditor_id
+        left join user u2 on u2.id = b.incharger_id
         left join department on department.department_id = c.department_id
         left join department dp2 on dp2.department_id = b.bu_id
         left join project_main on project_main.id=b.project_main_id
@@ -869,6 +879,9 @@
     </select>
     <select id="getMyOvertime"  resultType="java.lang.Double">
         select IFNULL(sum(overtime_hours),0) from report where creator_id=#{userId}
+        <if test="startDate != null">
+        and create_date &gt;= #{startDate}
+        </if>
     </select>
     <select id="getProWaitingApproveCnt" resultType="java.util.HashMap">
         select count(1) as num, user.dingding_userid as auditorDDId ,user.corpwx_userid as corpwxUserid from report
@@ -958,7 +971,7 @@
     <select id="getPushProjectReportToSap" resultType="java.util.Map">
         select r.id as ReportId, u.job_number as EmployeeID,r.create_date as StartDate,r.create_date as EndDate,r.start_time as StartTime,r.end_time as EndTime,
         r.working_time as Duration,t.sap_task_code as ProjectElementID,
-        sps.service_code as ServiceProductInternalID,r.content as WorkDescriptionText
+        sps.service_code as ServiceProductInternalID,r.content as WorkDescriptionText,p.id as ProjectId
         from report r
         left join user u on u.id=r.creator_id
         left join department d on u.department_id=d.department_id
@@ -1009,9 +1022,14 @@
         left join user u on te.executor_id=u.id
         where t.company_id=#{companyId}
         and t.start_date is not null
+        and t.end_date is not null
         and t.plan_hours is not null
         and te.service_id is not null
         and u.job_number is not null
+        and p.id in
+        <foreach collection="list" open="(" separator="," close=")" item="item">
+            #{item}
+        </foreach>
         <if test="startDate!=null and startDate!='' and endDate!=null and endDate!=''">
             and t.create_date between #{startDate} and #{endDate}
         </if>
@@ -1037,9 +1055,9 @@
         ps.contract_code as contractCode,ps.project_category_sub as projectCategorySub,ps.region,DATE_FORMAT(p.create_date,'%Y-%m-%d') as createDate,DATE_FORMAT(ps.warranty_start_date,'%Y-%m-%d') as warrantyStartDate,
         DATE_FORMAT(ps.warranty_end_date,'%Y-%m-%d') as warrantyEndDate,DATE_FORMAT(p.finish_date,'%Y-%m-%d') as finishDate,ps.bu,IFNULL(p.man_day*8,0) as planTime,IFNULL(SUM(r.working_time),0) as realityTime,
         case  when p.man_day*8-SUM(r.working_time) &gt;= 0 then '否' else '是' end as isOver ,case when p.man_day*8-SUM(r.working_time) &gt; 0 then (p.man_day*8-SUM(r.working_time)) else '0' end as remaining,
-        CONCAT('[',(select GROUP_CONCAT(CONCAT(u.job_number,'/',u.name)) from participation pa
+        (select GROUP_CONCAT(CONCAT(u.job_number,'/',u.name)) from participation pa
         left join user u on pa.user_id=u.id
-        where pa.project_id=p.id ),']') as participations
+        where pa.project_id=p.id ) as participations
         from project p
         left join project_main pm on p.project_main_id=pm.id
         left join project_level pl on p.level=pl.id
@@ -1070,9 +1088,9 @@
     <select id="getTaskGroupPlanTime" resultType="java.util.Map">
         select tg.project_id as projectId,tg.task_group_code as taskGroupCode,tg.name,tg.wbs_code as wbsCode,IFNULL(tg.man_day*8,0) as planTime,tg.id as groupId,
         CONCAT(uu.job_number,'/',uu.name) as incahrgerName,
-        CONCAT('[',(select GROUP_CONCAT(CONCAT(u.job_number,'/',u.name)) from group_participator gp
+        (select GROUP_CONCAT(CONCAT(u.job_number,'/',u.name)) from group_participator gp
         left join user u on gp.user_id=u.id
-        where gp.group_id=tg.id ),']') as participations
+        where gp.group_id=tg.id ) as participations
         from task_group tg
         left join user uu on uu.id=tg.incharger_id
         <where>
@@ -1082,4 +1100,42 @@
             </foreach>
         </where>
     </select>
+
+    <select id="getUserWorkTimeByCategory" resultType="java.util.Map">
+        select p.id as projectId, p.project_code as projectCode,date_format(r.create_date,'%Y-%m-%d') as createDate,u.id as userId,u.name as userName,u.corpwx_userid as corpWxUserId,d.department_name as deptName,d.department_id as deptId
+        ,d.corpwx_deptid as corpWxDeptId,u.plate1,u.plate2,u.plate3,u.plate4,u.plate5,SUM(r.working_time) as workingTime
+        <if test="startDate!=null and startDate!='' and endDate!=null and endDate!=''">
+            ,IFNULL((select SUM(working_time) from report where company_id=#{companyId} and create_date between  #{startDate} and #{endDate} and creator_id=u.id),0) as allWorkingTime
+            ,IFNULL((select SUM(working_time) from report where company_id=#{companyId} and create_date between  #{startDate} and #{endDate} and creator_id=u.id and project_id =p.id),0) as targetWorkingTime
+        </if>
+        from
+        report r
+        left join project p on r.project_id=p.id
+        left join project_category pc on pc.id=p.category
+        left join user u on u.id=r.creator_id
+        left join department d on d.department_id=u.department_id
+        where r.company_id=#{companyId}
+        <if test="startDate!=null and startDate!='' and endDate!=null and endDate!=''">
+            and r.create_date between #{startDate} and #{endDate}
+        </if>
+        <if test="categoryId!=null">
+            and pc.id=#{categoryId}
+        </if>
+        <if test="categoryId==null">
+            and p.category is null
+        </if>
+        <if test="list!=null and list.size()>0">
+            and d.department_id in
+            <foreach collection="list" open="(" close=")" item="item" separator=",">
+                #{item}
+            </foreach>
+        </if>
+        <if test="deptId!=null">
+            and d.department_id=#{deptId}
+        </if>
+        <if test="userId!=null and userId!=''">
+            and u.id=#{userId}
+        </if>
+        group by p.id,r.create_date,u.id
+    </select>
 </mapper>

+ 2 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/SapProjectServiceMapper.xml

@@ -8,11 +8,12 @@
         <result column="service_code" property="serviceCode" />
         <result column="service_name" property="serviceName" />
         <result column="company_id" property="companyId" />
+        <result column="status" property="status" />
     </resultMap>
 
     <!-- 通用查询结果列 -->
     <sql id="Base_Column_List">
-        id, service_code, service_name, company_id
+        id, service_code, service_name, company_id, status
     </sql>
 
 </mapper>

+ 7 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/TaskMapper.xml

@@ -168,7 +168,7 @@
     </select>
 
     <select id="getProjectTask" resultType="java.util.Map">
-        SELECT task.id, task.`name`,task.executor_name,task.executor_id,DATE_FORMAT(task.`end_date`, '%Y-%m-%d') as end_date, task.`plan_hours`,
+        SELECT task.id,tg.id as groupId, task.`name`,task.executor_name,task.executor_id,DATE_FORMAT(task.`end_date`, '%Y-%m-%d') as end_date, task.`plan_hours`,
         (SELECT IFNULL(SUM(working_time),0) FROM report WHERE report.`task_id` = task.id AND report.`state` = 1) AS real_hours,
         task.`task_status`, task.`task_type`,
         project.`project_code`, project.`project_name`,tg.name as groupName
@@ -179,6 +179,9 @@
         <if test="projectId != null">
             and task.project_id = #{projectId}
         </if>
+        <if test="groupId != null">
+            and task.group_id = #{groupId}
+        </if>
         <if test="taskType!=null">
             and task.task_type=#{taskType}
         </if>
@@ -199,6 +202,9 @@
         <if test="projectId != null">
             and task.project_id = #{projectId}
         </if>
+        <if test="groupId != null">
+            and task.group_id = #{groupId}
+        </if>
         <if test="taskType!=null">
             and task.task_type=#{taskType}
         </if>

+ 20 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/UserWithBeisenMapper.xml

@@ -0,0 +1,20 @@
+<?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.UserWithBeisenMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.management.platform.entity.UserWithBeisen">
+        <id column="id" property="id" />
+        <result column="user_id" property="userId" />
+        <result column="name" property="name" />
+        <result column="mobile_phone" property="mobilePhone" />
+        <result column="job_number" property="jobNumber" />
+        <result column="company_id" property="companyId" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, user_id, name, mobile_phone, job_number, company_id
+    </sql>
+
+</mapper>

+ 28 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/controller/ReportController.java

@@ -143,6 +143,14 @@ public class ReportController {
         msg.data = reportService.getById(id);
         return msg;
     }
+
+    @RequestMapping("/fixSteelNumData")
+    public HttpRespMsg fixSteelNumData() {
+        HttpRespMsg msg = new HttpRespMsg();
+        //修复report表中钢印号存在重复问题
+        msg.data = reportService.fixSteelNumData();
+        return msg;
+    }
 //
 //    @RequestMapping("/getCardTime")
 //    public HttpRespMsg getCardTime(@RequestParam String date) {
@@ -1606,5 +1614,25 @@ public class ReportController {
     public HttpRespMsg exportProductionQuantity(Integer productId,String startDate,String endDate){
         return reportService.exportProductionQuantity(productId,startDate,endDate);
     }
+
+    @RequestMapping("/getPlanDataWithStation")
+    public HttpRespMsg getPlanDataWithStation(@RequestParam(defaultValue = "0") Integer isFilterDept,Integer filterDeptId,Integer stationId,String startDate,String endDate,Integer pageIndex,Integer pageSize){
+        return reportService.getPlanDataWithStation(isFilterDept,filterDeptId,stationId,startDate,endDate,pageIndex,pageSize);
+    }
+
+    @RequestMapping("/exportPlanDataWithStation")
+    public HttpRespMsg exportPlanDataWithStation(@RequestParam(defaultValue = "0") Integer isFilterDept,Integer filterDeptId,Integer stationId,String startDate,String endDate){
+        return reportService.exportPlanDataWithStation(isFilterDept,filterDeptId,stationId,startDate,endDate);
+    }
+    
+    @RequestMapping("/getPlanDataWithUserId")
+    public HttpRespMsg getPlanDataWithUserId(String userId,String startDate,String endDate){
+        return reportService.getPlanDataWithUserId(userId,startDate,endDate);
+    }
+
+    @RequestMapping("/getUserCommentPlanResult")
+    public HttpRespMsg getUserCommentPlanResult(String pptIds){
+        return reportService.getUserCommentPlanResult(pptIds);
+    }
 }
 

+ 7 - 1
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/entity/Plan.java

@@ -22,7 +22,7 @@ import org.springframework.format.annotation.DateTimeFormat;
  * </p>
  *
  * @author Seyason
- * @since 2023-11-27
+ * @since 2024-01-11
  */
 @Data
 @EqualsAndHashCode(callSuper = false)
@@ -247,6 +247,12 @@ public class Plan extends Model<Plan> {
     @TableField("is_delete")
     private Integer isDelete;
 
+    /**
+     * 实际完工日期
+     */
+    @TableField("real_end_date")
+    private LocalDate realEndDate;
+
     @TableField(exist = false)
     private String  steelStampNumber;
 

+ 6 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/mapper/ReportMapper.java

@@ -203,4 +203,10 @@ public interface ReportMapper extends BaseMapper<Report> {
     Integer getDpetStatisticsProgressCount(Integer companyId, String deptId, String foremanId, String userId, String startDate, String endDate);
 
     List<Map<String,Object>> getReportList(String startDate, String endDate, Integer planId, Integer stateKey, Integer departmentId, Integer companyId);
+
+    List<Map<String,Object>> getPlanDataWithStation(Integer companyId, String startDate, String endDate, String foremanId, Integer pageStart, Integer pageSize);
+
+    List<Map<String, Object>> getPlanDataWithUser(Integer companyId, String startDate, String endDate, Integer filterDeptId);
+
+    List<Map<String, Object>> getPlanDataWithUserId(Integer companyId,String userId, String startDate, String endDate);
 }

+ 10 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/ReportService.java

@@ -146,4 +146,14 @@ public interface ReportService extends IService<Report> {
     HttpRespMsg productionQuantityList(Integer productId, String startDate, String endDate,Integer pageIndex, Integer pageSize);
 
     HttpRespMsg exportProductionQuantity(Integer productId, String startDate, String endDate);
+
+ 	Object fixSteelNumData();
+
+ 	HttpRespMsg getPlanDataWithStation(Integer isFilterDept,Integer filterDeptId,Integer stationId, String startDate, String endDate, Integer pageIndex, Integer pageSize);
+
+    HttpRespMsg exportPlanDataWithStation(Integer isFilterDept, Integer filterDeptId, Integer stationId, String startDate, String endDate);
+
+    HttpRespMsg getPlanDataWithUserId(String userId, String startDate, String endDate);
+
+    HttpRespMsg getUserCommentPlanResult(String pptIds);
 }

+ 4 - 0
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/impl/PlanProcedureTotalServiceImpl.java

@@ -112,6 +112,7 @@ public class PlanProcedureTotalServiceImpl extends ServiceImpl<PlanProcedureTota
         HttpRespMsg msg = new HttpRespMsg();
         String token = request.getHeader("TOKEN");
         HashMap prodProcedureTeam = prodProcedureTeamMapper.getFillProcedureDetail(id);
+        prodProcedureTeam.remove("steel_num_array");
         //道工序是否自己已经填过了,有的话取数据
         Report oldReport = reportMapper.selectOne(new QueryWrapper<Report>().eq("user_procedure_team_id", id).eq("creator_id", token).eq("create_date", createDate));
         if (oldReport != null) {
@@ -185,9 +186,12 @@ public class PlanProcedureTotalServiceImpl extends ServiceImpl<PlanProcedureTota
             List<Report> reportList = reportMapper.selectList(
                     new QueryWrapper<Report>().select("id", "steel_num_array","create_date", "creator_id")
                             .eq("plan_id", planId).eq("prod_procedure_id", (Integer)prodProcedureTeam.get("prod_procedure_id")));
+
+            //自己以前填过的钢印号
             List<String> filledSteelNumList=new ArrayList<>();
 
             for (Report report : reportList) {
+                System.out.println("report.getCreateDate() = " + report.getCreateDate()+", "+report.getSteelNumArray());
                 //自己当天填的不算
                 if(dtf.format(report.getCreateDate()).equals(createDate)&&report.getCreatorId().equals(token)){
                     continue;

+ 71 - 24
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/impl/PlanServiceImpl.java

@@ -139,7 +139,7 @@ public class PlanServiceImpl extends ServiceImpl<PlanMapper, Plan> implements Pl
                 queryWrapper.and(wrapper->wrapper.eq(Plan::getStartDate,now).or().inSql(Plan::getId,"select ppt1.plan_id \n" +
                         "from  plan_procedure_total ppt1\n" +
                         "left join prod_procedure_team  ppt on ppt.plan_procedure_id=ppt1.id\n" +
-                        "where ppt.progress<100")).eq(Plan::getHideState,0);
+                        "where ppt.progress<100")).lt(Plan::getStartDate,now.plusDays(1)).eq(Plan::getHideState,0);
             }else {
                 queryWrapper.eq(Plan::getStartDate,(planType==0||planType==2)?now:now.plusDays(1));
             }
@@ -523,6 +523,9 @@ public class PlanServiceImpl extends ServiceImpl<PlanMapper, Plan> implements Pl
             List<Product> productList = productMapper.selectList(new QueryWrapper<Product>().eq("company_id", companyId));
             List<ProdProcedure> allProcedureList = prodProcedureMapper.selectList(new QueryWrapper<ProdProcedure>().eq("company_id", companyId).orderByDesc("id"));
             List<Plan> needInsertList=new ArrayList<>();
+            XSSFRow row0 = sheet.getRow(0);
+            XSSFCell cell0 = row0.getCell(0);
+            if (cell0 != null) cell0.setCellType(CellType.STRING);
             List<PlanSteelStampNumber> allPlanSteelStampNumberList=new ArrayList<>();
             for (int rowIndex = 1; rowIndex <= rowNum; rowIndex++) {
                 XSSFRow row = sheet.getRow(rowIndex);
@@ -536,24 +539,28 @@ public class PlanServiceImpl extends ServiceImpl<PlanMapper, Plan> implements Pl
                 Plan plan=new Plan();
                 plan.setCompanyId(companyId);
                 List<PlanSteelStampNumber> planSteelStampNumberList=new ArrayList<>();
-                if(planType!=1){
+                if(planType!=2){
+                    if(!StringUtils.isEmpty(cell0.getStringCellValue())){
+                        if(cell0.getStringCellValue().equals("任务变更通知号")){
+                            msg.setError("导入模板为插单计划模板,请重新下载模板");
+                            return  msg;
+                        }
+                    }
                     plan.setPlanType(0);
                     //排产工单号 产品名称 钢印号 数量 主工序 工位 开工时间 完工时间 描述
                     XSSFCell productSchedulingNumCell = row.getCell(0);
                     XSSFCell productNameCell = row.getCell(1);
                     XSSFCell steelStampNumberCell = row.getCell(2);
-                    XSSFCell vehiclSerialNumberCell = row.getCell(3);
-                    XSSFCell numCell = row.getCell(4);
-                    XSSFCell mainProcessCell = row.getCell(5);
-                    XSSFCell stationNameCell = row.getCell(6);
-                    XSSFCell startDateCell = row.getCell(7);
-                    XSSFCell endDateCell = row.getCell(8);
-                    XSSFCell describtionCell = row.getCell(9);
+                    XSSFCell numCell = row.getCell(3);
+                    XSSFCell mainProcessCell = row.getCell(4);
+                    XSSFCell stationNameCell = row.getCell(5);
+                    XSSFCell startDateCell = row.getCell(6);
+                    XSSFCell endDateCell = row.getCell(7);
+                    XSSFCell describtionCell = row.getCell(8);
 
                     if (productSchedulingNumCell != null) productSchedulingNumCell.setCellType(CellType.STRING);
                     if (productNameCell != null) productNameCell.setCellType(CellType.STRING);
                     if (steelStampNumberCell != null) steelStampNumberCell.setCellType(CellType.STRING);
-                    if (vehiclSerialNumberCell != null) vehiclSerialNumberCell.setCellType(CellType.STRING);
                     if (numCell != null) numCell.setCellType(CellType.NUMERIC);
                     if (mainProcessCell != null) mainProcessCell.setCellType(CellType.STRING);
                     if (stationNameCell != null) stationNameCell.setCellType(CellType.STRING);
@@ -575,16 +582,35 @@ public class PlanServiceImpl extends ServiceImpl<PlanMapper, Plan> implements Pl
                     }
                     if(steelStampNumberCell!=null){
                         String stringCellValue = steelStampNumberCell.getStringCellValue();
-                        String[] split = stringCellValue.split("[|\\,\\,]");
+                        String[] split = stringCellValue.split("\\|");
                         for (String s : split) {
+                            String[] targetSplit = s.split(",");
+                            if(targetSplit.length!=2){
+                                msg.setError("数据["+s+"]钢印号数组及下标错误");
+                                return msg;
+                            }
+                            String steelStampNum=targetSplit[0];
+                            String indexNum=targetSplit[1];
                             PlanSteelStampNumber p=new PlanSteelStampNumber();
-                            if(s.contains("-")){
-                                String[] split1 = s.split("-");
+                            if(steelStampNum.contains("-")){
+                                String[] split1 = steelStampNum.split("-");
                                 p.setSteelStampNumberStart(split1[0]);
                                 p.setSteelStampNumberEnd(split1[1]);
                             }else {
-                                p.setSteelStampNumberStart(s);
-                                p.setSteelStampNumberEnd(s);
+                                p.setSteelStampNumberStart(steelStampNum);
+                                p.setSteelStampNumberEnd(steelStampNum);
+                            }
+                            if(indexNum.contains("-")){
+                                String[] split2 = indexNum.split("-");
+                                if(Integer.valueOf(split2[0])>Integer.valueOf(split2[1])){
+                                    msg.setError("钢印号数组["+s+"]下标异常,第一下标不能大于第二下标");
+                                    return msg;
+                                }
+                                p.setRuleIndexStart(Integer.valueOf(split2[0]));
+                                p.setRuleIndexEnd(Integer.valueOf(split2[1]));
+                            }else {
+                                p.setRuleIndexStart(Integer.valueOf(indexNum));
+                                p.setRuleIndexEnd(Integer.valueOf(indexNum));
                             }
                             planSteelStampNumberList.add(p);
                         }
@@ -603,11 +629,6 @@ public class PlanServiceImpl extends ServiceImpl<PlanMapper, Plan> implements Pl
                         msg.setError("产品名称不能为空");
                         return msg;
                     }
-                    if(vehiclSerialNumberCell!=null){
-                        String[] split = vehiclSerialNumberCell.getStringCellValue().split("-");
-                        plan.setVehicleNumStart(Integer.valueOf(split[0]));
-                        plan.setVehicleNumEnd(split.length>1?Integer.valueOf(split[1]):Integer.valueOf(split[0]));
-                    }
                     plan.setNum(numCell==null?0:Double.valueOf(numCell.getNumericCellValue()).intValue());
                     plan.setMainProcess(mainProcessCell==null?"":mainProcessCell.getStringCellValue());
                     if(stationNameCell!=null){
@@ -628,14 +649,30 @@ public class PlanServiceImpl extends ServiceImpl<PlanMapper, Plan> implements Pl
                         msg.setError("工位不能为空");
                         return msg;
                     }
-                    if(startDateCell!=null){
+                    if(startDateCell!=null&&!StringUtils.isEmpty(startDateCell.getDateCellValue())&&endDateCell!=null&&!StringUtils.isEmpty(endDateCell.getDateCellValue())){
+                        LocalDate startDate = LocalDate.parse(sdf.format(startDateCell.getDateCellValue()), df);
+                        LocalDate endDate = LocalDate.parse(sdf.format(endDateCell.getDateCellValue()), df);
+                        if(endDate.isBefore(startDate)){
+                            msg.setError("第"+rowIndex+"行数据结束日期大于开始日期");
+                            return msg;
+                        }
+                    }
+                    if(startDateCell!=null&&!StringUtils.isEmpty(startDateCell.getDateCellValue())){
+                        plan.setStartDate(LocalDate.parse(sdf.format(startDateCell.getDateCellValue()),df));
+                    }else {
                         plan.setStartDate(planType==0?LocalDate.now():LocalDate.now().plusDays(1));
                     }
-                    if(endDateCell!=null){
+                    if(endDateCell!=null&&!StringUtils.isEmpty(endDateCell.getDateCellValue())){
                         plan.setEndDate(LocalDate.parse(sdf.format(endDateCell.getDateCellValue()),df));
                     }
                     plan.setDescribtion(describtionCell==null?"":describtionCell.getStringCellValue());
                 }else {
+                    if(!StringUtils.isEmpty(cell0.getStringCellValue())){
+                        if(cell0.getStringCellValue().equals("排产工单号")){
+                            msg.setError("导入模板为排产计划模板,请重新下载模板");
+                            return  msg;
+                        }
+                    }
                     plan.setPlanType(1);
                     /*插单计划*/
                     //任务变更通知号 任务名称 任务类型 计划人数 数量 计划工时 单价 质检类型 工位 开工时间 完工时间 描述
@@ -727,10 +764,20 @@ public class PlanServiceImpl extends ServiceImpl<PlanMapper, Plan> implements Pl
                         msg.setError("工位不能为空");
                         return msg;
                     }
-                    if(startDateCell!=null){
+                    if(startDateCell!=null&&!StringUtils.isEmpty(startDateCell.getDateCellValue())&&endDateCell!=null&&!StringUtils.isEmpty(endDateCell.getDateCellValue())){
+                        LocalDate startDate = LocalDate.parse(sdf.format(startDateCell.getDateCellValue()), df);
+                        LocalDate endDate = LocalDate.parse(sdf.format(endDateCell.getDateCellValue()), df);
+                        if(endDate.isBefore(startDate)){
+                            msg.setError("第"+rowIndex+"行数据结束日期大于开始日期");
+                            return msg;
+                        }
+                    }
+                    if(startDateCell!=null&&!StringUtils.isEmpty(startDateCell.getDateCellValue())){
                         plan.setStartDate(LocalDate.parse(sdf.format(startDateCell.getDateCellValue()),df));
+                    }else {
+                        plan.setStartDate(LocalDate.now());
                     }
-                    if(endDateCell!=null){
+                    if(endDateCell!=null&&!StringUtils.isEmpty(endDateCell.getDateCellValue())){
                         plan.setEndDate(LocalDate.parse(sdf.format(endDateCell.getDateCellValue()),df));
                     }
                     plan.setDescribtion(describtionCell==null?"":describtionCell.getStringCellValue());

Dosya farkı çok büyük olduğundan ihmal edildi
+ 851 - 52
fhKeeper/formulahousekeeper/management-workshop/src/main/java/com/management/platform/service/impl/ReportServiceImpl.java


+ 2 - 1
fhKeeper/formulahousekeeper/management-workshop/src/main/resources/mapper/PlanMapper.xml

@@ -38,11 +38,12 @@
         <result column="vehicle_num_end" property="vehicleNumEnd" />
         <result column="hide_state" property="hideState" />
         <result column="is_delete" property="isDelete" />
+        <result column="real_end_date" property="realEndDate" />
     </resultMap>
 
     <!-- 通用查询结果列 -->
     <sql id="Base_Column_List">
-        id, product_scheduling_num, product_id, product_name, project_code, company_id, num, main_process, station_id, station_name, foreman_id, foreman_name, plan_type, start_date, end_date, plan_total_wages, progress, task_name, task_type_id, task_type_name, check_type, task_change_notice_num, plan_man_num, plan_work_hour, money_of_job, describtion, version_number, create_time, create_id, status, vehicle_num_start, vehicle_num_end, hide_state, is_delete
+        id, product_scheduling_num, product_id, product_name, project_code, company_id, num, main_process, station_id, station_name, foreman_id, foreman_name, plan_type, start_date, end_date, plan_total_wages, progress, task_name, task_type_id, task_type_name, check_type, task_change_notice_num, plan_man_num, plan_work_hour, money_of_job, describtion, version_number, create_time, create_id, status, vehicle_num_start, vehicle_num_end, hide_state, is_delete, real_end_date
     </sql>
 
 </mapper>

+ 117 - 61
fhKeeper/formulahousekeeper/management-workshop/src/main/resources/mapper/ReportMapper.xml

@@ -135,7 +135,7 @@
     </select>
 
     <select id="getPersonWorkHoursWagesList" resultType="java.util.Map">
-        select b.id as userId,c.department_name as departmentName,b.name as userName,DATE_FORMAT(a.create_date,'%Y%m%d') as crateDate,SUM(a.cost) as cost,SUM(a.working_time) as workTime
+        select b.id as userId,c.department_name as departmentName,b.name as userName,DATE_FORMAT(a.create_date,'%Y%m%d') as crateDate,IFNULL(SUM(a.cost),0) as cost,IFNULL(SUM(a.working_time),0) as workTime
         from report a
         left join user b on a.creator_id=b.id
         left join department c on c.department_id=b.department_id
@@ -153,12 +153,13 @@
     </select>
 
     <select id="getPersonWorkHoursWagesDetail" resultType="java.util.Map">
-        select r.cost,r.working_time,r.creator_id,ppt.total_progress as progress,DATE_FORMAT(r.create_date,'%Y%m%d') as createDate,pp.name as procedureName,(case  when pp.check_type=0 then '自检' when pp.check_type=1 then '互检' else '专检' end) as checkType,
+        select r.cost,r.working_time,r.finish_num, r.creator_id,ppt.total_progress as progress,DATE_FORMAT(r.create_date,'%Y%m%d') as createDate,pp.name as procedureName,(case  when pp.check_type=0 then '自检' when pp.check_type=1 then '互检' else '专检' end) as checkType,
         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 taskName,plan.plan_type as planType,u.name as checkerName,u2.name as creatorName,plan.product_scheduling_num
+        plan.task_change_notice_num as taskName,plan.plan_type as planType,u.name as checkerName,u2.name as creatorName,plan.product_scheduling_num,r.finish_num as finishNum
         from report r
+        left join prod_procedure_team ppt2 on r.user_procedure_team_id=ppt2.id
         left join prod_procedure pp on r.prod_procedure_id=pp.id
-        left join plan_procedure_total ppt on ppt.prod_procedure_id=pp.id
+        left join plan_procedure_total ppt on ppt.id=ppt2.plan_procedure_id
         left join product p on p.id=r.product_id
         left join plan on plan.id=r.plan_id
         left join user u on r.checker_id=u.id
@@ -180,7 +181,6 @@
         <if test="startDate!=null and endDate!=null">
             and r.create_date between #{startDate} and #{endDate}
         </if>
-        group by r.id
     </select>
 
     <select id="getProcedureRealTimeProgressList" resultType="java.util.Map">
@@ -189,9 +189,9 @@
         from plan_procedure_total a
         left join plan b on a.plan_id=b.id
         left join prod_procedure c on a.prod_procedure_id=c.id
-        where b.company_id=#{companyId}
+        where b.company_id=#{companyId} and b.status!=2
         <if test="userId!=null and userId!=''">
-            and d.user_id=#{userId}
+            and b.foreman_id=#{userId}
         </if>
         <if test="deptId!=null and deptId!=''">
             and b.station_id=#{deptId}
@@ -200,7 +200,7 @@
             and b.foreman_id=#{foremanId}
         </if>
         <if test="startDate!=null and startDate!='' and endDate!=null and endDate!=''">
-            and (b.start_date &gt;= #{startDate} and b.end_date &lt;= #{endDate})
+            and b.start_date between #{startDate} and #{endDate}
         </if>
         order by b.create_time desc ,a.id
         <if test="pageStart!=null and pageSize!=null">
@@ -215,9 +215,9 @@
         from plan_procedure_total a
         left join plan b on a.plan_id=b.id
         left join prod_procedure c on a.prod_procedure_id=c.id
-        where b.company_id=#{companyId}
+        where b.company_id=#{companyId} and b.status!=2
         <if test="userId!=null and userId!=''">
-            and d.user_id=#{userId}
+            and  b.foreman_id=#{userId}
         </if>
         <if test="deptId!=null and deptId!=''">
             and b.station_id=#{deptId}
@@ -226,7 +226,7 @@
             and b.foreman_id=#{foremanId}
         </if>
         <if test="startDate!=null and startDate!='' and endDate!=null and endDate!=''">
-            and (b.start_date &gt;= #{startDate} and b.end_date &lt;= #{endDate})
+            and b.start_date between #{startDate} and #{endDate}
         </if>
         ) as total
     </select>
@@ -312,17 +312,16 @@
 
     <select id="getPlanRealTimeProgressList" resultType="java.util.Map">
         select b.id as planId,(Case when b.plan_type=0 then b.product_scheduling_num else b.task_change_notice_num end) as taskName,
-        b.foreman_name as userName,IFNULL(ROUND(SUM(d.work_time),2),0) as planWorkTime,SUM(d.job_of_money) as planCost,
-        IFNULL(SUM((select SUM(working_time) from report where user_procedure_team_id = d.id)),0)  as nowWorkTime,
-        SUM((select SUM(cost) from report where user_procedure_team_id = d.id)) as nowCost
-        from plan_procedure_total a
-        left join plan b on a.plan_id=b.id
-        left join prod_procedure c on a.prod_procedure_id=c.id
-        left join prod_procedure_team d on a.id=d.plan_procedure_id
-        left join user u on u.id=d.user_id
+        b.foreman_name as userName,IFNULL(ROUND(SUM(a.total_working_hours),2),0) as planWorkTime,IFNULL(ROUND(SUM(a.total_wages),2),0)  as planCost,
+        IFNULL(ROUND(SUM(a.`total_fill_time`),2),0) AS nowWorkTime,
+        IFNULL(ROUND(SUM(a.`total_wages`*a.`total_progress`/100),2),0) AS nowCost,
+        b.product_name as productName,b.num as planNum,DATE_FORMAT(b.start_date,'%Y%m%d') as startDate,DATE_FORMAT(b.end_date,'%Y%m%d') as endDate,DATE_FORMAT(b.real_end_date,'%Y%m%d') as realEndDate,b.station_name as statinoName
+        from plan b
+        left join plan_procedure_total a on a.plan_id=b.id
+        left join user u on u.id=b.station_id
         where b.company_id=#{companyId}
         <if test="userId!=null and userId!=''">
-            and d.user_id=#{userId}
+            and b.foreman_id=#{userId}
         </if>
         <if test="deptId!=null and deptId!=''">
             and b.station_id=#{deptId}
@@ -348,18 +347,16 @@
 
     <select id="getPlanRealTimeProgressCount" resultType="java.lang.Integer">
         select count(1) from (
-        select (Case when b.plan_type=0 then b.product_scheduling_num else b.task_change_notice_num end) as taskName,
-        b.foreman_name as userName,SUM(d.work_time) as planWorkTime,SUM(d.job_of_money) as planCost,
-        SUM((select SUM(working_time) from report where user_procedure_team_id = d.id))  as nowWorkTime,
-        SUM((select SUM(cost) from report where user_procedure_team_id = d.id)) as nowCost
-        from plan_procedure_total a
-        left join plan b on a.plan_id=b.id
-        left join prod_procedure c on a.prod_procedure_id=c.id
-        left join prod_procedure_team d on a.id=d.plan_procedure_id
-        left join user u on u.id=d.user_id
+        select b.id as planId,(Case when b.plan_type=0 then b.product_scheduling_num else b.task_change_notice_num end) as taskName,
+        b.foreman_name as userName,IFNULL(ROUND(SUM(a.total_working_hours),2),0) as planWorkTime,IFNULL(ROUND(SUM(a.total_wages),2),0)  as planCost,
+        IFNULL(ROUND(SUM(a.`total_fill_time`),2),0) AS nowWorkTime,
+        IFNULL(ROUND(SUM(a.`total_wages`*a.`total_progress`/100),2),0) AS nowCost
+        from plan b
+        left join plan_procedure_total a on a.plan_id=b.id
+        left join user u on u.id=b.station_id
         where b.company_id=#{companyId}
         <if test="userId!=null and userId!=''">
-            and d.user_id=#{userId}
+            and b.foreman_id=#{userId}
         </if>
         <if test="deptId!=null and deptId!=''">
             and b.station_id=#{deptId}
@@ -376,31 +373,27 @@
     </select>
 
     <select id="getDpetStatisticsProgressList" resultType="java.util.Map">
-        select de.department_id as departmentId, de.department_name as departmentName,
-        SUM(d.work_time) as planWorkTime,
-        SUM((select SUM(working_time) from report where user_procedure_team_id = d.id)) as nowWorkTime,
-        SUM((select SUM(cost) from report where user_procedure_team_id = d.id)) as  nowCost
-        from plan_procedure_total a
-        left join plan b on a.plan_id=b.id
-        left join prod_procedure c on a.prod_procedure_id=c.id
-        left join prod_procedure_team d on a.id=d.plan_procedure_id
-        left join user u on u.id=d.user_id
-        left join department de on b.station_id=de.department_id
-        where b.company_id=#{companyId}
+        select d.department_id as departmentId,d.department_name as departmentName,IFNULL(SUM((select SUM(working_time) from report where plan_id = p.id)),0) as nowWorkTime,
+        IFNULL(SUM((select SUM(cost) from report where plan_id  = p.id)),0) as  nowCost,
+        IFNULL(SUM((select SUM(total_working_hours) from plan_procedure_total where plan_id  = p.id)),0) as   planWorkTime
+        from
+        department d
+        left join plan p on p.station_id=d.department_id
+        where p.company_id=#{companyId} and p.status!=2
         <if test="userId!=null and userId!=''">
             and d.user_id=#{userId}
         </if>
         <if test="deptId!=null and deptId!=''">
-            and b.station_id=#{deptId}
+            and p.station_id=#{deptId}
         </if>
         <if test="foremanId!=null and foremanId!=''">
-            and b.foreman_id=#{foremanId}
+            and p.foreman_id=#{foremanId}
         </if>
         <if test="startDate!=null and startDate!='' and endDate!=null and endDate!=''">
-            and (b.start_date &gt;= #{startDate} and b.end_date &lt;= #{endDate})
+            and p.start_date between #{startDate} and #{endDate}
         </if>
-        group by b.station_id
-        order by b.create_time desc ,a.id
+        group by d.department_id
+        order by p.create_time desc
         <if test="pageStart!=null and pageSize!=null">
             limit #{pageStart},#{pageSize}
         </if>
@@ -408,30 +401,26 @@
 
     <select id="getDpetStatisticsProgressCount" resultType="java.lang.Integer">
         select count(1) from (
-        select de.department_name as departmentName,
-        SUM(d.work_time) as planWorkTime,
-        SUM((select SUM(working_time) from report where user_procedure_team_id = d.id)) as nowWorkTime,
-        SUM((select SUM(cost) from report where user_procedure_team_id = d.id)) as  nowCost
-        from plan_procedure_total a
-        left join plan b on a.plan_id=b.id
-        left join prod_procedure c on a.prod_procedure_id=c.id
-        left join prod_procedure_team d on a.id=d.plan_procedure_id
-        left join user u on u.id=d.user_id
-        left join department de on b.station_id=de.department_id
-        where b.company_id=#{companyId}
+        select d.department_id as departmentId,d.department_name as departmentName,IFNULL(SUM((select SUM(working_time) from report where plan_id = p.id)),0) as nowWorkTime,
+        IFNULL(SUM((select SUM(cost) from report where plan_id  = p.id)),0) as  nowCost,
+        IFNULL(SUM((select SUM(total_working_hours) from plan_procedure_total where plan_id  = p.id)),0) as   planWorkTime
+        from
+        department d
+        left join plan p on p.station_id=d.department_id
+        where p.company_id=#{companyId} and p.status!=2
         <if test="userId!=null and userId!=''">
             and d.user_id=#{userId}
         </if>
         <if test="deptId!=null and deptId!=''">
-            and b.station_id=#{deptId}
+            and p.station_id=#{deptId}
         </if>
         <if test="foremanId!=null and foremanId!=''">
-            and b.foreman_id=#{foremanId}
+            and p.foreman_id=#{foremanId}
         </if>
         <if test="startDate!=null and startDate!='' and endDate!=null and endDate!=''">
-            and (b.start_date &gt;= #{startDate} and b.end_date &lt;= #{endDate})
+            and p.start_date between #{startDate} and #{endDate}
         </if>
-        group by b.station_id
+        group by d.department_id
         ) as total
     </select>
     <select id="getReportList" resultType="java.util.Map">
@@ -456,4 +445,71 @@
         </if>
     </select>
 
+    <select id="getPlanDataWithStation" resultType="java.util.Map">
+        SELECT p.id, p.num AS planNum,IFNULL(SUM(ppt.`total_working_hours`),0) AS  planHour ,IFNULL(SUM(ppt.`total_fill_time`),0) AS nowHour,IFNULL(SUM(ppt.`total_wages`),0) AS planCost,
+        IFNULL(SUM(ppt.`total_wages`*ppt.`total_progress`/100),0) AS nowCost,
+        IFNULL(ROUND(IFNULL(ROUND(SUM(ppt.total_fill_time)/SUM(ppt.total_working_hours), 2),0)*p.num,2),0) AS nowNum,d.department_id AS deptId,p.start_date AS startDate,
+        IFNULL(d.`superior_id`,d.`department_id`) AS superiorId
+        FROM plan p
+        LEFT JOIN plan_procedure_total ppt ON ppt.plan_id=p.id
+        LEFT JOIN department d ON p.station_id=d.department_id
+        LEFT JOIN department dd ON d.superior_id=dd.department_id
+        <where>
+            p.status!=2 and
+            p.company_id=#{companyId}
+            <if test="startDate!=null and startDate!='' and endDate!=null and endDate!=''">
+                and p.start_date between #{startDate} and #{endDate}
+            </if>
+            <if test="foremanId!=null">
+                and (d.manager_id=#{foremanId} or dd.manager_id=#{foremanId})
+            </if>
+        </where>
+        group by p.id
+        order by p.create_time desc
+<!--        <if test="pageStart!=null and pageSize!=null">-->
+<!--            limit #{pageStart},#{pageSize}-->
+<!--        </if>-->
+    </select>
+
+
+    <select id="getPlanDataWithUser" resultType="java.util.Map">
+        select d.department_id as deptId,u.id as userId, u.name as userName,p.start_date as startDate,IFNULL(ppt.total_wages,0) as planCost,IFNULL(ppt.total_working_hours,0) as planHour,
+        IFNULL((select SUM(working_time) from report where report.user_procedure_team_id=ppt2.id),0) as nowHour,
+        IFNULL((select SUM(cost) from report where report.user_procedure_team_id=ppt2.id),0) as nowCost,ppt.id as pptId,IF((select COUNT(1) from prod_procedure_team where plan_procedure_id=ppt.id)>1,true,false) as hasMoreUser
+        from prod_procedure_team ppt2
+        left join plan_procedure_total ppt on ppt2.plan_procedure_id=ppt.id
+        left join user u on u.id=ppt2.user_id
+        left join plan p on ppt.plan_id=p.id
+        left join department d on u.department_id=d.department_id
+        <where>
+         p.status!=2 and
+         p.company_id=#{companyId}
+         <if test="filterDeptId!=null">
+             and d.department_id=#{filterDeptId}
+         </if>
+        <if test="startDate!=null and startDate!='' and endDate!=null and endDate!=''">
+            and p.start_date between #{startDate} and #{endDate}
+        </if>
+        </where>
+    </select>
+
+    <select id="getPlanDataWithUserId" resultType="java.util.Map">
+        select DATE_FORMAT(p.start_date,'%Y%m%d') as createDate, IFNULL(SUM(r.working_time),0) as workingTime,
+        IFNULL(SUM(r.cost),0) as cost,pp.product_name as productName,pp.product_id as productId,pp.name as procedureName,pp.id as procedureId,r.finish_num as finishNum
+        from
+        report r
+        left join plan p on r.plan_id=p.id
+        left join prod_procedure pp on r.prod_procedure_id=pp.id
+        <where>
+            r.company_id=#{companyId}
+            <if test="startDate!=null and startDate!='' and endDate!=null and endDate!=''">
+                and p.start_date between #{startDate} and #{endDate}
+            </if>
+            <if test="userId!=null">
+                and r.creator_id=#{userId}
+            </if>
+        </where>
+        group by r.create_date,pp.id
+    </select>
+
 </mapper>

+ 13 - 3
fhKeeper/formulahousekeeper/timesheet-workshop-h5/src/views/statisticsView/statisticsView.vue

@@ -21,9 +21,19 @@
             <van-collapse  v-model="activeNames">
               <van-collapse-item v-for="(item,index) in groupList" :key="index" :title="item.createDate+' 工时:'+item.working_time+'分钟 工价:'+item.cost+'元'" :name="index">
                  <van-cell v-for="(item2,index2) in item.subDataList" :key="index2" @click="goDetail(item2)">
-                  <span>{{item2.creatorName}}:</span>
-                  工时:<span :style="{color:item2.working_time==0?'red':''}">{{item2.working_time}}</span>分钟
-                  工价:<span :style="{color:item2.cost==0?'red':''}">{{item2.cost}}</span>元
+                  <div v-if="checkStatus==1">
+                    <span >{{item2.creatorName}}:</span>
+                    工时:<span :style="{color:item2.working_time==0?'red':''}">{{item2.working_time}}</span>分钟
+                    工价:<span :style="{color:item2.cost==0?'red':''}">{{item2.cost}}</span>元
+                  </div>
+                  <div v-for="(item3, index3) in item2.detailData" :key="index3">
+                    <span style="color:#20a0ff;">{{ item3.productName }}</span>
+                    <span style="margin-left:5px;">{{ item3.procedureName }}</span>
+                    <span style="margin-left:5px;">{{ item3.cost }}元</span>
+                    <span style="margin-left:5px;">{{ item3.working_time }}分钟</span>
+                    <span style="margin-left:5px;"><span style="color:rgb(185, 160, 16);">{{ item3.finish_num?item3.finish_num:0 }}</span> 件</span>
+                  </div>
+
                  </van-cell>
               </van-collapse-item>
             </van-collapse>

+ 42 - 13
fhKeeper/formulahousekeeper/timesheet-workshop-h5/src/views/workView/fillReport.vue

@@ -1,11 +1,17 @@
 <template>
   <div class="distribution">
     <van-nav-bar title="报工" left-text="返回" @click-left="back" fixed left-arrow />
-    <div class="distribution_header">
+    <van-cell title="报工日期" :value="reportDate" @click="reportDateShow = true" is-link>
+    </van-cell>
+    <van-cell title="产品名称" :value="reportForm.product_name"></van-cell>
+    <van-cell :title="reportForm.plan_type == 0?'排产工单号':'任务变更通知号'" :value="reportForm.plan_type == 0 ? reportForm.product_scheduling_num : reportForm.task_change_notice_num"></van-cell>
+    <van-cell title="计划工期" :value="reportForm.start_date+'至'+(reportForm.end_date==null?' ':reportForm.end_date)"></van-cell>
+    <!-- <div class="distribution_header">
+      
       <div>{{ reportForm.product_name }}<span style="float:right;color:#20a0ff;">{{reportDate  }}</span> </div>
       <div>{{ reportForm.plan_type == 0 ? reportForm.product_scheduling_num : reportForm.task_change_notice_num }}</div>
       <div>{{ reportForm.start_date }}至{{ reportForm.end_date }}</div>
-    </div>
+    </div> -->
     <div class="distribution_con">
       <van-form @submit="onSubmit">
         <van-cell-group inset>
@@ -48,8 +54,7 @@
           </van-cell>
         </van-cell-group>
         <div style="margin: 16px;">
-          <van-button round block type="primary" native-type="submit" :loading="saving"
-            :disabled="reportForm.finishNum == 0">
+          <van-button round block type="primary" native-type="submit" :loading="saving">
             提交
           </van-button>
           <p v-if="reportForm.canBeDeleted" @click="deleteReport" style="margin:16px;text-align:center;color:#666;">删除</p>
@@ -68,6 +73,8 @@
         </template>
       </van-picker>
     </van-popup>
+    <!-- 日期 -->
+    <van-calendar v-model="reportDateShow" :min-date="minDate" @confirm="reportDateOnConfirm" />
   </div>
 </template>
 
@@ -78,6 +85,8 @@ export default {
   },
   data() {
     return {
+      minDate: new Date(2023, 0, 1),
+      reportDateShow: false,
       reportId: null,
       reportDate: null,
       checkerOptionList: [],
@@ -97,10 +106,27 @@ export default {
   created() { },
   mounted() {
     this.reportDate = this.$route.query.date;
-    this.reportId = this.$route.query.ohterId;
+    if (this.reportDate == null) {
+      //初始化为当天
+      this.reportDate = this.formatDate(new Date());
+    }
+    this.reportId = this.$route.query.otherId;
+
     this.getMyPlanProcedureList();
   },
   methods: {
+    formatDate(date) {
+      // 中国标准时间转成 YYYY-MM-DD
+      const year = date.getFullYear();
+      const month = date.getMonth() + 1;
+      const day = date.getDate();
+      return `${year}-${month < 10 ? '0' + month : month}-${day < 10 ? '0' + day : day}`;
+    },
+    reportDateOnConfirm(date) {
+      this.reportDateShow = false;
+      this.reportDate = this.formatDate(date);
+      this.getMyPlanProcedureList();
+    },
     deleteReport() {
       this.$dialog.confirm({
           title: '删除报工',
@@ -160,11 +186,12 @@ export default {
         isTerminated: this.reportForm.isTerminated,
         steelNumArray: JSON.stringify(this.reportForm.checkedSteelNum),
         finishNum: this.reportForm.finishNum,
-        isFinish: this.reportForm.isFinish
+        isFinish: this.reportForm.isFinish,
+        createDate: this.reportDate
       };
-      const { id, reportBoolean, ohterId } = this.$route.query;
-      if(reportBoolean == 'true') {
-        postData.id = ohterId;
+      const { id, reportBoolean, otherId } = this.$route.query;
+      if(this.reportId) {
+        postData.id = this.reportId;
       }
       if (this.reportForm.isFinish) {
         if (this.reportForm.check_type != 0) {
@@ -197,9 +224,6 @@ export default {
         id: id,
         inputSteelNum:this.inputSteelNum
       }
-      if(reportBoolean == 'true') {
-        params.createDate = date
-      }
       if (this.reportDate) {
         params.createDate = this.reportDate;
       }
@@ -208,8 +232,13 @@ export default {
         .then(res => {
           if (res.code == "ok") {
             this.reportForm = res.data;
+            if (this.reportForm.oldReport != null) {
+              //日报已存在,赋予id
+              this.reportId = this.reportForm.oldReport.id;
+            }
             this.oldPlanSteelStampNumberList=this.reportForm.planSteelStampNumberList
-            this.reportForm.checkedSteelNum = JSON.parse(this.reportForm.steel_num_array);
+            //当日选中的钢印号,默认勾选上
+            this.reportForm.checkedSteelNum = this.reportForm.steelNumArray==null?[]:this.reportForm.steelNumArray;
             if (this.reportForm.check_type == 0) {
               //自检
               this.reportForm.checker_name = this.user.name;

+ 1 - 1
fhKeeper/formulahousekeeper/timesheet-workshop-h5/src/views/workView/workView.vue

@@ -286,7 +286,7 @@ export default {
         query: {
           id: this.reportBoolean ? item.userProcedureTeamId : item.id,
           reportBoolean: this.reportBoolean,
-          ohterId: item.id,
+          otherId: item.id,
           date: item.createDate,
         }
       })

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

@@ -23,6 +23,7 @@
                   <el-menu-item index="1-4"  @click="ssl(3)"><p>{{'计划实时进度表'}}</p></el-menu-item>
                   <el-menu-item index="1-5"  @click="ssl(4)"><p>{{'部门生产统计表'}}</p></el-menu-item>
                   <el-menu-item index="1-6"  @click="ssl(5)"><p>{{'月生产件数报表'}}</p></el-menu-item>
+                  <el-menu-item index="1-7"  @click="ssl(6)"><p>{{'车间工位计划表'}}</p></el-menu-item>
                 </el-submenu>
               </el-menu>
           </el-col>
@@ -37,13 +38,13 @@
       <h3 ref="headHe" style="padding-left: 10px;float:left;width:15%">{{shuz[ins]}}</h3>
       <div class="headScreen" :style="'width:72%'">
           <!-- 部门筛选 -->
-          <el-cascader v-if="ins!=5" v-model="departmentIdArray" :options="departmentList" :placeholder="$t('qing-xuan-ze-bu-men')"
-            :props="{ checkStrictly: true,expandTrigger: 'hover',multiple: ins == 6 ? true : false }" collapse-tags :show-all-levels="false" clearable
+          <el-cascader v-if="ins!=5 && !isViewUser" v-model="departmentIdArray" :options="departmentList" :placeholder="$t('qing-xuan-ze-bu-men')"
+            :props="{ checkStrictly: true,expandTrigger: 'hover' }" collapse-tags :show-all-levels="false" clearable
             @change="selcts()" size="small" style="margin-bottom: 10px;width:180px"
           ></el-cascader>
 
           <!-- 人员筛选 -->
-          <el-select v-if="ins!=4 && ins!=5" v-model="userId" :placeholder="$t('pleaseselectpersonnel')" @change="selcts()" clearable filterable size="small" style="width:120px">
+          <el-select v-if="ins!=4 && ins!=5 && ins!=6" v-model="userId" :placeholder="$t('pleaseselectpersonnel')" @change="selcts()" clearable filterable size="small" style="width:120px">
             <el-option v-for="(item, index) in selUserList" :key="index" :label="item.name" :value="item.id"></el-option>
           </el-select>
 
@@ -54,7 +55,7 @@
 
           <!-- 时间段筛选 -->
           <template>
-            <span>
+            <span v-if="!personnelFlag">
               <span class="demonstration" style="color:#999;padding:0 10px">
                 {{ ins == 15 ? $t('xiang-mu-chuang-jian-shi-jian-duan') : $t('message.period') }}
               </span>
@@ -70,7 +71,7 @@
           <el-input v-if="ins == 2" v-model="steelNum" placeholder="请输入钢印号" @change="selcts()" size="small" style="width:140px"></el-input>
           
       </div>
-      <p :style="`${ins == 9 ? 'width:20%' : ins == 14 ? 'width: 20%' : 'width: 10%'}`" class="tableRightBtn">
+      <p  v-if="!personnelFlag" :style="`${ins == 9 ? 'width:20%' : ins == 14 ? 'width: 20%' : 'width: 10%'}`" class="tableRightBtn">
         <el-button type="primary" @click="exportExcel" size="mini">{{ $t('reporderived') }}</el-button>
       </p>
     </div>
@@ -86,9 +87,10 @@
                 <el-table-column align="center" prop="name" label="人员" min-width="100" fixed="left"></el-table-column>
                 <el-table-column v-for="(item, index) in personWorkHoursWagesHead" :key="index" :label="item" align="center" min-width="150">
                     <template slot-scope="scope">
-                        <div v-for="(items, indexs) in scope.row.personWorkHoursWages" :key="indexs" @click="showReportDetail(scope.row,item)" class="colorText">
+                        <div v-for="(items, indexs) in scope.row.personWorkHoursWages" :key="indexs" @click="showReportDetail(scope.row,item)" :class="`${scope.row.departmentCascade== '小计' ? '' : 'colorText'}`">
                             <div v-if="items.crateDate == item">
-                                {{items.workTime}}分钟  {{items.cost}}元
+                               <div> {{items.workTime}}分钟 </div> 
+                               <div>{{items.cost}}元</div>
                             </div>
                         </div>
                     </template>
@@ -141,16 +143,32 @@
 
             <!-- 计划实时进度表 -->
             <el-table v-if="ins == 3"  key="4" border :data="planRealTimeProgressList" highlight-current-row v-loading="listLoading" :height="+tableHeight - 1" style="width: 100%;">
-                <el-table-column align="center" prop="taskName" label="排产计划" min-width="150">
+                <el-table-column align="center" prop="taskName" label="排产工单号" min-width="150">
                   <template slot-scope="scope">{{scope.row.taskName}}</template>
                 </el-table-column>
                 <el-table-column align="center" prop="userName" label="工长" min-width="250"></el-table-column>
+                <el-table-column align="center" prop="planNum" label="计划件数" min-width="150">
+                  <template slot-scope="scope">{{scope.row.planNum}}</template>
+                </el-table-column>
+                <el-table-column align="center" prop="productName" label="产品名称" min-width="150">
+                  <template slot-scope="scope">{{scope.row.productName}}</template>
+                </el-table-column>
+                <el-table-column align="center" prop="startDate" label="开始日期" min-width="150">
+                  <template slot-scope="scope">{{scope.row.startDate}}</template>
+                </el-table-column>
+                <el-table-column align="center" prop="endDate" label="完工日期" min-width="150">
+                  <template slot-scope="scope">{{scope.row.endDate}}</template>
+                </el-table-column>
+                <el-table-column align="center" prop="statinoName" label="工位" min-width="250"></el-table-column>
                 <el-table-column align="center"  label="计划工时" min-width="150">
                   <template slot-scope="scope" v-if="scope.row.planWorkTime">{{scope.row.planWorkTime}}分钟 {{scope.row.planCost}}元</template>
                 </el-table-column>
                 <el-table-column align="center"  label="当前工时" min-width="250">
                   <template slot-scope="scope" v-if="scope.row.nowWorkTime">{{scope.row.nowWorkTime}}分钟 {{scope.row.nowCost}}元</template>
                 </el-table-column>
+                <el-table-column align="center"  label="实际完工日期" min-width="150">
+                  <template slot-scope="scope" v-if="scope.row.realEndDate">{{scope.row.realEndDate}}</template>
+                </el-table-column>
                 <el-table-column align="center"  label="进度" min-width="250">
                   <template slot-scope="scope" v-if="scope.row.progress">{{scope.row.progress}}</template>
                 </el-table-column>
@@ -178,11 +196,84 @@
                 <el-table-column align="center" prop="rounding" label="凑整件数" min-width="150">
                   <template slot-scope="scope">{{scope.row.rounding}}</template>
                 </el-table-column>
-                <el-table-column align="center" prop="converted" label="拆算件数" min-width="150">
-                  <template slot-scope="scope">{{scope.row.converted}}</template>
+                <el-table-column align="center" prop="convertedTime" label="工时折算件数" min-width="150">
+                  <template slot-scope="scope">{{scope.row.convertedTime}}</template>
+                </el-table-column>
+                <el-table-column align="center" prop="convertedCost" label="工价折算件数" min-width="150">
+                  <template slot-scope="scope">{{scope.row.convertedCost}}</template>
+                </el-table-column>
+                <el-table-column align="center" prop="totalTime" label="工时总件数" min-width="150">
+                  <template slot-scope="scope">{{scope.row.totalTime}}</template>
+                </el-table-column>
+                <el-table-column align="center" prop="totalCost" label="工价总件数" min-width="150">
+                  <template slot-scope="scope">{{scope.row.totalCost}}</template>
+                </el-table-column>
+            </el-table>
+
+            <!-- 车间工位计划表 -->
+            <el-table v-if="ins == 6"  key="7" border :data="planDataWithStationDatas" :span-method="workshopStationMerge" highlight-current-row v-loading="listLoading" :height="+tableHeight - 1" style="width: 100%;">
+                <el-table-column v-if="!isViewUser && !personnelFlag" align="center" prop="departmentCascade" label="部门名称"   min-width="150"  fixed="left">
+                  <template slot-scope="scope">
+                    <span v-if="scope.row.deptId!='0'" class="colorText" @click="getPlanDataWithStation(scope.row.deptId)" >{{scope.row.departmentCascade}}</span>
+                    <span v-else class="colorText" >{{scope.row.departmentCascade}}</span>
+                    <!-- <span class="colorText" >{{scope.row.departmentCascade}}</span> -->
+                  </template>
+                </el-table-column>
+                <el-table-column v-if="isViewUser && !personnelFlag" align="center" prop="departmentCascade" label="人员名称"   min-width="150"  fixed="left">
+                  <template slot-scope="scope">
+                    <span v-if="scope.row.userId!='0'" class="colorText"  @click="getPlanDataWithUserId(scope.row.userId)">{{scope.row.userName}}</span>
+                    <span v-else class="colorText" >{{scope.row.userName}}</span>
+                    <!-- <span class="colorText" >{{scope.row.departmentCascade}}</span> -->
+                  </template>
                 </el-table-column>
-                <el-table-column align="center" prop="total" label="总件数" min-width="150">
-                  <template slot-scope="scope">{{scope.row.total}}</template>
+                <el-table-column v-if="personnelFlag" align="center" prop="departmentCascade" label="产品名称"   min-width="150"  fixed="left">
+                  <template slot-scope="scope">
+                    <span>{{scope.row.productName}}</span>
+                  </template>
+                </el-table-column>
+                <div v-if="!personnelFlag">
+                   <el-table-column v-for="(item, index) in planDataWithStationHead" :key="index" :label="item" align="center" min-width="250">
+                      <template slot-scope="scope">
+                          <div  v-for="(items, indexs) in (isViewUser?scope.row.userList:scope.row.deptList)" :key="indexs" >
+                              <div v-if="items.startDate == item">
+                                  <div>计划数:{{items.planNum}} {{items.planHour}}分钟  {{items.planCost}}元 </div>
+                                  <div>实际数:{{items.nowNum}} {{items.nowHour}}分钟  {{items.nowCost}}元    
+                                    <el-popover
+                                    v-if="items.hasMoreUser"
+                                    placement="bottom"
+                                    title="详情"
+                                    width="200"
+                                    trigger="click"
+                                    :content="hasMoreUserResult">
+                                    <i slot="reference" type="primary" style="color:#E6A23C" class="el-icon-warning-outline" @click="getUserCommon(items)"></i>
+                                  </el-popover></div>
+                                  <div v-if="!isViewUser">进度:{{items.progress}}</div>
+                                  <div v-if="isViewUser">进度:{{ comSchedule(items.nowHour, items.planHour) }}</div>
+                              </div>
+                          </div>
+                      </template>
+                  </el-table-column>
+                </div>
+                <div v-if="personnelFlag">
+                  <el-table-column v-for="(item, index) in planDataWithStationHead" :key="index" :label="item" align="center" min-width="250" prop="createDate">
+                    <template slot-scope="scope">
+                          <div  v-for="(items, indexs) in (scope.row.dataList)" :key="indexs" >
+                              <div v-if="items.createDate == item">
+                                  <div>{{items.procedureName}}</div>
+                                  <div>{{items.workingTime}}分钟 {{items.cost}}元</div>
+                                  <div>{{items.finishNum}}件数</div>
+                              </div>
+                          </div>
+                      </template>
+                  </el-table-column>
+                </div>
+                <el-table-column v-if="!personnelFlag" align="center" prop="totalResult" label="合计" min-width="280">
+                   <template slot-scope="scope">
+                      <div>计划数:{{scope.row.totalPlanNum}}  {{scope.row.totalPlanHour}}分钟  {{scope.row.totalPlanCost}}元 </div>
+                      <div>实际数:{{scope.row.totalNowNum}}  {{scope.row.totalNowHour}}分钟  {{scope.row.totalNowCost}}元</div>
+                      <div v-if="!isViewUser">进度:{{scope.row.totalProgress}}</div>
+                      <div v-if="isViewUser">进度:{{ comSchedule(scope.row.totalNowHour, scope.row.totalPlanHour) }}</div>
+                  </template>
                 </el-table-column>
             </el-table>
 
@@ -217,7 +308,7 @@
 
   <el-dialog :title="'详情'" :visible.sync="reportDetailDialog" width="1480px">
           <div>
-            日期:<el-select v-model="simpleDateChoose" placeholder="请选择" @change="getPersonWorkHoursWagesDetail()">
+            日期:<el-select v-model="simpleDateChoose" placeholder="请选择" @change="getPersonWorkHoursWagesDetail(simpleDateChoose)">
                 <el-option
                   v-for="(item,index) in personWorkHoursWagesHead"
                   :key="index"
@@ -272,9 +363,9 @@
               <el-table-column prop="productName" label="产品名称" width="180"></el-table-column>
               <el-table-column prop="product_scheduling_num" label="排产工单号" width="180"></el-table-column>
               <el-table-column prop="procedureName" label="工序名称" width="180"></el-table-column>
-              <el-table-column prop="progress" label="进度" width="80">
+              <el-table-column prop="finishNum" label="完成件数" width="80">
                 <template slot-scope="scope">
-                  {{scope.row.progress?scope.row.progress:0}}%
+                  {{scope.row.finishNum?scope.row.finishNum:0}}
                 </template>
               </el-table-column>
               <el-table-column prop="cost" label="工钱" width="80"></el-table-column>
@@ -466,9 +557,9 @@ export default {
       z   : null,
       value: null,
       dialog: false, // 单据查看展示
-      shuz: ['人员工时工价表', '工序实时进度表','报工查询表','计划实时进度表','部门生产统计表','月度生产件数表'],
+      shuz: ['人员工时工价表', '工序实时进度表','报工查询表','计划实时进度表','部门生产统计表','月度生产件数表','车间工位计划表'],
 
-      shuzArr: ['人员工时工价表', '工序实时进度表','报工查询表','计划实时进度表','部门生产统计表','月度生产件数表'],
+      shuzArr: ['人员工时工价表', '工序实时进度表','报工查询表','计划实时进度表','部门生产统计表','月度生产件数表','车间工位计划表'],
 
       ins: 10000,
       user: JSON.parse(sessionStorage.user),
@@ -564,6 +655,10 @@ export default {
       reportQueryList:[],
 
       productionQuantityList:[],
+      planDataWithStationDatas:[],
+      planDataWithStationHead:[],
+      isViewUser:false,
+      exportDeptId:null,
 
       //筛选项
       productId:"",
@@ -572,6 +667,12 @@ export default {
       steelNum:"",
 
       plondelas: 100, 
+      personnelFlag: false, // 是否处于最后一集的人员
+      rowSpanArr: [], // 需要合并的数据
+
+      sumObject: { english_achievements: 1000, math_achievements: 888 }, // 合计数据
+
+      hasMoreUserResult:""
     };
   },
   computed: {},
@@ -645,6 +746,9 @@ export default {
       this.getPlanDetail(item);
     },
     showReportDetail(row,item){
+      if(row.departmentCascade=='小计'){
+          return
+      }
       console.log(item)
       this.reportDetailDialog=true
       this.detailUserId=row.id
@@ -690,6 +794,27 @@ export default {
       }
     },
 
+    getUserCommon(target){
+      this.http.post('/report/getUserCommentPlanResult', {
+        pptIds:target.pptIds
+      },
+      res => {
+          if (res.code == "ok") {
+              this.hasMoreUserResult = res.data;
+          } else {
+              this.$message({
+                message: res.msg,
+                type: "error"
+              });
+          }
+      },
+      error => {
+          this.$message({
+              message: error,
+              type: "error"
+          });
+      });
+    },
     getUserList(e) {
       let param={}
       if(e){
@@ -965,6 +1090,103 @@ export default {
           });
         });
     },
+    //车间工位计划表
+    getPlanDataWithStation(deptId){
+      let param={
+        startDate:this.rangeDatas[0],
+        endDate:this.rangeDatas[1],
+        pageIndex: this.page,
+        pageSize: this.size,
+        stationId:this.departmentIdArray[this.departmentIdArray.length - 1],
+      }
+      if(deptId){
+        this.exportDeptId=deptId
+        param.filterDeptId=deptId
+        param.isFilterDept=1
+      }
+      this.listLoading=true
+        this.http.post( "/report/getPlanDataWithStation",param,
+        res => {
+          if (res.code == "ok") {
+            this.personnelFlag = false
+            this.planDataWithStationDatas=res.data.records
+            this.planDataWithStationHead=res.data.header
+            this.total=res.data.total
+            this.isViewUser=res.data.isViewUser
+          } else {
+            this.$message({
+              message: res.msg,
+              type: "error"
+            });
+          }
+          this.listLoading=false
+        },error => {
+          this.$message({
+            message: error,
+            type: "error"
+          });
+        });
+    },
+    //获取人员填报数据
+    getPlanDataWithUserId(userId){
+      this.listLoading=true
+        this.http.post( "/report/getPlanDataWithUserId", {
+            startDate:this.rangeDatas[0],
+            endDate:this.rangeDatas[1],
+            userId: userId,
+        },
+        res => {
+          if (res.code == "ok") {
+            this.personnelFlag = true
+            this.handleTableData(res.data)
+            this.planDataWithStationDatas=res.data
+            this.total=res.data
+          } else {
+            this.$message({
+              message: res.msg,
+              type: "error"
+            });
+          }
+          this.listLoading=false
+        },error => {
+          this.$message({
+            message: error,
+            type: "error"
+          });
+        });
+    },
+    // 获取相同名称的个数 tableData: 表格的数据, productId: 确定相同的参数
+    handleTableData(tableData){
+          let rowSpanArr = [], position = 0;
+          for (let [index, item] of tableData.entries()) {
+            if (index == 0) {
+              rowSpanArr.push(1);
+              position = 0;
+            } else {
+              if (item.productId == tableData[index - 1].productId) {
+                rowSpanArr[position] += 1; //项目名称相同,合并到同一个数组中
+                rowSpanArr.push(0);
+              } else {
+                rowSpanArr.push(1);
+                position = index;
+              }
+            }
+          }
+          this.rowSpanArr = rowSpanArr
+    },
+    // 合并车间工位计划表人员点击进去的数据
+    workshopStationMerge({ row, column, rowIndex, columnIndex }) {
+      if(!this.personnelFlag) {
+        return
+      }
+      if (columnIndex === 0) {
+        const rowSpan = this.rowSpanArr[rowIndex];
+        return {
+          rowspan: rowSpan, //行
+          colspan: 1 //列
+        };
+      }
+    },
     //获取产品列表
     getProductList(){
       this.http.post( "/product/getProductPage", {
@@ -1081,6 +1303,8 @@ export default {
             this.getDpetStatisticsProgressList()
         }else if(this.ins==5){
             this.getProductionQuantityList()
+        }else if(this.ins==6){
+            this.getPlanDataWithStation()
         }
     },
     exportExcel() {
@@ -1131,6 +1355,17 @@ export default {
         sl.startDate=this.rangeDatas[0];
         sl.endDate=this.rangeDatas[1];
         sl.productId=this.productId;
+    }
+    else if (this.ins == 6) {
+        fName = '车间工位计划表_' + '.xlsx';
+        url += "/exportPlanDataWithStation";
+        sl.startDate=this.rangeDatas[0];
+        sl.endDate=this.rangeDatas[1];
+        sl.deptId=this.departmentIdArray[this.departmentIdArray.length-1];
+        if(this.exportDeptId){
+          sl.filterDeptId=this.exportDeptId;
+          sl.isFilterDept=1
+        }
     }
         this.http.post(url, sl,
         res => {
@@ -1217,6 +1452,10 @@ export default {
         //TODO: 获取数据
         this.getProductionQuantityList()
       }
+      if(this.ins == 6){
+        //TODO: 获取数据
+        this.getPlanDataWithStation()
+      }
     },
     // 日期
     getCurrentRangeTime() {
@@ -1254,6 +1493,12 @@ export default {
         this.selcts(9)
       }
     },
+    comSchedule(divisor, dividend) {
+      if(!dividend) {
+        return  '0%'
+      }
+      return Math.ceil((divisor / dividend) * 100) + '%'
+    }
   },
 };
 </script>

BIN
fhKeeper/formulahousekeeper/timesheet/src/assets/image/pdfIcon.png


+ 16 - 3
fhKeeper/formulahousekeeper/timesheet/src/components/select.vue

@@ -36,7 +36,7 @@
     <transition name="el-zoom-in-top">
       <div v-show="show" style="position: relative;z-index: 999;"> 
         <!-- 搜索框 -->
-        <div class="searchBox" v-if="filterable">
+        <div class="searchBox" v-if="filterable" :style="`top: ${searchBoxTop}px`">
             <el-input placeholder="请输入名称搜索" size="mini" v-model="searchTex" style="width: 100%" @input="searchLick()" @focus="selectCli()"></el-input>
         </div>
         <div class="transitionBox" :style="filterable ? 'margin: 30px 0;' : ''">
@@ -152,7 +152,11 @@ export default {
             type: Boolean,
             default: false
         },
-        
+        // searchBoxTop 搜索框距离顶部的距离
+        searchBoxTop: {
+            type: String,
+            default: '-9'
+        }
     },
     components: {
         selectWidth: '150',
@@ -165,6 +169,7 @@ export default {
             selectFontSize: '12',
             show: false, // 下拉框
             options: [], // 列表数据
+            optionsCopy: [], // 列表数据复制
             transitionBoxLiIdx: '', // hover 背景色
             selectName: this.$t('defaultText.pleaseChoose'), // 显示的文字
             classDiv: false, // 获得焦点样式
@@ -186,6 +191,7 @@ export default {
         subject: {
             handler(newValue, oldValue) {
                 this.options = newValue
+                this.optionsCopy = JSON.parse(JSON.stringify(newValue))
                 if(this.flg) {
                     if(newValue) {
                         this.selectName = newValue[0].auditorName || newValue[0].name
@@ -348,6 +354,9 @@ export default {
                 this.show = !this.show
                 this.move = !this.move
                 this.searchTex = ''
+                if(this.optionsCopy.length > 0) {
+                    this.$set(this, 'options', JSON.parse(JSON.stringify(this.optionsCopy)))
+                }
             }
         },
         selectClihide() {
@@ -513,7 +522,10 @@ export default {
                             return item;
                         }
                     })
-                    this.options = arr
+                    // this.options = arr
+                    console.log('将要赋值')
+                    var newArr = arr.length > 0 ? arr : res.data.records
+                    this.$set(this, 'options', newArr)
                     this.cursor = res.data.nextCursor
                 } else {
                     this.$message({
@@ -605,6 +617,7 @@ export default {
         position: absolute; 
         width: 100%;
         top: -9px;
+        // top: 0px;
     }
     .transitionBox {
         background: #FFF;

+ 12 - 12
fhKeeper/formulahousekeeper/timesheet/src/components/taskComponent.vue

@@ -34,7 +34,7 @@
                 </el-select>
             </el-form-item>
             <el-form-item :label="$t('types')">
-                <el-select v-model="addForm.taskType" style="width:100%;" :disabled="((this.addForm.id != null && user.id != this.addForm.createrId && currentProject.inchargerId != user.id) && !permissions.projectManagement) && !(groupResponsibleId == user.id)" @change="selchg()">
+                <el-select v-model="addForm.taskType" style="width:100%;" :disabled="((this.addForm.id != null && user.id != this.addForm.createrId && currentProject.inchargerId != user.id) && !permissions.projectManagement && !permissions.editAnyTask) && !(groupResponsibleId == user.id)" @change="selchg()">
                     <el-option v-for="item in taskTypeList" :key="item.id" :label="item.name" :value="item.id">
                         <i :class="item.icon" ></i>
                         <span>{{item.name}}</span>
@@ -52,35 +52,35 @@
                 </el-select>
             </el-form-item> -->
             <el-form-item  :label="$t('taskdefinition')" prop="name">
-                <el-input v-model="addForm.name" :maxlength="40" :disabled="(this.addForm.id != null && user.id != this.addForm.createrId && currentProject.inchargerId != user.id) && !permissions.projectManagement && !(groupResponsibleId == user.id)" :placeholder="$t('enterthetaskcontent')" clearable></el-input>
+                <el-input v-model="addForm.name" :maxlength="40" :disabled="(this.addForm.id != null && user.id != this.addForm.createrId && currentProject.inchargerId != user.id) && !permissions.projectManagement && !permissions.editAnyTask && !(groupResponsibleId == user.id)" :placeholder="$t('enterthetaskcontent')" clearable></el-input>
             </el-form-item>
             <!-- {{timelabel}}{{mileageCup}} -->
             <el-form-item :label="!timelabel ? $t('starttimes') : $t('jie-zhi-shi-jian')" prop="startDate">
                 <el-date-picker v-model="addForm.startDate" type="date" style="width:40%;" value-format="yyyy-MM-dd"  
-                :placeholder="$t('pleaseselectadate')" :disabled="(this.addForm.id != null && user.id != this.addForm.createrId && currentProject.inchargerId != user.id) && !permissions.projectManagement && !(groupResponsibleId == user.id)" @change="DateChange()" v-if="!timelabel"></el-date-picker>
+                :placeholder="$t('pleaseselectadate')" :disabled="(this.addForm.id != null && user.id != this.addForm.createrId && currentProject.inchargerId != user.id) && !permissions.projectManagement && !permissions.editAnyTask && !(groupResponsibleId == user.id)" @change="DateChange()" v-if="!timelabel"></el-date-picker>
                 <span style="margin-left:30px;margin-right:10px;" v-if="!timelabel">{{ $t('deadline') }}</span>
                 <el-date-picker style="width:40%;" v-model="addForm.endDate" type="date" value-format="yyyy-MM-dd"  
-                :placeholder="$t('pleaseselectadate')" :disabled="(this.addForm.id != null && user.id != this.addForm.createrId && currentProject.inchargerId != user.id) && !permissions.projectManagement && !(groupResponsibleId == user.id)" @change="DateChange()"></el-date-picker>
+                :placeholder="$t('pleaseselectadate')" :disabled="(this.addForm.id != null && user.id != this.addForm.createrId && currentProject.inchargerId != user.id) && !permissions.projectManagement && !permissions.editAnyTask && !(groupResponsibleId == user.id)" @change="DateChange()"></el-date-picker>
                 <span style="margin-left:30px;margin-right:10px;" v-if="timelabel && mileageCup">{{ $t('wan-cheng-shi-jian') }}</span>
                 <el-date-picker style="width:40%;" v-if="timelabel && mileageCup" v-model="addForm.finishDate" type="date" value-format="yyyy-MM-dd"  
-                :placeholder="$t('pleaseselectadate')" :disabled="(this.addForm.id != null && user.id != this.addForm.createrId && currentProject.inchargerId != user.id) && !permissions.projectManagement && !(groupResponsibleId == user.id)" @change="DateChange()"></el-date-picker>
+                :placeholder="$t('pleaseselectadate')" :disabled="(this.addForm.id != null && user.id != this.addForm.createrId && currentProject.inchargerId != user.id) && !permissions.projectManagement && !permissions.editAnyTask && !(groupResponsibleId == user.id)" @change="DateChange()"></el-date-picker>
             </el-form-item>
             <div style="border: 1px solid #ddd;margin:5px 0;padding:5px 0;">
             <el-form-item :label="$t('zhi-hang-ren') + (index+1)" v-for="(executorItem, index) in addForm.executorListFront" :key="index">
                 <div class="editingTask">
                     <div style="margin-right: 30px">
-                        <el-select v-if="user.userNameNeedTranslate != 1" v-model="executorItem.executorId" :disabled="(addForm.id != null && user.id != addForm.createrId && currentProject.inchargerId != user.id) && !permissions.projectManagement && !(groupResponsibleId == user.id)" size="small" filterable clearable :placeholder="$t('pleaseselectanexecutor')" style="width: 150px" @change="$forceUpdate()">
+                        <el-select v-if="user.userNameNeedTranslate != 1" v-model="executorItem.executorId" :disabled="(addForm.id != null && user.id != addForm.createrId && currentProject.inchargerId != user.id) && !permissions.projectManagement && !permissions.editAnyTask && !(groupResponsibleId == user.id)" size="small" filterable clearable :placeholder="$t('pleaseselectanexecutor')" style="width: 150px" @change="$forceUpdate()">
                             <el-option v-for="item in users" :key="item.id" :label="item.name" :value="item.id">
                                 <span style="float: left">{{ item.name }}</span>
                                 <span style="float: right; color: #8492a6; font-size: 13px;margin-left: 20px" v-if="item.jobNumber">{{ item.jobNumber }}</span>
                             </el-option>
                         </el-select>
-                        <selectCat v-if="user.userNameNeedTranslate == 1" :size="'mini'" :filterable="true" :subject="users" :subjectId="executorItem.executorId" :distinction="'1'" @selectCal="selectCal" :index="index" :disabled="(addForm.id != null && user.id != addForm.createrId && currentProject.inchargerId != user.id) && !permissions.projectManagement && !(groupResponsibleId == user.id)"></selectCat>
+                        <selectCat v-if="user.userNameNeedTranslate == 1" :size="'mini'" :filterable="true" :subject="users" :subjectId="executorItem.executorId" :distinction="'1'" @selectCal="selectCal" :index="index" :disabled="(addForm.id != null && user.id != addForm.createrId && currentProject.inchargerId != user.id) && !permissions.projectManagement && !permissions.editAnyTask && !(groupResponsibleId == user.id)"></selectCat>
                     </div>
                     <!-- 项目服务 -->
                     <div v-if="user.companyId==3092">
                         <span style="margin-left:30px;margin-right:10px;">{{'项目服务'}}</span>
-                        <el-select  clearable collapse-tags  filterable  v-model="executorItem.serviceId" size="small" placeholder="请选择项目服务" style="width: 300px" @change="serviceIdChange()">
+                        <el-select  clearable collapse-tags  filterable  v-model="executorItem.serviceId" size="small" placeholder="请选择项目服务" style="width: 300px" @change="serviceIdChange()" :disabled="(addForm.id != null && user.id != addForm.createrId && currentProject.inchargerId != user.id) && !permissions.projectManagement && !permissions.editAnyTask && !(groupResponsibleId == user.id)">
                             <el-option
                             v-for="item in sapServiceList"
                             :key="item.id"
@@ -92,18 +92,18 @@
                     <!-- 计划工时 -->
                     <div>
                         <span style="margin-right:10px;">{{ $t('plantime') }}</span>
-                        <el-input-number size="small" :disabled="(addForm.id != null && user.id != addForm.createrId && currentProject.inchargerId != user.id) && !permissions.projectManagement && !(groupResponsibleId == user.id)" v-model="gstimday[index]" style="width:120px;" :min="1" :max="100"  :placeholder="$t('danweitian')" @change="chggstim(0,index)"></el-input-number ><span style="margin-left:5px;">{{ $t('time.day') }}</span>
-                        <el-input-number size="small" :disabled="(addForm.id != null && user.id != addForm.createrId && currentProject.inchargerId != user.id) && !permissions.projectManagement && !(groupResponsibleId == user.id)" v-model="gstimhour[index]" style="width:120px;" :min="1" :max="999"  :placeholder="$t('pleaseentertheplannedworking')" @change="chggstim(1,index)"></el-input-number ><span style="margin-left:5px;">{{ $t('time.hour') }}</span>
+                        <el-input-number size="small" :disabled="(addForm.id != null && user.id != addForm.createrId && currentProject.inchargerId != user.id) && !permissions.projectManagement && !permissions.editAnyTask && !(groupResponsibleId == user.id)" v-model="gstimday[index]" style="width:120px;" :min="1" :max="100"  :placeholder="$t('danweitian')" @change="chggstim(0,index)"></el-input-number ><span style="margin-left:5px;">{{ $t('time.day') }}</span>
+                        <el-input-number size="small" :disabled="(addForm.id != null && user.id != addForm.createrId && currentProject.inchargerId != user.id) && !permissions.projectManagement && !permissions.editAnyTask && !(groupResponsibleId == user.id)" v-model="gstimhour[index]" style="width:120px;" :min="1" :max="999"  :placeholder="$t('pleaseentertheplannedworking')" @change="chggstim(1,index)"></el-input-number ><span style="margin-left:5px;">{{ $t('time.hour') }}</span>
 
                         <!-- <el-input-number v-model="numnnumnum" @change="handleChange" :min="1" :max="10" label="描述文字"></el-input-number> -->
 
                         <!-- 移除执行人 -->
-                        <i class="el-icon-delete" v-if="index>0 && (addForm.id == null|| user.id == addForm.createrId || currentProject.inchargerId == user.id|| permissions.projectManagement || groupResponsibleId == user.id)" style="margin-left:5px" @click="removeExecutorLine(index)"></i>
+                        <i class="el-icon-delete" v-if="index>0 && (addForm.id == null|| user.id == addForm.createrId || currentProject.inchargerId == user.id|| permissions.projectManagement || permissions.editAnyTask|| groupResponsibleId == user.id)" style="margin-left:5px" @click="removeExecutorLine(index)"></i>
                     </div>
                 </div>
             </el-form-item>
             <el-link type="primary" v-if="(((addForm.executorListFront == null || addForm.executorListFront.length<100) && 
-            (addForm.id == null|| user.id == addForm.createrId || currentProject.inchargerId == user.id || permissions.projectManagement)) || 
+            (addForm.id == null|| user.id == addForm.createrId || currentProject.inchargerId == user.id || permissions.projectManagement || permissions.editAnyTask)) || 
             groupResponsibleId == user.id)" 
             style="margin-left:35px;" @click="addExecutorLine">{{ $t('addinganexecutor') }}</el-link>
             </div>

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

@@ -25,7 +25,8 @@
     "basicDataManagement": "基础数据管理",
     "basicSystemSettings": "系统基础设置",
     "roleRightsManagement": "角色权限管理",
-    "projectFormSettings": "项目表单设置"
+    "projectFormSettings": "项目表单设置",
+    "budgetReview":"预估工时审核"
   },
   "role": {
     "ordinaryEmployees": "普通员工",

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

@@ -18,6 +18,7 @@ const StringUtil = {
         projectPhase: false, // 项目阶段管理 // 
         projectCodeAndName: false, // 编辑负责项目编码和名称 //
         projectEditDefaultFolder: false, // 修改默认文件夹 //
+        projectViewAllTasks: false, // 查看全部任务 //
 
         // 合同管理
         contractNew: false, // 新增合同 // 
@@ -94,6 +95,9 @@ const StringUtil = {
         reportFTEAll: false, // 全部部门FTE报表 //
         reportFTEPart: false, // 负责部门FTE报表 // 
         reportEfficent: false, // 有效工时率 // 
+        reportSortScaleTable: false, // 项目分类工时占比表 // 
+        reportSortDetailTable: false, // 分类全部工时明细表 // 
+        reportSortSectionDetailTable: false, // 分类负责部门工时明细表 //
 
         // 请假模块
         leaveFil : false, // 请假填报 // 
@@ -212,6 +216,7 @@ const StringUtil = {
         arr[i] == '负责项目任务分组工时' ? obj.reportGroup = true : ''
         arr[i] == '全部项目成本基线表' ? obj.reportAllOutputValue = true : ''
         arr[i] == '负责项目成本基线表' ? obj.reportOutputValue = true : ''
+        arr[i] == '编辑项目内任务' ? obj.editAnyTask = true : ''
         arr[i] == '日报导出' ? obj.reportExport = true : ''
         arr[i] == '手动推送工时' ? obj.reportPush = true : ''
         arr[i] == '查看全公司数值' ? obj.customDataAll = true : ''
@@ -240,6 +245,12 @@ const StringUtil = {
         arr[i] == '负责项目子项目工时成本' ? obj.reportResponsibleManhourCost = true : ''
         arr[i] == '修改默认文件夹' ? obj.projectEditDefaultFolder = true : ''
         arr[i] == '费用发放' ? obj.costExpenseRelease = true : ''
+        
+        arr[i] == '查看全部任务' ? obj.projectViewAllTasks = true : ''
+
+        arr[i] == '项目分类工时占比表' ? obj.reportSortScaleTable = true : ''
+        arr[i] == '分类全部工时明细表' ? obj.reportSortDetailTable = true : ''
+        arr[i] == '分类负责部门工时明细表' ? obj.reportSortSectionDetailTable = true : ''
     }
     return obj
   }

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

@@ -87,6 +87,9 @@ import provider from './views/provider/provider'
 // 项目表单设置
 import projectForm from './views/project/projectForm'
 
+// 预算工时审核
+import budgetReview from './views/project/budgetReview'
+
 Vue.use(Router)
 
 export const fixedRouter = [
@@ -289,6 +292,19 @@ export const allRouters = [//组织架构
         // 其他信息
         meta: { text: 'navigation.projectManagement' } 
     },
+    //预算工时审核
+    {
+        path: '/',
+        component: Home,
+        name: '预估工时审核',
+        iconCls: 'iconfont firerock-iconxiangmu',
+        leaf: true,
+        children: [
+            { path: '/budgetReview', component: budgetReview, name: '预估工时审核' },
+        ],
+        // 其他信息
+        meta: { text: 'navigation.budgetReview' } 
+    },
     {
         path: '/',
         component: Home,

+ 18 - 0
fhKeeper/formulahousekeeper/timesheet/src/views/Login.vue

@@ -151,6 +151,9 @@
                         } else {
                             if(user.moduleList.length > 0) {
                                 this.$router.push({ path: user.moduleList[0].path })
+                            } else {
+                                //没有授权任何模块,需要提示用户
+                                alert('无权访问,请联系管理员为您分配权限');
                             }
                         }
                     } else if (href.indexOf('errorMsg=') > 0) {
@@ -183,6 +186,9 @@
                     } else {
                         if(user.moduleList.length > 0) {
                             this.$router.push({ path: user.moduleList[0].path })
+                        } else {
+                            //没有授权任何模块,需要提示用户
+                            alert('无权访问,请联系管理员为您分配权限');
                         }
                     }
                 } else {
@@ -368,6 +374,9 @@
                                         var newHref = location.href.split("?")[0] + '#' + (path.indexOf('/')>-1?path:('/'+path));
                                         location.href = newHref;
                                     }
+                                } else {
+                                    //没有授权任何模块,需要提示用户
+                                    alert('无权访问,请联系管理员为您分配权限');
                                 }
                             } else {
                                 this.$message({
@@ -394,6 +403,9 @@
                                     this.$router.push({ path: jumpurl })
                                 }else if(user.moduleList.length > 0) {
                                     this.$router.push({ path: user.moduleList[0].path })
+                                }else {
+                                    //没有授权任何模块,需要提示用户
+                                    alert('无权访问,请联系管理员为您分配权限');
                                 }
                             } else {
                                 this.$message({
@@ -498,6 +510,9 @@
                             if(user.moduleList.length > 0) {
                                 this.$router.push({ path: user.moduleList[0].path })
                                 sessionStorage.setItem('autoRoute',user.moduleList[0].path)
+                            } else {
+                                //没有授权任何模块,需要提示用户
+                                alert('无权访问,请联系管理员为您分配权限');
                             }
                         }
                     } else {
@@ -527,6 +542,9 @@
                         this.permissionsList(res.data)
                         if(user.moduleList.length > 0) {
                             this.$router.push({ path: user.moduleList[0].path })
+                        } else {
+                            //没有授权任何模块,需要提示用户
+                            alert('无权访问,请联系管理员为您分配权限');
                         }
                     } else {
                         this.$message({

+ 445 - 32
fhKeeper/formulahousekeeper/timesheet/src/views/corpreport/list.vue

@@ -41,6 +41,8 @@
                   <el-menu-item index="1-19" v-if="user.timeType.restartTaskNeedReason == 1" @click="ssl(18)"><p>任务重启表</p></el-menu-item>
                   <el-menu-item index="1-20" v-if="permissions.reportFTEAll || permissions.reportFTEPart" @click="ssl(19)"><p>FTE报表</p></el-menu-item>
                   <el-menu-item index="1-21" v-if="permissions.reportEfficent"  @click="ssl(20)"><p>有效工时率表</p></el-menu-item>
+                  <el-menu-item index="1-22" v-if="permissions.reportSortScaleTable" @click="ssl(21)"><p>项目分类工时占比表</p></el-menu-item>
+                  <el-menu-item index="1-23" v-if="permissions.reportSortDetailTable || permissions.reportSortSectionDetailTable" @click="ssl(22)"><p>分类工时明细表</p></el-menu-item>
                   <!-- <el-menu-item index="1-12"><p @click="ssl(11)">人员工时统计表</p></el-menu-item> -->
                 </el-submenu>
               </el-menu>
@@ -74,14 +76,26 @@
           </el-select>
         </template>
         <!-- 时间段筛选 -->
-          <template v-if="ins == 6 || ins == 8 || ins == 9 || ins == 10 || ins == 11 || ins == 12 || ins == 5 || ins == 16 || ins == 17 || ins == 18 || ins == 20">
-            <span>
-              <span class="demonstration" style="color:#999;padding:0 10px">
-                {{ ins == 15 ? $t('xiang-mu-chuang-jian-shi-jian-duan') : $t('message.period') }}
-              </span>
-              <el-date-picker v-model="rangeDatas" type="daterange" value-format="yyyy-MM-dd" :placeholder="$t('selectstartdate')" @change="picks()" :range-separator="$t('other.to')" :start-placeholder="$t('time.startDate')" :end-placeholder="$t('time.endDate')" style="width:300px" :clearable="ins == 15" size="small"> </el-date-picker>
+        <template v-if="ins == 6 || ins == 8 || ins == 9 || ins == 10 || ins == 11 || ins == 12 || ins == 5 || ins == 16 || ins == 17 || ins == 18 || ins == 20 || ins == 21 || ins == 22">
+          <span>
+            <span class="demonstration" style="color:#999;padding:0 10px">
+              {{ ins == 15 ? $t('xiang-mu-chuang-jian-shi-jian-duan') : $t('message.period') }}
             </span>
-          </template>
+            <el-date-picker v-model="rangeDatas" type="daterange" value-format="yyyy-MM-dd" :placeholder="$t('selectstartdate')" @change="picks()" :range-separator="$t('other.to')" :start-placeholder="$t('time.startDate')" :end-placeholder="$t('time.endDate')" style="width:300px" :clearable="ins == 15" size="small"> </el-date-picker>
+          </span>
+        </template>
+
+        <!-- 项目分类 -->
+        <template v-if="ins == 22">
+          <span>
+            <span class="demonstration" style="color:#999;padding:0 10px">
+              项目分类
+            </span>
+            <el-select v-model="projectSortId" placeholder="请选择" @change="picks()" size="small">
+              <el-option v-for="item in projectSortList" :key="item.id" :label="item.name" :value="item.id"></el-option>
+            </el-select>
+          </span>
+        </template>
           
         <!-- 按部门/项目筛选 -->
         <!-- <el-select v-if="ins == 10" v-model="departmentOrProject" placeholder="请选择" size="small" @change="selcts(10)" style="margin-left:10px;width:120px">
@@ -89,12 +103,18 @@
           <el-option label="查看部门审核人" :value="0"></el-option>
         </el-select> -->
         <!-- 项目筛选 -->
-        <el-select v-if="ins != 4 && ins != 8 && ins != 9 && ins != 19 && ins != 10 && ins != 11 && ins != 14 && ins != 15 && ins != 17 && ins != 20" v-model="proJuctId" :placeholder="$t('defaultText.pleaseSelectSnItem')" clearable filterable size="small" @change="selcts()" style="margin-left:10px">
+        <el-select v-if="ins != 4 && ins != 8 && ins != 9 && ins != 19 && ins != 10 && ins != 11 && ins != 14 && ins != 15 && ins != 17 && ins != 20 && ins != 21 && ins != 22" v-model="proJuctId" :placeholder="$t('defaultText.pleaseSelectSnItem')" clearable filterable size="small" @change="projectChange()" style="margin-left:10px">
           <el-option v-for="(item) in proListOvertime" :key="item.id" :label="item.projectName + (item.projectCode ? item.projectCode : '')" :value="item.id">
             <span style="float: left;color: #8492a6;">{{ item.projectCode }}</span>
             <span style="float: right;font-size: 13px;margin-left: 20px">{{ item.projectName }}</span>
           </el-option>
         </el-select>
+
+        <!-- 任务分组 -->
+        <el-select v-if="ins == 1 && user.companyId == '3092'" v-model="projectGroupId" :placeholder="'请选择任务分组'" clearable filterable size="small" @change="getList(true)" style="margin-left:10px">
+          <el-option v-for="(item) in projectTaskgroupList" :key="item.id" :label="item.name" :value="item.id"></el-option>
+        </el-select>
+
         <el-select v-if="ins==12 && user.companyId==936" v-model="projectCategorySubId" :placeholder="'请选择自主项目类别'" clearable filterable size="small" @change="selcts()" style="margin-left:10px">
           <el-option v-for="(item) in projectCategorySubList" :key="item.value" :label="item.label" :value="item.value"></el-option>
         </el-select>
@@ -137,7 +157,7 @@
             <el-option v-for="(item, index) in selUserList" :key="index" :label="item.name" :value="item.id"></el-option>
           </el-select>
 
-          <selectCat :subject="selUserList" :subjectId="userId" :clearable="true" :size="mini" @selectCal="selectCal" v-if="(ins == 6 || ins == 8 || ins == 9 || ins == 10 || ins == 11 || ins == 14 || ins == 18) && user.userNameNeedTranslate == '1'"></selectCat>
+          <selectCat :subject="selUserList" :filterable="true" :searchBoxTop="'1'" :subjectId="userId" :clearable="true" :size="mini" @selectCal="selectCal" v-if="(ins == 6 || ins == 8 || ins == 9 || ins == 10 || ins == 11 || ins == 14 || ins == 18) && user.userNameNeedTranslate == '1'"></selectCat>
           
 
           <!-- 待审核筛选切换 -->
@@ -152,9 +172,10 @@
       </div>
       <!-- <p :style="ins == 9 ? 'float: right;margin-right: 25px;width:20%' : 'float: right;margin-right: 25px;width:10%'" > -->
       <p :style="`${ins == 9 ? 'width:20%' : ins == 14 ? 'width: 20%' : 'width: 10%'}`" class="tableRightBtn">
-        <el-button type="primary" @click="exportExcel" size="mini">{{ $t('reporderived') }}</el-button>
+        <el-button type="primary" @click="exportExcel" size="mini" v-if="ins != 21">{{ $t('reporderived') }}</el-button>
         <el-button type="primary" @click="fillAll" size="mini" v-if="ins == 14">全部补足</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">设置预警</el-button>
       </p>
       
     </div>
@@ -263,6 +284,18 @@
                         {{scope.row.end_date}}
                     </template>
                 </el-table-column>
+                <span v-if="user.companyId == '3092'">
+                  <el-table-column prop="group_plan_hours" :label="'分组预估工时(h)'"  width="150">
+                      <template slot-scope="scope">
+                          {{scope.row.group_plan_hours}}
+                      </template>
+                  </el-table-column>
+                  <el-table-column prop="group_real_hours" :label="'分组实际工时(h)'"  width="150">
+                      <template slot-scope="scope">
+                          {{scope.row.group_real_hours}}
+                      </template>
+                  </el-table-column>
+                </span>
             </el-table>
 
             <!--项目成本报表 -->
@@ -687,7 +720,10 @@
                 <el-table-column prop="departmentName" :label="$t('subordinatedepartments')" min-width="200" align="center">
                   <template slot-scope="scope" >
                     <span v-if="user.userNameNeedTranslate == '1'">
-                      <ww-open-data type='departmentName' :openid='scope.row.departmentName'></ww-open-data>
+                      <span v-for="(item,index) in scope.row.departmentName" :key="index">
+                        <ww-open-data type='departmentName' :openid='item'></ww-open-data>
+                        <span v-if="index < scope.row.departmentName.length - 1">/</span>
+                      </span>
                     </span>
                     <span v-if="user.userNameNeedTranslate != '1'">
                       {{scope.row.departmentName}}
@@ -925,8 +961,96 @@
                 </el-table-column>
                 <el-table-column align="center" prop="rate" label="有效工时率" min-width="150"></el-table-column>
             </el-table>
+
+            <!-- 项目分类工时占比表 -->
+            <el-table  v-if="ins == 21" :key="projectCateRatioListKey" border :data="projectCateRatioList.userList" highlight-current-row v-loading="listLoading" :height="(+tableHeight + 50) - 1" style="width: 100%;" >
+              <el-table-column align="center" prop="name" label="人员" min-width="150" fixed="left">
+                <template slot-scope="scope">
+                  <div>
+                    <span v-if="user.userNameNeedTranslate == '1'">
+                      <ww-open-data type='userName' :openid='scope.row.userName'></ww-open-data>
+                    </span>
+                    <span v-if="user.userNameNeedTranslate != '1'">
+                      {{scope.row.userName}}
+                    </span>
+                  </div>
+                </template>
+              </el-table-column>
+              <el-table-column align="center" prop="workingTime" label="总工时" min-width="150">
+                <template slot-scope="scope">
+                  {{ scope.row.workingTime }} h
+                </template>
+              </el-table-column>
+              <el-table-column align="center" prop="s" :label="item.name" min-width="150" v-for="item in projectCateRatioList.categoryList" :key="item.id">
+                <template slot-scope="scope">
+                  <div v-for="v,i in scope.row.cateTimeList || []" :key="i">
+                    <div v-if="item.name == v.categoryName && v.categoryName" :style="`color: ${v.warning ? 'red' : ''}`">
+                      <div>工时: {{ v.workingTime }} h </div>
+                      <div>占比: {{ v.percent | schedulePercentage }} % </div>
+                    </div>
+                    <div v-if="!v.categoryName && item.name == '未分类'" :style="`color: ${v.warning ? 'red' : ''}`">
+                      <div>工时: {{ v.workingTime }} h </div>
+                      <div>占比: {{ v.percent | schedulePercentage }} % </div>
+                    </div>
+                  </div>
+                </template>
+              </el-table-column>
+            </el-table>
+
+            <!-- 分类工时明细表 -->
+            <el-table  v-if="ins == 22" :key="hoursDetailClassListKey" border :data="hoursDetailClassList.record" highlight-current-row v-loading="listLoading" :height="+tableHeight -1" style="width: 100%;" >
+              <el-table-column align="center" prop="projectCode" :label="`${projectSortName}项目号`" min-width="150"></el-table-column>
+              <el-table-column align="center" prop="userName" label="姓名" min-width="150">
+                <template slot-scope="scope">
+                  <div>
+                    <span v-if="user.userNameNeedTranslate == '1'">
+                      <ww-open-data type='userName' :openid='scope.row.userName'></ww-open-data>
+                    </span>
+                    <span v-if="user.userNameNeedTranslate != '1'">
+                      {{scope.row.userName}}
+                    </span>
+                  </div>
+                </template>
+              </el-table-column>
+              <el-table-column align="center" prop="deptName" label="部门" min-width="150">
+                <template slot-scope="scope">
+                  <div>
+                    <span v-if="user.userNameNeedTranslate == '1'">
+                      <ww-open-data type='departmentName' :openid='scope.row.deptName'></ww-open-data>
+                    </span>
+                    <span v-if="user.userNameNeedTranslate != '1'">
+                      {{scope.row.userName}}
+                    </span>
+                  </div>
+                </template>
+              </el-table-column>
+
+              <!-- 渲染自定义字段 -->
+              <el-table-column align="center" :label="item.titleName" min-width="150" v-for="(item, index) in hoursDetailClassList.custom" :key="index">
+                <template slot-scope="scope">
+                  <div v-if="processingJudgment(item.titleIndex, scope.row, false)">
+                    {{ scope.row[item.titleIndex] || '' }}
+                  </div>
+                </template>
+              </el-table-column>
+
+              <el-table-column align="center" prop="allWorkingTime" label="总工时" min-width="150"></el-table-column>
+              <el-table-column align="center" prop="targetWorkingTime" :label="`${projectSortName}工时`" min-width="150"></el-table-column>
+
+              <!-- 渲染日期 -->
+              <el-table-column align="center" :label="item.titleName" min-width="150" v-for="(item, index) in hoursDetailClassList.header" :key="index">
+                <template slot-scope="scope">
+                  <div v-for="v,i in scope.row.dataList || []" :key="i">
+                    <div v-if="processingJudgment(item.titleIndex, v, true)">
+                      {{ v.workingTime ? `${v.workingTime} h` : '' }}
+                    </div>
+                  </div>
+                </template>
+              </el-table-column>
+
+            </el-table>
         <!--工具条-->
-        <el-col :span="24" class="toolbar" v-if="ins != 6 && ins != 20">
+        <el-col :span="24" class="toolbar" v-if="ins != 6 && ins != 20 && ins != 21">
           <el-pagination
                 v-if="ins == 12"
                 @size-change="groupSizeChange"
@@ -1008,6 +1132,7 @@
             </div>
         </el-dialog>
         <el-dialog :title="curProject.projectName+'-'+$t('detailsofreimbursementexpenses')" show-summary=true v-if="detailVisible" :summary-method="getSummaries" :visible.sync="detailVisible" :close-on-click-modal="false" customClass="customWidth" width="1000px">
+        <div><el-button size="mini" @click="exportExpenseDetail" style="float:right" type="primary">导出</el-button></div>
         <el-table  :key="ins" border :data="detailList" highlight-current-row v-loading="detailListLoading" :height="500" style="width: 100%;">
                 <el-table-column  prop="username" :label="$t('screening.employeename')"  >
                   <template slot-scope="scope" >
@@ -1139,6 +1264,33 @@
             <el-button @click.native="quarterExport" :loading="exportLoading" type="primary">{{ $t('export.export') }}</el-button>
           </div>
         </el-dialog>
+
+        <!-- 设置预警弹窗 -->
+        <el-dialog title="设置预警" :visible.sync="setWarningModal" width="600px" :before-close="handleClose">
+          <div>
+            <el-form ref="warningFrom" :model="warningFrom" label-width="120px">
+              <el-form-item label="提醒分类:">
+                <el-select v-model="warningFrom.monitorCategoryId" placeholder="请选择提醒分类">
+                  <el-option v-for="item in projectCateRatioList.categoryList" :key="item.id" :label="item. name" :value="item.id"></el-option>
+                </el-select>
+              </el-form-item>
+              <el-form-item label="选择关系:">
+                <el-radio v-model="warningFrom.moreOrLess" :label="0">低于</el-radio>
+                <el-radio v-model="warningFrom.moreOrLess" :label="1">高于</el-radio>
+              </el-form-item>
+              <el-form-item label="设置占比:">
+                <div class="sliderSetup">
+                  <el-slider v-model="warningFrom.ratio" style="width: 340px"></el-slider>
+                  <div class="text">{{ warningFrom.ratio }} %</div>
+                </div>
+              </el-form-item>
+            </el-form>
+          </div>
+          <span slot="footer" class="dialog-footer">
+            <el-button @click="setWarningModal = false">取 消</el-button>
+            <el-button type="primary" @click="setForewarning()" :loading="warningTableLoading">确 定</el-button>
+          </span>
+        </el-dialog>
   </section>
 </template>
 
@@ -1187,8 +1339,10 @@ export default {
       list1:[],
       listArr1:[],
       listArr2:[],
+      listArr3:[],
       listPosition1:0,
       listPosition2:0,
+      listPosition3:0,
       windowHeight: document.documentElement.clientHeight,
       windowWidth: document.documentElement.clientWidth,
 
@@ -1212,13 +1366,13 @@ export default {
       this.$t('pojectbalancesheetincomestatement'),this.$t('customerprojectprofitstatement'),this.$t('projectphasetimesheet'),
       this.$t('statisticsofovertimework'),this.$t('timecostearlywarningtable'),this.$t('personneltimeallocationtable'),
       this.$t('statisticsofstafffillingintimerate'),this.$t('dailyreporttobereviewedstatistics'),this.$t('statisticsofpersonnelhours'),this.$t('taskgrouptimesheet'),this.$t('projectcostbaselinetable'),
-      this.$t('ren-yuan-yue-du-gong-shi-biao'), this.$t('bumenchanyuqingkuang'), this.$t('ge-fen-zu-yu-jie-duan-gong-shi-biao'), '子项目工时成本表', '任务重启表', 'FTE报表', '有效工时率表'],
+      this.$t('ren-yuan-yue-du-gong-shi-biao'), this.$t('bumenchanyuqingkuang'), this.$t('ge-fen-zu-yu-jie-duan-gong-shi-biao'), '子项目工时成本表', '任务重启表', 'FTE报表', '有效工时率表', '项目分类工时占比表', '分类工时明细表'],
 
       shuzArr: [this.$t('projectreport'),this.$t('projectTaskReport'),this.$t('projectcoststatement'),
       this.$t('projectbalancesheet'),this.$t('customerprojectincomestatement'),this.$t('projectphasetimesheet'),
       this.$t('statisticsofovertimework'),this.$t('timecostearlywarningtable'),this.$t('personneltimeallocationtable'),
       this.$t('employeereporttimelinessrate'),this.$t('dailyreporttobereviewedstatistics'),this.$t('statisticsofpersonnelhours'),this.$t('taskgrouptimesheet'),this.$t('projectcostbaselinetable'),
-      this.$t('ren-yuan-yue-du-gong-shi-biao'), this.$t('bumenchanyuqingkuang'), this.$t('ge-fen-zu-yu-jie-duan-gong-shi-biao'), '子项目工时成本表', '任务重启表', 'FTE报表','有效工时率表'],
+      this.$t('ren-yuan-yue-du-gong-shi-biao'), this.$t('bumenchanyuqingkuang'), this.$t('ge-fen-zu-yu-jie-duan-gong-shi-biao'), '子项目工时成本表', '任务重启表', 'FTE报表','有效工时率表', '项目分类工时占比表', '分类工时明细表'],
 
       ins: 10000,
       user: JSON.parse(sessionStorage.user),
@@ -1310,8 +1464,35 @@ export default {
               label: '服务项目'
           }
       ],
-      projectCategorySubId:''
-
+      projectCategorySubId:'',
+
+      projectCateRatioList: {
+        categoryList: [],
+        userList: []
+      }, // 项目分类工时占比表数据
+      setWarningModal: false, // 设置预警弹窗
+      warningTableLoading: false, // 预警表格loading
+      warningFrom: {}, // 预警表单
+      projectCateRatioListKey: 120,
+      forewarningTableList: [{
+        radio: 0,
+        slider: 0,
+      }], // 预警表格数据
+      hoursDetailClassList: {
+        header: [],
+        record: [],
+        custom: []
+      }, // 分类工时明细表数据
+      hoursDetailClassListKey: 500,
+      dateSelect: '', // 日期选择
+      projectSortId: '', // 项目分类选中的id
+      projectSortName: '', // 项目分类选中的Name
+      projectSortList: [], // 项目分类
+
+      projectTaskgroupList: [], // 选择项目的任务分组
+      projectGroupId: '', // 选择项目的任务分组id
+
+      detailProjectId:null,//报销费用详情项目id
     };
   },
   computed: {},
@@ -1326,6 +1507,12 @@ export default {
   },
 
   mounted() {
+    var myDate = new Date();
+    let year = myDate.getFullYear();
+    let month = +myDate.getMonth() + 1
+    let yue = month >= 10 ? yue = month : yue = '0' + month
+    this.monthPersonnel = year + '-' + yue
+
     this.getProjectListOvertime()
     // this.getProjectList();
     // this.getUserList()
@@ -1333,12 +1520,7 @@ export default {
     this.getcustomerList()
     // this.getcusProjectList()
     this.authorityToJudge()
-
-    var myDate = new Date();
-    let year = myDate.getFullYear();
-    let month = +myDate.getMonth() + 1
-    let yue = month >= 10 ? yue = month : yue = '0' + month
-    this.monthPersonnel = year + '-' + yue
+    this.getProjectSort()
   },
   filters: {
       numberToCurrency(value) {
@@ -1379,6 +1561,12 @@ export default {
           }
         }
         return str
+      },
+      schedulePercentage(value) {
+        if(!value) {
+          return ''
+        }
+        return value.toFixed(0)
       }
   },
   methods: {
@@ -1396,13 +1584,16 @@ export default {
       if(this.permissions.reportTimely || this.permissions.reportAllTimely) {this.ssl(9);this.defaultActive = '1-10';return} else
       if(this.permissions.reportAllGroup || this.permissions.reportGroup) {this.ssl(12);this.defaultActive = '1-13';return} else
       if(this.permissions.reportAuditRate) {this.ssl(10);this.defaultActive = '1-11';return} else 
-      if(this.permissions.reportPersonnel || this.permissions.reportResponsible) {this.ssl(11);this.defaultActive = '1-12';return}
-      if(this.permissions.reportMonthlyPersonnel || this.permissions.reportResponsiblePersonnel) {this.ssl(14);this.defaultActive = '1-15';return}
-      if(this.permissions.reportAllDepartmentParticipation || this.permissions.reportResponsibleDepartmentParticipation) {this.ssl(15);this.defaultActive = '1-16';return}
-      if(this.permissions.reportPhaseHours || this.permissions.reportStageWorkingTime) {this.ssl(16);this.defaultActive = '1-17';return}
-      if(this.permissions.reportAllManhourCost || this.permissions.reportResponsibleManhourCost) {this.ssl(17);this.defaultActive = '1-18';return}
-      if(this.user.timeType.restartTaskNeedReason == 1) {this.ssl(18);this.defaultActive = '1-19';return}
-      if(this.permissions.reportFTEAll || this.permissions.reportFTEPart) {this.ssl(19);this.defaultActive = '1-20';return}
+      if(this.permissions.reportPersonnel || this.permissions.reportResponsible) {this.ssl(11);this.defaultActive = '1-12';return} else
+      if(this.permissions.reportMonthlyPersonnel || this.permissions.reportResponsiblePersonnel) {this.ssl(14);this.defaultActive = '1-15';return} else
+      if(this.permissions.reportAllDepartmentParticipation || this.permissions.reportResponsibleDepartmentParticipation) {this.ssl(15);this.defaultActive = '1-16';return} else
+      if(this.permissions.reportPhaseHours || this.permissions.reportStageWorkingTime) {this.ssl(16);this.defaultActive = '1-17';return} else
+      if(this.permissions.reportAllManhourCost || this.permissions.reportResponsibleManhourCost) {this.ssl(17);this.defaultActive = '1-18';return} else
+      if(this.user.timeType.restartTaskNeedReason == 1) {this.ssl(18);this.defaultActive = '1-19';return} else
+      if(this.permissions.reportFTEAll || this.permissions.reportFTEPart) {this.ssl(19);this.defaultActive = '1-20';return} else
+      if(this.permissions.reportEfficent) {this.ssl(20);this.defaultActive = '1-21';return} else
+      if(this.permissions.reportSortScaleTable) {this.ssl(21);this.defaultActive = '1-22';return} else
+      if(this.permissions.reportSortDetailTable || this.permissions.reportSortSectionDetailTable) {this.ssl(22);this.defaultActive = '1-23';return} else
       {this.allWrong = false}
     },
     rowspan(spanArr,position,spanName){
@@ -1422,6 +1613,7 @@ export default {
       })
     },
     objectSpanMethod({ row, column, rowIndex, columnIndex }){
+      const { companyId } = this.user
       if(columnIndex == 0){
         const _row = this.listArr1[rowIndex]
         const _col = _row > 0 ? 1 : 0
@@ -1438,6 +1630,14 @@ export default {
           colspan: _col
         }
       }
+      if(columnIndex == 2 && companyId == '3092') {
+        const _row = this.listArr3[rowIndex]
+        const _col = _row > 0 ? 1 : 0
+        return {
+          rowspan: _row,
+          colspan: _col
+        }
+      }
     },
 
     getCustomName(){
@@ -1560,6 +1760,7 @@ export default {
       this.curProject = row;
       this.detailListLoading = true;
       this.detailVisible = true;
+      this.detailProjectId=row.id;
       this.http.post('/expense-item/list', {projectId: row.id},
             res => {
               this.detailListLoading = false;
@@ -1579,6 +1780,30 @@ export default {
                 });
             });
     },
+    exportExpenseDetail(){
+      this.http.post("/expense-item/exportData", {projectId:this.detailProjectId},
+        res => {
+            if (res.code == "ok") {
+                var filePath = res.data;
+                const a = document.createElement('a'); // 创建a标签
+                a.setAttribute('download', '费用报销明细表.xlsx');// download属性
+                a.setAttribute('href', filePath);// href链接
+                a.click(); //自执行点击事件
+                a.remove();
+            } else {
+                this.$message({
+                message: res.msg,
+                type: "error"
+                });
+            }
+        },
+        error => {
+            this.$message({
+                message: error,
+                type: "error"
+            });
+        });
+    },
     expandRow(row, index) {
       this.title = this.$t('ke-hu')+':'+row.customerName;
         this.childrenList = row.children;
@@ -1674,9 +1899,15 @@ export default {
                 } else if (this.ins == 20) {
                   this.getEffectiveLaborHourRate();
                 }
-                if(this.ins != 16 && this.ins != 17 && this.ins != 18 && this.ins != 19 && this.ins != 20) {
+                if(this.ins != 16 && this.ins != 17 && this.ins != 18 && this.ins != 19 && this.ins != 20 && this.ins != 21 && this.ins != 22) {
                   this.getUserList()
                 }
+                if(this.ins == 21) {
+                  this.getProjectWoekScale()
+                }
+                if(this.ins == 22) {
+                  this.getHoursDetailClass()
+                }
             },
       exportExcel() {
         var url = "/project";
@@ -1819,6 +2050,12 @@ export default {
           url += "/exportFTEData"
           sl.month = this.monthPersonnel + '-01'
           sl.area = this.areaName || null
+        } else if(this.ins == 22) {
+          fName = '分类工时明细表' + '.xlsx'
+          url = "/report/exportUserWorkTimeByCategory"
+          sl.categoryId = this.projectSortId
+          sl.startDate = this.rangeDatas[0]
+          sl.endDate = this.rangeDatas[1]
         }
           this.http.post(url, sl,
             res => {
@@ -2340,6 +2577,7 @@ export default {
     },
     getProjectTask() {
       this.listLoading = true;
+      const { companyId } = this.user
       let ginseng = {
         pageIndex: this.page,
         pageSize: this.size,
@@ -2348,9 +2586,13 @@ export default {
       if(this.taskTypeId != 'null' && this.taskTypeId != null && this.taskTypeId != '') {
         ginseng.taskType = this.taskTypeId
       }
+      if(companyId == '3092') {
+        ginseng.groupId = this.projectGroupId
+      }
       this.http.post('/project/getProjectTask', ginseng,
         res => {
             if (res.code == "ok") {
+              const { companyId } = this.user
               for(var i in res.data.records) {
                 if(i > 0 && (res.data.records[i].project_code == res.data.records[i - 1].project_code)) {
                   res.data.records[i].customCode = '——'
@@ -2371,10 +2613,15 @@ export default {
                 this.list1 = res.data.records;
                 this.listArr1 = []
                 this.listArr2 = []
+                this.listArr3 = []
                 this.listPosition1 = 0
                 this.listPosition2 = 0
+                this.listPosition3 = 0
                 this.rowspan(this.listArr1,this.listPosition1,'project_code')
                 this.rowspan(this.listArr2,this.listPosition2,'project_name')
+                if(companyId == 3092) {
+                  this.rowspan(this.listArr3,this.listPosition3,'groupId')
+                }
                 this.total = res.data.total;
                 this.listLoading = false; 
             } else {
@@ -2594,7 +2841,16 @@ export default {
         res => {
           this.listLoading = false
           if(res.code == 'ok'){
-            this.auditRateList = res.data.result
+            const { userNameNeedTranslate } = this.user
+            if(userNameNeedTranslate == 1) {
+              res.data.result.forEach((item) => {
+                item.departmentName = item.departmentName.split('/') || []
+              })
+              this.auditRateList = res.data.result
+              console.log('处理好的 ==>', this.auditRateList)
+            } else {
+              this.auditRateList = res.data.result
+            }
             this.total = res.data.total
           }else {
             this.$message({
@@ -2886,6 +3142,14 @@ export default {
       if (this.ins == 20) {
         this.getEffectiveLaborHourRate();
       }
+      if(this.ins == 21) {
+        this.getProjectWoekScale()
+      }
+      if(this.ins == 22) {
+        this.projectSortName = this.projectSortList.filter((item) => item.id == this.projectSortId)[0].name
+        console.log(this.projectSortName)
+        this.getHoursDetailClass()
+      }
     },
     // 任务重启表
     taskRestart() {
@@ -2933,6 +3197,15 @@ export default {
         _this.gettime = [time1 , time2];
         return  _this.gettime
     },
+    projectChange() {
+      const { companyId } = this.user
+      if(this.ins == 1 && companyId == '3092') {
+        this.projectTaskgroupList == []
+        this.projectGroupId = ''
+        this.getProjectTaskgroupList()
+      }
+      this.selcts()
+    },
     selcts(e) {
       this.page = 1
       if(this.ins == 12){
@@ -3076,11 +3349,150 @@ export default {
           type: 'error'
         })
       })
-    }
+    },
+    // 设置预警
+    setWarning() {
+      this.setWarningModal = true
+      this.getForewarningTableList()
+    },
+    // 单独封装请求
+    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)
+          }
+        )
+      });
+    },
+    // 获取项目分类工时占比表
+    async getProjectWoekScale() {
+      let params = {
+        startDate: this.rangeDatas[0],
+        endDate: this.rangeDatas[1],
+        onlyShowWarning: 0
+      }
+      this.listLoading = true
+      let { data } = await this.postData('/project/getMembProjectCateRatio', params)
+      let { categoryList, userList } = data
+      categoryList.push({
+        id: 999999,
+        name: '未分类'
+      })
+      this.listLoading = false
+      this.projectCateRatioList = {
+        categoryList,
+        userList
+      }
+      this.projectCateRatioListKey++
+    },
+    // 获取设置预警
+    async getForewarningTableList() {
+      const { companyId } = this.user
+      this.warningTableLoading = true
+      let { data } = await this.postData('/category-ratio-tbl-setting/get', { companyId })
+      const { monitorCategoryId, moreOrLess, ratio } = data
+      this.warningFrom = {
+        companyId,
+        monitorCategoryId,
+        moreOrLess: moreOrLess || 0,
+        ratio: ratio || 0
+      }
+      this.warningTableLoading = false
+    },
+    // 设置预警
+    async setForewarning() {
+      this.warningTableLoading = true
+      await this.postData('/category-ratio-tbl-setting/update', this.warningFrom)
+      this.getProjectWoekScale()
+      this.setWarningModal = false
+      this.warningTableLoading = false
+    },
+    // 获取分类工时明细表
+    async getHoursDetailClass() {
+      let params = {
+        // 日期, 项目分类
+        categoryId: this.projectSortId || 0,
+        startDate: this.rangeDatas[0],
+        endDate: this.rangeDatas[1],
+        pageIndex: this.page,
+        pageSize: this.size,
+      }
+      this.listLoading = true
+      let { data } = await this.postData('/report/getUserWorkTimeByCategory', params)
+      this.hoursDetailClassListKey++
+      this.hoursDetailClassList = data
+      this.total = data.total
+      this.listLoading = false
+    },
+    processingJudgment(fields, item, date) {
+      if(!date) {
+        for(var i in item) {
+          if(i == fields) {
+            // return item[fields]
+            return true
+          }
+        }
+
+        return false
+      }
+
+      if(date) {
+        if(item.createDate == fields) {
+          // return item.workingTime
+          return true
+        }
+
+        return false
+      }
+      
+      return ''
+    },
+    // 获取项目分类
+    async getProjectSort() {
+      let { data } = await this.postData('/project-category/list', {})
+      let dataList = data || []
+      dataList.push({id: 0, name: '未分类'})
+      this.projectSortList = dataList
+      this.projectSortId = dataList[0].id
+      this.projectSortName = dataList[0].name
+    },
+    // 获取任务分组
+    async getProjectTaskgroupList() {
+      let { data } = await this.postData('/task-group/list', {
+        projectId: this.proJuctId
+      })
+      this.projectTaskgroupList = data
+    },
   },
 };
 </script>
 <style scoped>
+.sliderSetup {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  .text {
+    color: #409EFF;
+    margin-right: 20px;
+  }
+}
 .tableRightBtn {
   float: right;
   margin-left: 15px !important;
@@ -3100,6 +3512,7 @@ export default {
   justify-content: space-between;
   align-items: center;
   z-index: 2;
+  margin-top: 5px;
 }
 .headine h3 {
   margin: 0;

+ 125 - 22
fhKeeper/formulahousekeeper/timesheet/src/views/expense/expense.vue

@@ -103,32 +103,30 @@
               </el-form-item>
               <!-- 第一审核人 -->
               <el-form-item label="第一审核人" v-if="auditTypeItem.auditType == 2">
-                <!--普通员工只能自己填报自己的 -->
                 <el-select v-if="user.userNameNeedTranslate != '1'" v-model="addForm.firstCheckerId"
-                  :placeholder="$t('pleaseselecttheapplicant')" style="width: 150px"
+                  :placeholder="'请选择审核人'" style="width: 150px"
                   filterable="true">
-                  <span v-for="(item, index) in users" :key="index">
+                  <span v-for="(item, index) in usersNoInfo" :key="index">
                     <el-option :label="item.name" :value="item.id"></el-option>
                   </span>
                 </el-select>
 
                 <selectCat v-if="user.userNameNeedTranslate == '1'" :size="'medium'" :widthStr="'150'" :distinction="'4'"
-                  :subject="users" :subjectId="addForm.firstCheckerId" ref="selectCat" 
+                  :subject="usersNoInfo" :subjectId="addForm.firstCheckerId" ref="selectCat" 
                   @selectCal="selectCal"></selectCat>
               </el-form-item>
               <!-- 第一审核人 -->
               <el-form-item label="第二审核人" v-if="auditTypeItem.auditType == 2">
-                <!--普通员工只能自己填报自己的 -->
                 <el-select v-if="user.userNameNeedTranslate != '1'" v-model="addForm.secondCheckerId"
-                  :placeholder="$t('pleaseselecttheapplicant')" style="width: 150px"
+                  :placeholder="'请选择审核人'" style="width: 150px"
                   filterable="true">
-                  <span v-for="(item, index) in users" :key="index">
+                  <span v-for="(item, index) in usersNoInfo" :key="index">
                     <el-option :label="item.name" :value="item.id"></el-option>
                   </span>
                 </el-select>
 
                 <selectCat v-if="user.userNameNeedTranslate == '1'" :size="'medium'" :widthStr="'150'" :distinction="'5'"
-                  :subject="users" :subjectId="addForm.secondCheckerId" ref="selectCat" 
+                  :subject="usersNoInfo" :subjectId="addForm.secondCheckerId" ref="selectCat" 
                   @selectCal="selectCal"></selectCat>
               </el-form-item>
               <!-- 备注 -->
@@ -258,11 +256,21 @@
       <div class="dayImge">
         <div class="dayImgeItem" v-if="dialogVisibleImageList">
           <viewer :images="dialogVisibleImageList" v-viewer="viewerOptions" class="dayImgeItem">
-            <div class="xiaoImg" v-for="src,i in dialogVisibleImageList" :key="i">
-              <img ref="imgsa" :src="src.url">
-              <div class="imgIcon" @click.stop="deteleIpc(apl)" v-if="imgLoadType==1"><i class="el-icon-circle-close"></i></div>
-              <div class="imgIcon" @click.stop="deteleIpc(apl, 'ParticularsList', 'invoiceList')" v-if="imgLoadType==2"><i class="el-icon-circle-close"></i></div>
-            </div>
+            <template v-for="src,i in dialogVisibleImageList" :id="src.url">
+              <!-- 图片 -->
+              <div class="xiaoImg" v-if="isFileType(src.url) == 'image'">
+                <img ref="imgsa" :src="src.url">
+                <div class="imgIcon" @click.stop="deteleIpc(apl)" v-if="imgLoadType==1"><i class="el-icon-circle-close"></i></div>
+                <div class="imgIcon" @click.stop="deteleIpc(apl, 'ParticularsList', 'invoiceList')" v-if="imgLoadType==2"><i class="el-icon-circle-close"></i></div>
+              </div>
+
+              <!-- 文件 -->
+              <div class="xiaoImg" v-if="isFileType(src.url) == 'pdf'" @click.stop="openViewPdf(src.url)">
+                <img :src="pdfIcons">
+                <div class="imgIcon" @click.stop="deteleIpc(apl)" v-if="imgLoadType==1"><i class="el-icon-circle-close"></i></div>
+                <div class="imgIcon" @click.stop="deteleIpc(apl, 'ParticularsList', 'invoiceList')" v-if="imgLoadType==2"><i class="el-icon-circle-close"></i></div>
+              </div>
+            </template>
             <img @click.stop="performCustomization(apl, imgLoadType)" v-if="dialogVisibleImageList.length < 10" :src="require('../../assets/image/aacbc.png')" class="xiaoImg" style="margin-right: 0" />
           </viewer>
         </div>
@@ -342,8 +350,8 @@
             v-loading="listLoading" :height="tableHeight - currentClickNum" style="width: 100%;"
             :summary-method="getSummaries" show-summary>
             <el-table-column type="selection" width="55"></el-table-column>
-            <el-table-column prop="code" :label="$t('ticketnumber')"></el-table-column>
-            <el-table-column prop="totalAmount" :label="$t('amountof') + '(' + $t('yuan') + ')'" align="center">
+            <el-table-column prop="code" :label="$t('ticketnumber')" width="120"></el-table-column>
+            <el-table-column prop="totalAmount" :label="$t('amountof') + '(' + $t('yuan') + ')'" align="center" width="120">
               <template slot-scope="scope">
                 <span style="float:right;margin-right:20px">{{ scope.row.totalAmount ? scope.row.totalAmount.toFixed(2) :
                   '0' }}</span>
@@ -361,7 +369,7 @@
                 </div>
               </template>
             </el-table-column>
-            <el-table-column prop="createDate" :label="$t('fillinthedate')"></el-table-column>
+            <el-table-column prop="createDate" :label="$t('fillinthedate')" width="100"></el-table-column>
             <el-table-column prop="ticketNum" :label="$t('invoicenumber')"
               v-if="this.user.timeType.easyExpense == 0"></el-table-column>
             <el-table-column prop="type" :label="$t('ppertype')" v-if="this.user.timeType.easyExpense == 0">
@@ -381,6 +389,13 @@
                 <span v-if="scope.row.status == 0 || scope.row.status == 3">{{ statusTxt[scope.row.status] }}</span>
               </template>
             </el-table-column>
+            <el-table-column prop="reviewProcess" :label="'审核流程'" width="180" v-if="auditTypeItem.auditType == 2">
+              <template slot-scope="scope">
+                <span v-if="scope.row.reviewProcess == 0">待第一审核人审核</span>
+                <span v-if="scope.row.reviewProcess == 1">待第二审核人审核</span>
+                <span v-if="scope.row.reviewProcess == 2">审核完成</span>
+              </template>
+            </el-table-column>
             <!-- <el-table-column prop="denyReason" :label="$t('dismissreason')" width="180">
                 <template slot-scope="scope">
                   <span style="font-size:12px;">{{scope.row.denyReason}}</span>
@@ -392,6 +407,8 @@
                   '未发放' }}</span>
               </template>
             </el-table-column>
+            <el-table-column prop="payWayName" label="支付方式" width="80" v-if="permissions.costExpenseRelease">
+            </el-table-column>
             <el-table-column fixed="right" :label="$t('operation')" :width="isAuditList ? 220 : 160">
               <template slot-scope="scope">
                 <div v-if="!isAuditList">
@@ -955,7 +972,8 @@
             <div class="detail-item" v-if="auditTypeItem.auditType != 1">
               <span class="detail-item-title"> <span class="printBox">项目</span> </span>
               <span class="detail-item-content">
-                <el-select size="small" v-if="!flg" v-model="item.projectId" :placeholder="$t('other.project')"
+                {{ item.projectName }}
+                <!-- <el-select size="small" v-if="!flg" v-model="item.projectId" :placeholder="$t('other.project')"
                   style="width: 130px">
                   <el-option v-for="(item, index) in projectList" :key="index"
                     :label="item.projectName + item.projectCode" :value="item.id" @click="ok(item)">
@@ -967,7 +985,7 @@
                   <div v-for="(item, index) in projectIdName" :key="index">
                     <span v-if="item.id == item.projectId">{{ item.projectName }}</span>
                   </div>
-                </div>
+                </div> -->
               </span>
             </div>
             <div class="detail-item" v-if="auditTypeItem.auditType == 1">
@@ -1019,7 +1037,10 @@
                       <img ref="imgsa" v-for="src in item.pic" :src="src.url" :key="src.title">
                     </viewer> -->
                     <viewer :images="item.pic">
-                      <img ref="imgsa" v-for="src in item.pic" :src="src.url" :key="src.title">
+                      <template v-for="src,i in item.pic" :id="src.url">
+                        <img ref="imgsa" :src="src.url" v-if="isFileType(src.url) == 'image'">
+                        <img :src="pdfIcons" v-if="isFileType(src.url) == 'pdf'" @click.stop="openViewPdf(src.url)">
+                      </template>
                     </viewer>
                   </div>
                 </div>
@@ -1036,8 +1057,21 @@
 
     <!-- 自定义图片上传 -->
     <div class="customIamgeLoad">
-      <input id="uploadInput" ref="uploadInput" type="file" class="file" @change="fileMultLoad" multiple accept="image/jpg,image/png" />
+      <input id="uploadInput" ref="uploadInput" type="file" class="file" @change="fileMultLoad" multiple accept="image/jpg,image/png,application/pdf" />
     </div>
+
+    <!-- 发放支付方式 -->
+    <el-dialog title="发放方式" :visible.sync="dialogVisibleRelease" width="400px" :before-close="handleClose">
+      <div>
+        <el-select v-model="releaseData.id" placeholder="请选择支付方式" style="width: 100%" clearable>
+          <el-option v-for="item in sendStateList" :key="item.id" :label="item.name" :value="item.id"></el-option>
+        </el-select>
+      </div>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="dialogVisibleRelease = false">取 消</el-button>
+        <el-button type="primary" @click="callingInterface(1, releaseData.data)">确 定</el-button>
+      </span>
+    </el-dialog>
   </section>
 </template>
 
@@ -1057,6 +1091,7 @@ export default {
   props: {},
   data() {
     return {
+      pdfIcons: require('@/assets/image/pdfIcon.png'),
       showSingleAudit: false,
       auditTypeItem: { auditType: 0 },
       queryExpenseMainType: null,
@@ -1092,6 +1127,7 @@ export default {
       type: null,
       ownerId: null,
       users: [], // 人员信息
+      usersNoInfo: [], // 人员信息,去掉自己
       displayTable: false,
       getLists: [],
       ProjectList: [], // 项目列表
@@ -1149,6 +1185,13 @@ export default {
       dialogVisibleImage: false,
       dialogVisibleImageList: [],
       imgLoadType: 1, // 1 为 费用填报的图片上传 2 单据修改的图片上传
+
+      releaseData: {
+        id: '',
+        data: '',
+      }, // 发放数据
+      sendStateList: [], // 发放状态列表
+      dialogVisibleRelease: false, // 发放弹出框
     };
   },
   computed: {
@@ -1181,6 +1224,7 @@ export default {
     this.getExpList();
     this.getBasecostItemList();
     this.getAuditType();
+    this.getSendStateList();
   },
   filters: {
     numberToCurrency(value) {
@@ -1720,7 +1764,9 @@ export default {
         res => {
           if (res.code == "ok") {
             // this.users = res.data.records;
+            const { id } = JSON.parse(sessionStorage.getItem('user'))
             this.users = res.data;
+            this.usersNoInfo = res.data.filter(item => item.id != id)
             if (!this.permissions.costAudit) {
               this.addForm.ownerId = this.user.id;
               this.addForm.status = 1;
@@ -2377,14 +2423,24 @@ export default {
         return;
       }
 
+      if(type == 1 && this.sendStateList.length > 0) {
+        this.releaseData = {
+          id: '',
+          data: unissueds
+        } 
+        this.dialogVisibleRelease = true
+        return
+      }
       this.callingInterface(type, type == 1 ? unissueds : Issueds);
     },
     callingInterface(type, ids) {
       this.http.post('/expense-sheet/editSendExpense', {
         expenseIds: ids.join(','),
-        sendState: type
+        sendState: type,
+        payWayId: this.releaseData.id || ''
       },
         res => {
+          this.dialogVisibleRelease = false
           if (res.code == "ok") {
             this.$message({
               message: '操作成功',
@@ -2399,6 +2455,7 @@ export default {
           }
         },
         error => {
+          this.dialogVisibleRelease = false
           this.$message({
             message: error,
             type: "error"
@@ -2495,7 +2552,43 @@ export default {
         });
       });
     },
-
+    // 判断当前数据的文件类型
+    isFileType(item) {
+      let str = item.split('.');
+      let format = str[str.length - 1];
+      if (['jpg', 'png', 'jpeg', 'JPG', 'PNG', 'JPEG'].includes(format)) {
+        return 'image'
+      } else if (format == "pdf") {
+        return 'pdf'
+      }
+    },
+    // 查看pdf
+    openViewPdf(urls) {
+      // 新窗口打开pdf
+      window.open(urls)
+    },
+    // 获取发放方式
+    getSendStateList() {
+      this.http.post('/expense-pay-way/get', {
+        companyId: this.user.companyId
+      },
+        res => {
+          if (res.code == "ok") {
+            this.sendStateList = res.data;
+          } else {
+            this.$message({
+              message: res.msg,
+              type: "error"
+            });
+          }
+        },
+        error => {
+          this.$message({
+            message: error,
+            type: "error"
+          });
+        });
+    }
   },
   beforeDestroy() {
 
@@ -2830,5 +2923,15 @@ export default {
     display: flex;
     flex-wrap: wrap;
   }
+
+  .dayImgeItemFile {
+    width: 100%;
+    .title {
+      font-size: 20px;
+    }
+    .text {
+      margin: 10px 30px;
+    }
+  }
 }
 </style>

+ 739 - 0
fhKeeper/formulahousekeeper/timesheet/src/views/project/budgetReview.vue

@@ -0,0 +1,739 @@
+<template>
+    <section>
+        <!--列表-->
+        <el-table :data="list" ref="multipleTable" v-if="showTable" highlight-current-row v-loading="listLoading" :height="tableHeight" style="width: 100%;"
+             :default-expand-all="defaultExpandAllFlg" >
+            <el-table-column type="selection" width="55"></el-table-column>
+            <el-table-column type="expand" :label="''">
+                <!-- <template slot-scope="props">
+                    <el-timeline>
+                    
+                    </el-timeline>
+                </template> -->
+            </el-table-column>
+
+            <el-table-column prop="projectName" :label="'项目名称'" sortable>
+                <template slot-scope="scope">
+                    <div>
+                        <span>
+                            {{scope.row.projectName}}
+                        </span>
+                    </div>
+                </template>
+            </el-table-column>
+
+            <el-table-column prop="groupName" :label="'分组名称'" sortable>
+                <template slot-scope="scope">
+                    <div>
+                        <span>
+                            {{scope.row.groupName}}
+                        </span>
+                    </div>
+                </template>
+            </el-table-column>
+            
+            <el-table-column prop="creator" :label="'提交人'" sortable>
+                <template slot-scope="scope">
+                    <div>
+                        <span v-if="user.userNameNeedTranslate == '1'">
+                            <ww-open-data type='userName' :openid='scope.row.creator'></ww-open-data>
+                        </span>
+                        <span v-else>
+                            {{scope.row.creator}}
+                        </span>
+                    </div>
+                </template>
+            </el-table-column>
+
+            <el-table-column prop="createTime" :label="'提交时间'" sortable>
+                <template slot-scope="scope">
+                    <div>
+                        <span>
+                            {{scope.row.createTime}}
+                        </span>
+                    </div>
+                </template>
+            </el-table-column>
+            <el-table-column prop="oldManDay" :label="'变更前预估工时'" sortable>
+                <template slot-scope="scope">
+                    <div>
+                        <span>
+                            {{scope.row.oldManDay}}
+                        </span>
+                    </div>
+                </template>
+            </el-table-column>
+
+            <el-table-column prop="changeManDay" :label="'预估工时变更'" sortable>
+                <template slot-scope="scope">
+                    <div>
+                        <span>
+                            {{scope.row.changeManDay}}
+                        </span>
+                    </div>
+                </template>
+            </el-table-column>
+
+            <el-table-column prop="nowManDay" :label="'变更后预估工时'" sortable>
+                <template slot-scope="scope">
+                    <div>
+                        <span>
+                            {{scope.row.nowManDay}}
+                        </span>
+                    </div>
+                </template>
+            </el-table-column>
+
+            <el-table-column prop="remark" :label="'变更理由'" sortable width="200px">
+                <template slot-scope="scope">
+                    <div>
+                        <div v-if="scope.row.remark && scope.row.remark.length > 11">
+                            <el-tooltip class="remarkClassItem" effect="dark" :content="scope.row.remark" placement="top">
+                                <div class="remarkClass">{{scope.row.remark}}</div>
+                            </el-tooltip>
+                        </div>
+                        <div v-else>
+                            {{scope.row.remark}}
+                        </div>
+                    </div>
+                </template>
+            </el-table-column>
+            
+            <el-table-column prop="status" :label="$t('state.states')" sortable>
+                <template slot-scope="scope">
+                    <span v-if="scope.row.status == 0" style="color:#DAA520;">{{ '待审核'}}</span>
+                    <span v-else-if="scope.row.status == 1" style="color:#32CD32;">{{ $t('state.alreadyPassed') }}</span>
+                    <span v-else-if="scope.row.status == 2" style="color:#FF0000;">{{ $t('state.rejected') }}</span>
+                </template>
+            </el-table-column>
+            <el-table-column :label="$t('operation')" width="220">
+                <template slot-scope="scope">
+                    <el-button v-if="scope.row.status==0"  type="primary" :loading="logining" size="small" @click="review(scope.row.id,1)">{{ $t('btn.through') }}</el-button>
+                    <el-button v-if="scope.row.status==0"  type="danger" :loading="logining" size="small" @click="review(scope.row.id,2)">{{ $t('btn.rejected') }}</el-button>
+                </template>
+            </el-table-column>
+        </el-table>
+        <!--工具条-->
+        <!-- <el-col v-if="search.value != -1" :span="24" class="toolbar">
+            <el-pagination
+                @size-change="handleSizeChange"
+                @current-change="handleCurrentChange"
+                :page-sizes="[20 , 50 , 80 , 100]"
+                :page-size="20"
+                layout="total, sizes, prev, pager, next"
+                :total="total"
+                style="float:right;"
+            ></el-pagination>
+        </el-col> -->
+    </section>
+</template>
+
+<script>
+    import util from "../../common/js/util";
+
+    // 引入自定义组件
+    import selectCat from "@/components/select.vue"
+
+    // 引入自定义级联组件
+    import vueCascader from "@/components/cascader.vue"
+    import cascaderOption from "@/components/cascaderOption.vue"
+
+    export default {
+        components: {
+            selectCat,
+            vueCascader,
+            cascaderOption
+        },
+        data() {
+            return {
+                yuzhongCompId: 3385,
+                roleList:[{value: 1,label: 'CRC&LM'},{value: 2,label: 'PM'}],
+                batchDenyLoading: false,
+                batchDenyDialog: false,
+                batchDenyData: {ids:'',reason:''},
+                batchApproveLoading: false,
+                denyForm:null,
+                denyReasonDialog:false,
+                isAllSelect:false,
+                user: JSON.parse(sessionStorage.getItem("user")),
+                permissions: JSON.parse(sessionStorage.getItem("permissions")),
+                search: {
+                    projectId:null,
+                    departmentIdArray: null,
+                    departmentId:null,
+                    // date: null,
+                    startDate: null,
+                    endDate: null,
+                    state:0,
+                    userId: null,
+                    userIdArray: []
+                },
+
+                users: [],
+                option:[],
+                tableHeight: 0,
+                listLoading: false,
+                total: 0,
+                page: 1,
+                size: 20,
+                list: [],
+                logining: false,
+                multipleSelection: [],
+                usersList: [],
+                searchUsersList: [],
+                dataTime: [],
+                recordDialogVisible: false,
+                recordLists: [],
+                totals: 0,
+                pageIndexList: 1,
+                pageSizeList: 20,
+                undoForm: {
+                    // reason: '',
+                    // userId: '',
+                    // createDate: ''
+                },
+                undoFormDialog: false,
+                detailsDialog: false,
+                idx: 0, // 详情索引
+                detailsList: [],
+                undoFormLoading: false,
+
+                approveinData: null,
+                approveinDialog: false,
+                isbatch: false,
+                defaultExpandAllFlg: false,
+                showTable: true
+            };
+        },
+        filters: {
+            // 过滤
+            amounts(value) {
+                var zhi = +value + 0
+                return zhi.toFixed(1)
+            }
+        },
+        methods: {
+            viewOneReport(r) {
+                this.http.post("/report/getAuditWorkflowList", {reportId:r.id},
+                    res => {
+                        if (res.code == "ok") {
+                            this.$set(r,'auditorList', res.data);
+                        } 
+                    },
+                    error => {
+                        this.undoFormLoading = false
+                        this.$message({
+                            message: error,
+                            type: "error"
+                        });
+                    });
+            },
+            expandChange(row, expandedRows) {
+                var reportList = row.data;
+                for (var i=0;i<reportList.length; i++) {
+                    var r = reportList[i];
+                    if (r.auditorList) continue;
+                    this.http.post("/report/getAuditWorkflowList", {reportId:r.id},
+                    res => {
+                        if (res.code == "ok") {
+                            this.$set(r,'auditorList', res.data);
+                        } 
+                    },
+                    error => {
+                        this.undoFormLoading = false
+                        this.$message({
+                            message: error,
+                            type: "error"
+                        });
+                    });
+                }
+            },
+            detailsClick(item, i) {
+                this.detailsDialog = true
+                this.detailsList = item.membdateList
+                this.idx = i
+            },
+            // 审核记录撤销点击确定
+            clickCancel() {
+                this.undoFormLoading = true
+                this.http.post('/report/denyHisReport', this.undoForm,
+                res => {
+                    this.undoFormLoading = false
+                    if (res.code == "ok") {
+                        this.$message({
+                            message: this.$t('Revocationofsuccess'),
+                            type: "success"
+                        });
+                        this.undoFormDialog = false
+                        this.recordList()
+                    } else {
+                        this.$message({
+                            message: res.msg,
+                            type: "error"
+                        });
+                    }
+                },
+                error => {
+                    this.undoFormLoading = false
+                    this.$message({
+                        message: error,
+                        type: "error"
+                    });
+                });
+            },
+            undoCli(item, i) {
+                // console.log(item)
+                this.undoFormDialog = true
+                this.undoForm = {reason: ''}
+                // this.undoForm.reason = ''
+                if(i){
+                    this.undoForm.hisId = item.id
+                }else{
+                    this.undoForm.hisId = item.membdateList[0].id
+                }
+                
+                this.ioss = i
+                // if(i == 0) {    
+                //     this.undoForm.createDate = item.indate.split(' ')[0]
+                //     this.undoForm.userId = item.userId
+                // } else {
+                //     this.undoForm.hisId = item.id
+                // }
+            },
+            // 获取审核记录
+            recordList() {
+                // this.recordDialogVisible = true
+                // return
+                this.http.post( '/report-audit-log/getProjectReportAuditLog', {
+                    companyId: this.user.companyId,
+                    pageIndex: this.pageIndexList,
+                    pageSize: this.pageSizeList
+                },
+                res => {
+                    if (res.code == "ok") {
+                        for (var i in res.data.records) {
+                            res.data.records[i].result.indexOf(this.$t('btn.through')) == '-1' ? res.data.records[i].flg = false : res.data.records[i].flg = true
+                        }
+                        this.recordLists = res.data.records
+                        this.totals = res.data.total
+                        if(this.recordLists.length != 0){
+                            this.detailsList = this.recordLists[this.idx].membdateList
+                        }
+                        
+                    } else {
+                        this.$message({
+                            message: res.msg,
+                            type: "error"
+                        });
+                    }
+                },
+                error => {
+                    this.$message({
+                        message: error,
+                        type: "error"
+                    });
+                });
+            },
+            // 获取部门列表
+            getDepartment() {
+                this.http.post( this.port.manage.depList, {},
+                res => {
+                    if (res.code == "ok") {
+                        var list1 = JSON.parse(JSON.stringify(res.data));
+                        
+                        this.option = this.changeArr(list1);
+                        console.log(this.option, '部门')
+                    } else {
+                        this.$message({
+                            message: res.msg,
+                            type: "error"
+                        });
+                    }
+                },
+                error => {
+                    this.$message({
+                        message: error,
+                        type: "error"
+                    });
+                });
+            },
+
+            handleSelectionChange(val) {
+                this.multipleSelection = val;
+            },
+            batchApprove(isPass) {
+                var ids = '';
+                for (var i=0;i<this.multipleSelection.length; i++) {
+                    var line = this.multipleSelection[i];
+                    var array = line.data;
+                    if (this.user.company.companyName == '成都明夷电子科技有限公司') {
+                        ids += line.reportIds+',';
+                    } else {
+                        for (var m=0;m<array.length; m++) {
+                            ids += array[m].id+',';
+                        }
+                    }
+                }
+                if (ids.length > 0) {
+                    ids = ids.substring(0, ids.length-1);
+                }
+                //等待
+                if(isPass){
+                    this.isbatch = true
+                    this.approveinData = {
+                        ids: ids
+                    }
+                    if(this.user.timeType.needEvaluate == 1){
+                        this.$set(this.approveinData,'evaluate','')
+                        this.approveinDialog = true
+                    }else{
+                        this.batchApproveLoading = true
+                        this.listLoading = true;
+                        this.batchApproveinfun()
+                    }
+                }else{
+                    this.batchDenyDialog = true
+                    this.batchDenyData.ids = ids
+                    this.batchDenyData.reason = ''
+                }
+            },
+            batchApproveinfun(){
+                this.http.post('/report/batchApproveReport', this.approveinData,
+                    res => {
+                        this.batchApproveLoading = false
+                        this.listLoading = false;
+                        if (res.code == "ok") {
+                            this.approveinDialog = false
+                            this.getList();
+                        } else {
+                            this.$message({
+                            message: res.msg,
+                            type: "error"
+                            });
+                        }
+                    },
+                    error => {
+                        this.listLoading = false;
+                        this.$message({
+                            message: error,
+                            type: "error"
+                        });
+                    });
+            },
+            batchDenyClick(){
+                this.batchDenyLoading = true
+                    this.listLoading = true;
+                    this.http.post('/report/batchDenyReport', this.batchDenyData,
+                    res => {
+                        this.batchDenyLoading = false;
+                        this.batchDenyDialog = false
+                        this.listLoading = false;
+                        if (res.code == "ok") {
+                            this.getList();
+                        } else {
+                            this.$message({
+                            message: res.msg,
+                            type: "error"
+                            });
+                        }
+                    },
+                    error => {
+                        this.listLoading = false;
+                        this.$message({
+                            message: error,
+                            type: "error"
+                        });
+                    });
+            },
+            //分页
+            handleCurrentChange(val) {
+                this.page = val;
+                this.getList();
+            },
+
+            handleSizeChange(val) {
+                this.size = val;
+                this.getList();
+            },
+
+            //分页
+            handleCurrentChangeList(val) {
+                this.pageIndexList = val;
+                this.recordList();
+            },
+
+            handleSizeChangeList(val) {
+                this.pageSizeList = val;
+                this.recordList();
+            },
+
+            test(){
+                console.log(this.search.userId);
+            },
+            searchUserIds(deptId){
+                this.searchUsersList = this.usersList.filter(item => deptId == item.departmentId)
+            },
+            usersSearch(e){
+                if(e == false){
+                    this.getList()
+                }
+            },
+            //获取待审核的数据列表
+            getList(e) {
+                this.listLoading = true;
+                this.http.post("/group-budget-review/list",{},
+                res => {
+                    this.listLoading = false;
+                    if (res.code == "ok") {
+                        this.list = res.data;
+                    } else {
+                        this.$message({
+                        message: res.msg,
+                        type: "error"
+                        });
+                    }
+                },
+                error => {
+                    this.listLoading = false;
+                    this.$message({
+                        message: error,
+                        type: "error"
+                    });
+                });
+            },
+
+            review(id,checkType){
+                this.http.post("/group-budget-review/check", {id:id,checkType:checkType},
+                res => {
+                    if (res.code == "ok") {
+                        this.$message({
+                            message:"操作成功",
+                            type: "success"
+                        });
+                        this.getList();
+                    } else {
+                        this.$message({
+                            message: res.msg,
+                            type: "error"
+                        });
+                    }
+                },
+                error => {
+                    this.$message({
+                        message: error,
+                        type: "error"
+                    });
+                });
+            },
+
+            approveinfun(){
+                this.http.post(this.port.report.approve, this.approveinData,
+                res => {
+                    this.logining = false;
+                    if (res.code == "ok") {
+                        this.approveinDialog = false
+                        this.$message({
+                            message: this.$t('message.Reviewsucceeded'),
+                            type: "success"
+                        });
+                        this.getList();
+                    } else {
+                        this.$message({
+                            message: res.msg,
+                            type: "error"
+                        });
+                    }
+                },
+                error => {
+                    this.logining = false;
+                    this.$message({
+                        message: error,
+                        type: "error"
+                    });
+                });
+            },
+// 修改数组
+            changeArr(arr) {
+                for (var i = 0; i < arr.length; i++) {
+                    if(arr[i].id != -1 && arr[i].id != 0) {
+                        if (arr[i].children != null && arr[i].children.length>0) {
+                            arr[i].children = this.changeArr(arr[i].children);
+                        }
+                        arr[i].id && (arr[i].value = arr[i].id);
+                        delete arr[i].id;
+                    }
+                }
+                for(var i in arr) {
+                    if(arr[i].id == -1 || arr[i].id == 0) {
+                        arr.splice(i,1)
+                    }    
+                }
+                return arr;
+            },
+            
+            //获取项目列表
+            getProjectList() {
+                this.http.post( this.port.project.list, {},
+                res => {
+                    if (res.code == "ok") {
+                        this.projectList = res.data;
+                    } else {
+                        this.$message({
+                            message: res.msg,
+                            type: "error"
+                        });
+                    }
+                },
+                error => {
+                    this.$message({
+                        message: error,
+                        type: "error"
+                    });
+                });
+            },
+            showDenyDialog(id,i, date, item) {
+                this.denyReasonDialog = true;
+                var ids = '';
+                if (this.user.company.companyName == '成都明夷电子科技有限公司') {
+                    ids = item.reportIds;
+                } else {
+                    var data = item.data;
+                    data.forEach(element => {
+                        ids +=(element.id+',');
+                    });
+                }
+                
+                this.denyForm = {id: id ,i:i, date: date, reportIds: ids, reason:null};
+            },
+
+            // 未通过日报
+            deny() {
+                this.logining = true;
+                this.http.post( this.port.report.deny, this.denyForm,
+                res => {
+                    this.logining = false;
+                    if (res.code == "ok") {
+                        this.$message({
+                            message: this.denyForm.i==0?this.$t('message.rejectedsuccessfully'):this.$t('Revocationofsuccess'),
+                            type: "success"
+                        });
+                        this.getList();
+                        this.denyReasonDialog = false;
+                    } else {
+                        this.$message({
+                            message: res.msg,
+                            type: "error"
+                        });
+                    }
+                },
+                error => {
+                    this.logining = false;
+                    this.$message({
+                        message: error,
+                        type: "error"
+                    });
+                });
+            },
+            // 获取所有人员
+            getUsers() {
+                // this.http.post(this.port.manage.list, {
+                //     departmentId: -1,
+                //     pageIndex: 1,
+                //     // pageSize: 99999
+                //     pageSize: -1
+                // },
+                this.http.post('/user/getSimpleActiveUserList', {},
+                res => {
+                    if (res.code == "ok") {
+                        this.usersList = res.data;
+                        this.searchUsersList = this.usersList
+                    } else {
+                        this.$message({
+                        message: res.msg,
+                        type: "error"
+                        });
+                    }
+                },
+                error => {
+                    this.$message({
+                        message: error,
+                        type: "error"
+                    });
+                });
+            },
+            // 选择日期后触发
+            dataTimes() {
+                // console.log(this.dataTime)
+                if(this.dataTime){
+                    this.search.startDate = this.dataTime[0]
+                    this.search.endDate = this.dataTime[1]
+                }else{
+                    this.search.startDate = null
+                    this.search.endDate = null
+                }
+                this.getList()
+            },
+            // 自定义部门选择
+            vueCasader(obj) {
+                console.log(obj, '组件传过来的')
+                if(obj.distinction == '1') {
+                    if(obj.id != '') {
+                        let arr = []
+                        arr.push(obj.id)
+                        this.search.departmentIdArray = arr
+                    } else {
+                        this.search.departmentIdArray = []
+                    }
+                    this.getList(1)
+                }
+            },
+            selectCal(obj) {
+                console.log(obj, '过来的数据')
+                // search.userIdArray
+                let userListId = obj.arrUserList
+                let arr = []
+                for(var i in userListId) {
+                    arr.push(userListId[i].id)
+                }
+                this.search.userIdArray = arr
+                console.log(this.search.userIdArray, '数据看看')
+                this.usersSearch(false)
+            },
+            defaultExpandAllFlgCli() {
+                this.defaultExpandAllFlg = !this.defaultExpandAllFlg
+                this.list = JSON.parse(JSON.stringify(this.list))
+                this.$nextTick(()=>{this.$refs.multipleTable.doLayout()})
+                this.showTable = false
+                this.$nextTick(() => {
+                    this.showTable = true
+                })
+            }
+        },
+        created() {
+            let height = window.innerHeight;
+            this.tableHeight = height - 125;
+            const that = this;
+            window.onresize = function temp() {
+                that.tableHeight = window.innerHeight - 125;
+            };
+        },
+        mounted() {
+            this.getList();
+            // this.getDepartment();
+            // this.getProjectList();
+            // this.getUsers()
+        }
+    };
+</script>
+
+<style lang="scss" scoped>
+.propsbtn {
+    display: inline-block;
+    padding-left: 20px;
+}
+.remarkClass {
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+}
+</style>

+ 27 - 13
fhKeeper/formulahousekeeper/timesheet/src/views/project/cost.vue

@@ -57,7 +57,7 @@
                 </el-option>
             </el-select>
             <span style="text-align: left">
-            <selectCat v-if="radio == $t('ren-yuan') && user.userNameNeedTranslate == '1'" :size="'small'" :widthStr="'350'" :distinction="'2'" :subject="hasReportUserList" :clearable="true" @selectCal="selectCal" :disabled="hasReportUserList.length == 0 ? true : false"></selectCat>
+            <selectCat v-if="radio == $t('ren-yuan') && user.userNameNeedTranslate == '1'" :searchBoxTop="'1'" :filterable="true" :size="'small'" :widthStr="'350'" :distinction="'2'" :subject="hasReportUserList" :clearable="true" @selectCal="selectCal" :disabled="hasReportUserList.length == 0 ? true : false"></selectCat>
             </span>
 
         </el-col>
@@ -93,14 +93,19 @@
         <!--导出报表条件选择 -->
         <el-dialog :title="$t('timeReportExport')" v-if="exportDialog" :visible.sync="exportDialog" :close-on-click-modal="false" customClass="customWidth" width="500px">
             <el-form ref="form3" :model="exportParam" >
-                <el-form-item prop="projectId" :label="$t('defaultText.selectProject')" v-if="radio != $t('ren-yuan') && radio != $t('projectclassification') && radio != $t('lable.department')">
+                <el-form-item prop="projectCategoryId" :label="$t('projectclassification')" v-if="radio == $t('projectclassification')||radio==$t('other.project')">
+                    <el-select v-model="exportParam.projectCategoryId" :placeholder="$t('classificationitems')"  clearable style="width:350px;" filterable="true">
+                        <el-option v-for="item in categoryList"  :key="item.id" :label="item.name" :value="item.id">
+                        </el-option>
+                    </el-select>
+                </el-form-item>
+                <el-form-item prop="projectId" :label="$t('defaultText.selectProject')" v-if="radio != $t('ren-yuan') && radio != $t('projectclassification') && radio != $t('lable.department') && radio != $t('zhu-xiang-mu')">
                     <el-select v-model="exportParam.projectId" :placeholder="$t('other.allProject')"  clearable style="width:350px;" filterable="true" popper-class="projectSelectPopperClass">
                         <el-option v-for="item in projectList"  :key="item.id" :label="item.projectName + item.projectCode" :value="item.id">
                             <span style="float: left;color: #8492a6;">{{ item.projectCode }}</span>
                             <span style="float: right;font-size: 13px;">{{ item.projectName }}</span>
                         </el-option>
                     </el-select>
-
                 </el-form-item>
                 <el-form-item prop="exportContent" label="导出内容" v-if="permissions.countCost && permissions.countHours && (radio == $t('other.project') || radio == $t('projectclassification'))">
                     <el-select v-model="exportParam.exportContent" style="width:350px;" filterable="true" popper-class="projectSelectPopperClass">
@@ -117,12 +122,7 @@
                     <vueCascader :size="'medium'" :widthStr="'350'" :clearable="true" :subject="departmentList" :radios="true" :distinction="'1'" @vueCasader="vueCasader" v-if="user.userNameNeedTranslate == 1"></vueCascader>
                 </el-form-item>
 
-                <el-form-item prop="projectCategoryId" :label="$t('projectclassification')" v-if="radio == $t('projectclassification')">
-                    <el-select v-model="exportParam.projectCategoryId" :placeholder="$t('classificationitems')"  clearable style="width:350px;" filterable="true">
-                        <el-option v-for="item in categoryList"  :key="item.id" :label="item.name" :value="item.id">
-                        </el-option>
-                    </el-select>
-                </el-form-item>
+
                 <el-form-item prop="userIds" :label="$t('screening.selectPeople')" v-if="radio == $t('ren-yuan')">
                     <el-select v-if="user.userNameNeedTranslate != '1'" v-model="exportParam.userIds" :placeholder="$t('lable.allStaff')" multiple="true"  clearable style="width:350px;" filterable="true">
                         <el-option v-for="item in hasReportUserList"  :key="item.id" :label="item.name" :value="item.id"></el-option>
@@ -183,13 +183,15 @@
                 <el-form-item v-if="exportParam.type == 1 && permissions.countHours && (radio == $t('other.project'))">
                     <el-checkbox v-model="exportParam.withPercent" >含项目工时占比</el-checkbox>
                 </el-form-item>
-                <el-form-item v-if="(radio == $t('other.project') || radio == $t('projectclassification')) && exportParam.type == '0'">
+                <el-form-item v-if="radio == $t('zhu-xiang-mu') || ((radio == $t('other.project') || radio == $t('projectclassification')) && exportParam.type == '0')">
                     <el-checkbox v-model="exportParam.projectSum" >{{ $t('individualprojectdata') }}</el-checkbox>
                 </el-form-item>
-                
+                <el-form-item v-if="radio == $t('ren-yuan') && user.timeType.mainProjectState == 1">
+                    <el-checkbox v-model="exportParam.mainProjectColumn" >含主项目</el-checkbox>
+                </el-form-item>
             </el-form>
             <div slot="footer" class="dialog-footer">
-                <el-button type="primary" @click="exportProjectData" style="width:100%;" >{{ $t('export.export') }}</el-button>
+                <el-button type="primary" @click="exportProjectData" style="width:100%;" :loading="exporting">{{ $t('export.export') }}</el-button>
             </div>
         </el-dialog>
     </section>
@@ -209,6 +211,7 @@
         },
         data() {
             return {
+                exporting: false,
                 totalTime111: 0,
                 allListData: [],
                 page: 1,
@@ -360,6 +363,9 @@
                  }
                  var url = "/project/exportTimeCost";
                  var fileName = this.$t('projectmanhourcoststatistics')+ '.xlsx';
+                 if (this.radio == this.$t('zhu-xiang-mu')) {
+                    param.withMainProject = 1;
+                 }
                  if(this.radio == this.$t('other.project')){
                     if (this.exportParam.userIds != null && this.exportParam.userIds.length > 0) {
                          var ids = '';
@@ -368,6 +374,9 @@
                         })
                         param.userIds = ids.substring(0,ids.length-1);
                      }
+                     if(this.exportParam.projectCategoryId){
+                        param.projectCategoryId = this.exportParam.projectCategoryId
+                    }
                      //是否含工时占比显示
                      if (this.exportParam.withPercent) {
                         param.withPercent = 1;
@@ -384,6 +393,7 @@
                         })
                         param.userIds = ids.substring(0,ids.length-1);
                      }
+                     param.mainProjectColumn = this.exportParam.mainProjectColumn;
                  } 
                 if(this.radio == this.$t('projectclassification')){
                     fileName = this.$t('projectclassificationlaborosttatistics')+ '.xlsx';
@@ -416,7 +426,7 @@
                     this.exportParam.projectSum = null
                 }
                 if (this.exportParam.projectSum != null) {
-                    if(this.radio == this.$t('other.project') || this.radio == this.$t('lable.department') || this.radio == this.$t('projectclassification')){
+                    if(this.radio == this.$t('other.project') || this.radio == this.$t('lable.department') || this.radio == this.$t('projectclassification') || this.radio == this.$t('zhu-xiang-mu')){
                         param.projectSum = this.exportParam.projectSum;
                     }
                 }
@@ -450,8 +460,10 @@
                     }
                     fileName = this.radio + '成本统计' + '.xlsx'
                 }
+                this.exporting = true;
                 this.http.post(url, param,
                     res => {
+                        this.exporting = false;
                         if (res.code == "ok") {
                             this.exportDialog = false;
                             var aTag = document.createElement('a');
@@ -470,6 +482,7 @@
                             message: error,
                             type: "error"
                         });
+                        this.exporting = false;
                     });
             },
             // 人员筛选
@@ -1466,6 +1479,7 @@
             });
             // this.getDepartment();
             this.getMyProjectList();
+            this.getCategoryList();
             this.getUsers()
             this.jutishez()
             this.scrollFunction()

+ 198 - 39
fhKeeper/formulahousekeeper/timesheet/src/views/project/list.vue

@@ -85,7 +85,7 @@
                                 <el-link type="primary" :underline="false" @click="projectLevelDialog = true">{{ $t('projectlevelmanagement') }}</el-link>
                             </el-dropdown-item>
                             <el-dropdown-item v-if="user.timeType.syncFanwei==1||user.timeType.syncSap==1">
-                                <el-link type="primary" :underline="false" @click="syncProjectForThird()">{{'同步项目信息'}}</el-link>
+                                <el-link type="primary" :underline="false" @click="syncProjectDig=true, synchronizationInputVal = ''">{{'同步项目信息'}}</el-link>
                             </el-dropdown-item>
                             <el-dropdown-item v-if="user.companyId==3385 && permissions.projectClassification">
                                 <el-link type="primary" :underline="false" @click="functionalDivisionDig=true,getFunctionalList()">{{'职能分工设置'}}</el-link>
@@ -93,6 +93,9 @@
                             <el-dropdown-item v-if="user.timeType.projectManDay == 1 && permissions.projectClassification">
                                 <el-link type="primary" :underline="false" @click="projectManDaySettingDialog = true;getManDaySetting()">{{ '预估工时配置' }}</el-link>
                             </el-dropdown-item>
+                            <el-dropdown-item v-if="user.companyId == 10 || user.companyId == 5608">
+                                <el-link type="primary" :underline="false" @click="importTaskDialog = true">{{ '项目任务导入' }}</el-link>
+                            </el-dropdown-item>
                         </el-dropdown-menu>
                         </el-dropdown>
                 </el-form-item>
@@ -126,9 +129,9 @@
                             <span style="float: left">{{ item.name }}</span>
                             <span style="float: right; color: #8492a6;" v-if="user.companyId == 936">{{ item.jobNumber }}</span>
                         </el-option>
-                    </el-select>
+                    </el-select> 
 
-                    <selectCat v-if="user.userNameNeedTranslate == 1" :size="'mini'" :subject="users" :subjectId="inchagerId" :distinction="'1'" :clearable="true" @selectCal="selectCal"></selectCat>
+                    <selectCat v-if="user.userNameNeedTranslate == 1" :filterable="true" :size="'mini'" :subject="users" :subjectId="inchagerId" :distinction="'1'" :clearable="true" @selectCal="selectCal"></selectCat>
 
                 </el-form-item>
                 <el-form-item>
@@ -141,7 +144,7 @@
                         </el-option>
                     </el-select>
 
-                    <selectCat v-if="user.userNameNeedTranslate == 1" :size="'mini'" :subject="users" :subjectId="participationId" :distinction="'2'" :clearable="true" @selectCal="selectCal"></selectCat>
+                    <selectCat v-if="user.userNameNeedTranslate == 1" :filterable="true" :size="'mini'" :subject="users" :subjectId="participationId" :distinction="'2'" :clearable="true" @selectCal="selectCal"></selectCat>
 
                 </el-form-item>
                 <!-- 部门筛选 -->
@@ -222,9 +225,9 @@
                          <el-link type="primary" v-if="user.company.packageProject==1" :underline="false" :href="'#/projectInside/'+scope.row.id">{{scope.row.projectName}}</el-link>
                             <span v-if="user.company.packageProject==0" >{{scope.row.projectName}}</span>
                      </div> -->
-                     <div>
-                         <el-link type="primary" v-if="user.company.packageProject==1" :underline="false" :href="'#/projectInside/'+scope.row.id">{{scope.row.projectName}}</el-link>
-                            <span v-if="user.company.packageProject==0" >{{scope.row.projectName}}</span>
+                     <div> 
+                         <el-link type="primary" v-if="user.company.packageProject==1 && (user.company.nonProjectSimple==0 || (user.company.nonProjectSimple==1&&scope.row.isPublic==0))" :underline="false" :href="'#/projectInside/'+scope.row.id">{{scope.row.projectName}}</el-link>
+                         <span v-else>{{scope.row.projectName}}</span>
                      </div>
                 </template>
             </el-table-column>
@@ -484,10 +487,7 @@
                         <el-input v-model="addForm.projectDesc" :placeholder="$t('peaseenterthe')" clearable maxlength="4000" :disabled="canOnlyModParticipator" show-word-limit></el-input>
                     </el-form-item>
                     <el-form-item :label="$t('projecttype')" :class="title == $t('newproject') && user.companyId == 936 ? 'wpgCssClass' : ''" prop="isPublic">
-                        <!-- <el-select v-model="addForm.isPublic" style="width:32%;" @change="selectPublic" :disabled="!permissions.projectManagement && addForm.creatorId != user.id"> -->
                         <el-select v-model="addForm.isPublic" style="width:32%;" @change="selectPublic" :disabled="canOnlyModParticipator">
-                            <!-- <el-option :value="0" :label="$t('commonproject')"></el-option>
-                            <el-option :value="1" :label="$t('publicprojects')"></el-option> -->
                             <el-option :value="0" :label="$t('zheng-shi-xiang-mu')"></el-option>
                             <el-option :value="1" :label="$t('fei-xiang-mu')"></el-option>
                         </el-select>
@@ -559,7 +559,7 @@
                             </div>
                         </el-tooltip>
                     </el-form-item>
-                    <el-form-item :label="$t('projectmanager')" :class="title == $t('newproject') && user.companyId == 936 ? 'wpgCssClass' : ''">
+                    <el-form-item :label="$t('projectmanager')" :class="title == $t('newproject') && user.companyId == 936 ? 'wpgCssClass' : ''" v-if="user.company.nonProjectSimple == 0 || (user.company.nonProjectSimple == 1 && addForm.isPublic == 0)">
                        <el-select v-if="user.userNameNeedTranslate != 1" v-model="addForm.inchargerId" filterable :placeholder="$t('defaultText.pleaseChoose')" style="width:32%;" :disabled="canOnlyModParticipator || projectManagerEdit">
                             <el-option v-for="item in participator" :key="item.id" :label="item.name" :value="item.id">
                                 <span style="float: left">{{ item.name }}</span>
@@ -568,20 +568,24 @@
                         </el-select>
                         <selectCat v-if="user.userNameNeedTranslate == 1" :size="'medium'" :subject="participator" :subjectId="addForm.inchargerId" :distinction="'3'" @selectCal="selectCal" :disabled="canOnlyModParticipator || projectManagerEdit || isShowProjectName"></selectCat>
                     </el-form-item>
-                    <el-form-item :label="$t('newspaperauditor')" v-show="user.timeType.reportAuditType == 0 || user.timeType.reportAuditType == 4 || user.timeType.reportAuditType == 6">
-                        <el-select v-if="user.userNameNeedTranslate != '1'" @change="$forceUpdate()" v-model="addForm.auditUserIds"  :disabled="!(permissions.projectManagement|| user.id == addForm.inchargerId || user.id == addForm.creatorId)" filterable :placeholder="$t('defaultistheprojectleader')" style="width:100%;" :multiple="user.timeType.reportAuditType != 6" >
-                            <el-option v-for="item in participator" :key="item.id" :label="item.name" :value="item.id"></el-option>
-                        </el-select>
-                        <selectCat v-if="user.userNameNeedTranslate == '1'" :size="'medium'" :tile="true" :widthStr="'800'" :disabled="!(permissions.projectManagement|| user.id == addForm.inchargerId || user.id == addForm.creatorId)" :subjectId="addForm.auditUserIds" :subject="participator" :clearable="false" :distinction="'10'"  :multiSelect="user.timeType.reportAuditType != 6" @selectCal="selectCal"></selectCat>
-                    </el-form-item>
-                    <el-form-item v-if="user.timeType.reportCc == 1" label="日报抄送人" >
+
+                    <span v-if="user.companyId != 469">
+                        <el-form-item :label="$t('newspaperauditor')" v-show="user.timeType.reportAuditType == 0 || user.timeType.reportAuditType == 4 || user.timeType.reportAuditType == 6" v-if="user.company.nonProjectSimple == 0 || (user.company.nonProjectSimple == 1 && addForm.isPublic == 0)">
+                            <el-select v-if="user.userNameNeedTranslate != '1'" @change="$forceUpdate()" v-model="addForm.auditUserIds"  :disabled="!(permissions.projectManagement|| user.id == addForm.inchargerId || user.id == addForm.creatorId)" filterable :placeholder="$t('defaultistheprojectleader')" style="width:100%;" :multiple="user.timeType.reportAuditType != 6" >
+                                <el-option v-for="item in participator" :key="item.id" :label="item.name" :value="item.id"></el-option>
+                            </el-select>
+                            <selectCat v-if="user.userNameNeedTranslate == '1'" :size="'medium'" :tile="true" :widthStr="'800'" :disabled="!(permissions.projectManagement|| user.id == addForm.inchargerId || user.id == addForm.creatorId)" :subjectId="addForm.auditUserIds" :subject="participator" :clearable="false" :distinction="'10'"  :multiSelect="user.timeType.reportAuditType != 6" @selectCal="selectCal"></selectCat>
+                        </el-form-item>
+                    </span>
+                    
+                    <el-form-item v-if="user.timeType.reportCc == 1 && (user.company.nonProjectSimple == 0 || (user.company.nonProjectSimple == 1 && addForm.isPublic == 0))" label="日报抄送人" >
                         <el-select v-if="user.userNameNeedTranslate != '1'" v-model="addForm.ccUserIds" multiple="true" :disabled="!(permissions.projectManagement|| user.id == addForm.inchargerId || user.id == addForm.creatorId)" filterable placeholder="请选择抄送人" style="width:100%;" >
                             <el-option v-for="item in participator" :key="item.id" :label="item.name" :value="item.id"></el-option>
                         </el-select>
                         <selectCat v-if="user.userNameNeedTranslate == '1'" :size="'medium'" :tile="true" :widthStr="'800'" :disabled="!(permissions.projectManagement|| user.id == addForm.inchargerId || user.id == addForm.creatorId)" :subjectId="addForm.ccUserIds" :subject="participator" :clearable="false" :distinction="'10'"  :multiSelect="true" @selectCal="selectCal"></selectCat>
                     </el-form-item>
                     <!--专业项目协作版本功能 -->
-                    <el-form-item :label="$t('ji-bie')" :class="title == $t('newproject') && user.companyId == 936 ? 'wpgCssClass' : ''" v-if="user.company.packageProject==1">
+                    <el-form-item :label="$t('ji-bie')" :class="title == $t('newproject') && user.companyId == 936 ? 'wpgCssClass' : ''" v-if="user.company.packageProject==1 && (user.company.nonProjectSimple == 0 || (user.company.nonProjectSimple == 1 && addForm.isPublic == 0))">
                         <el-select v-model="addForm.level"  :placeholder="$t('defaultText.pleaseChoose')" style="width:32%;" v-if="user.timeType.projectLevelState == 1" :disabled="canOnlyModParticipator || isShowProjectName">
                             <el-option v-for="item in levelList" :key="item.id" :label="item.projectLevelName" :value="item.id"></el-option>
                         </el-select>
@@ -594,7 +598,7 @@
                             placeholder="整数" clearable  @keyup.native="restrictNumber('contractAmount')" :disabled="title == '新增项目' ? false : false"></el-input><span style="margin-left:10px;">元</span> -->
                     </el-form-item>
                     <!-- 增加合同金额字段 -->
-                    <el-form-item  :label="$t('contractamount')" v-if="user.company.packageProject==1">
+                    <el-form-item  :label="$t('contractamount')" v-if="user.company.packageProject==1 && (user.company.nonProjectSimple == 0 || (user.company.nonProjectSimple == 1 && addForm.isPublic == 0))">
                         <el-input id="contractAmount" v-model="addForm.contractAmount" :disabled="canOnlyModParticipator" style="width:32%;" @input="contractAmountChange(addForm.contractAmount)" :placeholder="$t('zheng-shu')" clearable  @keyup.native="restrictNumber('contractAmount')"></el-input><span style="margin-left:10px;position:absolute;">{{ $t('yuan') }}</span>
                         <template v-if="title == $t('modifytheproject') && contractAmountReasonShow">
                             <span style="margin-left:63px;margin-right:10px;">{{ $t('modifythereason') }}</span>
@@ -603,7 +607,7 @@
                     </el-form-item>
 
 
-                    <el-form-item :label="$t('ommencementDate')" prop="planStartDate"  >
+                    <el-form-item :label="$t('ommencementDate')" prop="planStartDate"  v-if="(user.company.nonProjectSimple == 0 || (user.company.nonProjectSimple == 1 && addForm.isPublic == 0))">
                         <el-date-picker v-model="addForm.planStartDate" :disabled="canOnlyModParticipator"
                         :editable="false" style="width:32%;" 
                         format="yyyy-MM-dd" 
@@ -628,7 +632,7 @@
                     </el-form-item>
 
                     <!-- 增加项目人天字段 绎维固定字段 -->
-                    <el-form-item  v-if="user.timeType.projectManDay == 1">
+                    <el-form-item  v-if="user.timeType.projectManDay == 1 && (user.company.nonProjectSimple == 0 || (user.company.nonProjectSimple == 1 && addForm.isPublic == 0))">
                         <template slot="label"><span v-if="manDaySetting.projectManDayFillMode == 2 || (manDaySetting.projectManDayFillMode == 1 && addForm.fromOutside == 0)" style="padding:5px;color:red;">*</span>项目人天</template>
                         <el-input v-model.number="addForm.manDay" :placeholder="$t('peaseenterthe')" @input="jisuanEstimatedWorkTime(addForm.manDay)"  style="width: 100px"></el-input><span style="margin-left:10px;position:absolute;">人天(预估工时:{{this.estimatedWorkTime}}h)</span>
                         <el-tooltip effect="dark" :content="$t('根据系统基础设置每日正常工作时长计算,1人天为一个每日正常工作时长')" placement="top-start" style="margin-left:180px">
@@ -739,7 +743,7 @@
                         </el-form-item>
                     </div> -->
                     <!-- 项目基线 -->
-                    <div style="margin: 10px 0 30px 0;min-height:200px;" v-if="user.company.packageProject == 1 && !canOnlyModParticipator">
+                    <div style="margin: 10px 0 30px 0;min-height:200px;" v-if="user.company.packageProject == 1 && !canOnlyModParticipator && (user.company.nonProjectSimple == 0 || (user.company.nonProjectSimple == 1 && addForm.isPublic == 0))">
                         <el-tabs v-model="activeName" @tab-click="handleClick">
                         <el-tab-pane :label="$t('costbaseline')" name="baseCostPanel"  >
                             <div style="padding-top:10px;">
@@ -1239,7 +1243,7 @@
         <el-dialog :title="$t('selectingParticipants')"  :visible.sync="chooseParticipVisible" :close-on-click-modal="false" customClass="customWidth" width="500px">
             <!-- <el-input style="width:100%" v-model="filterName" placeholder="请输入姓名搜索" @change="findUserInTree"></el-input> -->
             <div v-if="user.userNameNeedTranslate == '1'">
-                <el-input placeholder="请输入内容" v-model.trim="wxFilterText" class="input-with-select">
+                <el-input placeholder="请输入内容" v-model.trim="filterText" class="input-with-select">
                     <el-button slot="append" icon="el-icon-search" @click="echartDepartment()"></el-button>
                 </el-input>
             </div>
@@ -1265,6 +1269,7 @@
                             <span v-if="user.userNameNeedTranslate != '1'">
                                 {{ node.label }}
                             </span>
+                            <!-- {{ node.label }} -->
                         </span>
                     </el-tree>
                 </el-scrollbar>
@@ -1632,6 +1637,47 @@
                 <el-button type="primary" @click="batchSetGroupIncharger()">{{ $t('btn.determine') }}</el-button>
             </div>
         </el-dialog>
+        <!-- 项目同步弹窗 -->
+        <el-dialog title="项目服务同步" :visible.sync="syncProjectDig" width="600px" :before-close="handleClose">
+            <el-form label-width="0">
+                <div class="synchronization">
+                    <div class="synchronizationLabel">
+                        <el-select v-model="synchronizationVal" placeholder="请选择" @change="synchronizationChange()">
+                            <el-option label="已同步项目" value="0"></el-option>
+                            <el-option label="未同步项目" value="1"></el-option>
+                        </el-select>
+                    </div>
+                    <el-form-item style="flex: 1" v-if="synchronizationVal == 0">
+                        <el-select filterable collapse-tags clearable  v-model="hasChooseProjectCode" multiple placeholder="请选择" style="width:100%">
+                            <el-option v-for="item in allProjectList" :key="item.id" :label="item.projectName  + '\u3000' + item.projectCode" :value="item.projectCode">
+                                <span style="float: right; color: #8492a6; font-size: 13px;">{{ item.projectCode }}</span>
+                                <span style="float: left;">{{ item.projectName }}</span>
+                            </el-option>
+                        </el-select>
+                    </el-form-item>
+                    <el-form-item style="flex: 1" v-if="synchronizationVal == 1">
+                        <el-input placeholder="请输入项目编号" v-model="synchronizationInputVal" clearable></el-input>
+                    </el-form-item>
+                </div>
+            </el-form>
+            <span slot="footer" class="dialog-footer">
+                <el-button @click="syncProjectDig = false">取 消</el-button>
+                <el-button type="primary" @click="syncProjectForThird(hasChooseProjectCode)">开始同步</el-button>
+            </span>
+        </el-dialog>
+        <!--导入数据,下载模板 -->
+        <el-dialog :title="$t('wdorkplanimport')" v-if="importTaskDialog" :visible.sync="importTaskDialog" :close-on-click-modal="false" customClass="customWidth" width="500px">
+            <el-form ref="form4" >
+                <el-form-item :label="'1. '+$t('qing-xian-xia-zai-mo-ban-bing-tian-xie-hou-shang-chuan')" >
+                    <el-link type="primary" :underline="false" href="./upload/多项目任务导入模板.xlsx" download="多项目任务模板.xlsx'">下载多项目任务模板</el-link>
+                </el-form-item>
+            </el-form>
+            <div slot="footer" class="dialog-footer">
+                <el-upload ref="upload" action="#" :limit="1" :http-request="importTask" :show-file-list="false">
+                        <el-button type="primary" :underline="false" style="width:100%;" :loading="loadingExport">{{ $t('uoloadFiles') }}</el-button>
+                </el-upload>
+            </div>
+        </el-dialog>
     </section>
 </template>
 <style scoped>
@@ -1673,6 +1719,7 @@ a {
         },
         data() {
             return {
+                importTaskDialog: false,
                 manDaySetting:{},
                 projectManDaySettingDialog: false,
                 projectListPageComponentKey: 1,
@@ -1925,6 +1972,12 @@ a {
                 hasSetGroupInchargerId:null,
                 hasSetGroupList:[],
                 addTaskGroupInchargerDig:false,
+                filterNodePersonnel: [],
+                syncProjectDig:false,
+                allProjectList:[],
+                hasChooseProjectCode:[],
+                synchronizationVal: '0',
+                synchronizationInputVal: ''
             };
         },
         // 过滤器
@@ -1957,7 +2010,13 @@ a {
         },
         watch: {
             filterText(val) {
-                this.$refs.chooseMembTree.filter(val);
+                let { userNameNeedTranslate } = JSON.parse(sessionStorage.getItem("user"))
+                if(userNameNeedTranslate != 1) {
+                    this.$refs.chooseMembTree.filter(val);
+                }
+                if(!val) {
+                    this.$refs.chooseMembTree.filter(val);
+                }
             },
             filterText2(val) {
                 this.$refs.chooseMembTree2.filter(val);
@@ -1970,6 +2029,52 @@ a {
             })
         },
         methods: {
+            // 批量导入任务
+            importTask(item) {
+                //首先判断文件类型
+                this.loadingExport = true
+                let str = item.file.name.split(".");
+                let format = str[str.length - 1];
+                if (format != "xls" && format != "xlsx") {
+                    this.loadingExport = false
+                    this.$message({
+                        message: this.$t('other.PleaseselecttheXLSorXLSXfile'),
+                        type: "error"
+                    });
+                } else {
+                    this.listLoading = true;
+                    let formData = new FormData();
+                    formData.append("file", item.file);
+                    formData.append("isMultiProject", 1);
+                    this.http.uploadFile('/task/importTask', formData,
+                    res => {
+                        this.$refs.upload.clearFiles();
+                        this.listLoading = false;
+                        this.loadingExport = false
+                        if (res.code == "ok") {
+                            this.$message({
+                                message: this.$t('other.importSuccess'),
+                                type: "success"
+                            });
+                            this.importTaskDialog = false;
+                        } else {
+                            this.$message({
+                                message: res.msg,
+                                type: "error"
+                            });
+                        }
+                    },
+                    error => {
+                        this.$refs.upload.clearFiles();
+                        this.listLoading = false;
+                        this.loadingExport = false
+                        this.$message({
+                            message: error,
+                            type: "error"
+                        });
+                    });
+                }
+            },
             saveProjectManDaySetting() {
                 this.http.post('/estimate-time-setting/save', this.manDaySetting,
                 res => {
@@ -2947,8 +3052,16 @@ a {
 
 
             filterNode(value, data) {
+                // if (!value) return true;
+                // return data.label.indexOf(value) !== -1;
+                let { userNameNeedTranslate } = this.user
+                console.log(value, data, '《=== 执行')
                 if (!value) return true;
-                return data.label.indexOf(value) !== -1;
+                if(userNameNeedTranslate != '1') {
+                    return data.label.indexOf(value) !== -1;
+                } else {
+                    return this.filterNodePersonnel.some(item => item.includes(data.label))
+                }
             },
             //重启项目
             restartPro(row) {
@@ -3590,19 +3703,18 @@ a {
             // 企业微信搜索
             echartDepartment() {
                 console.log('我点击了搜索')
-                if(this.wxFilterText != '') {
-                    this.http.post("/department/listAllMemb", {
-                        keyword: this.wxFilterText,
-                        cursor: ''
+                if(this.filterText != '') {
+                    this.http.post("/user/getEmployeeList", {
+                        keyword: this.filterText,
+                        cursor: '',
+                        departmentId: -1,
+                        pageIndex: 1,
+                        pageSize: 1000
                     },
                     res => {
                         if (res.code == "ok") {
-                            var list = res.data.data;
-                            this.setUserToDept(list);
-                            this.deptMembData = list;
-                            this.$forceUpdate()
-                            this.searchPersonnelFlgnum = +this.searchPersonnelFlgnum +1
-                            this.searchPersonnelFlg = true
+                            this.filterNodePersonnel = res.data.records.map(item => item.name)
+                            this.$refs.chooseMembTree.filter(this.filterText);
                         } else {
                             this.$message({
                                 message: res.msg,
@@ -3940,14 +4052,20 @@ a {
                 .catch(() => {});
             },
             
-            syncProjectForThird(){
+            syncProjectForThird(hasChooseProjectCode){
                 let url=''
+                let param={}
                 if(this.user.timeType.syncFanwei==1){
                     // 美莱德同步项目信息来源泛微
                     url='/project/syncProjectWithFanwei'
                 }else if(this.user.timeType.syncSap==1){
                     // 依斯倍同步项目信息来源SAP
                     url='/project/syncProjectWithSap'
+                    if(hasChooseProjectCode){
+                        param={
+                            projectCodes: this.synchronizationVal == '0' ? hasChooseProjectCode.toString() : this.synchronizationInputVal
+                        }
+                    }
                 }
                 this.$confirm('确认同步项目数据?','提示',{
                     confirmButtonText: '确定',
@@ -3960,7 +4078,7 @@ a {
                         spinner: 'el-icon-loading',
                         background: 'rgba(0, 0, 0, 0.7)'
                     });
-                    this.http.post(url,{},
+                    this.http.post(url,param,
                     res => {
                         loading.close();
                         console.log(res, 'res')
@@ -3969,6 +4087,8 @@ a {
                                 message: '项目同步成功',
                                 type: "success"
                             });
+                            this.syncProjectDig=false
+                            this.hasChooseProjectCode=[]
                         } else {
                             this.$message({
                                 message: res.msg,
@@ -5292,6 +5412,7 @@ a {
                     for(var i in userList) {
                         arr.push(userList[i].id)
                     }
+                    this.participator = JSON.parse(JSON.stringify(this.participator))
                     this.addForm.auditUserIds = arr
                 } else if(obj.distinction == '11') {
                     let userList = obj.id
@@ -5339,6 +5460,28 @@ a {
             jisuanEstimatedWorkTime(manDay){
                 this.estimatedWorkTime=manDay*this.user.timeType.allday
             },
+            getProjectList(){
+                this.http.post(this.port.project.list,{
+                },
+                res => {
+                    this.listLoading = false;
+                    if (res.code == "ok") {
+                        this.allProjectList=res.data
+                    } else {
+                        this.$message({
+                            message: res.msg,
+                            type: "error"
+                        });
+                    }
+                },
+                error => {
+                    this.$message({
+                        message: error,
+                        type: "error"
+                    });
+                    }
+                );
+            },
             //点击添加
             addFunctional(type){
                 if(type=="functional"){
@@ -5613,8 +5756,15 @@ a {
                     });
                     }
                 );
+            },
+            
+            synchronizationChange() {
+                if(this.synchronizationVal == '1') {
+                    this.hasChooseProjectCode = []
+                } else {
+                    this.synchronizationInputVal = ''
+                }
             }
-
         },
         created() {
             let height = window.innerHeight;
@@ -5641,6 +5791,7 @@ a {
             this.getClfConfigList()
             this.yanjiuzx()
             this.getObtain()
+            this.getProjectList()
             // this.getRoleList()
 
             // 判断是否有供应商字段
@@ -5683,6 +5834,14 @@ a {
 </script>
 
 <style lang="scss" scoped>
+.synchronization {
+    display: flex;
+    justify-content: space-between;
+    // align-items: center;
+    .synchronizationLabel {
+        width: 140px;
+    }
+}
 .rg_span{
     display: inline-block;
 }

+ 121 - 21
fhKeeper/formulahousekeeper/timesheet/src/views/project/projectInside.vue

@@ -239,7 +239,7 @@
                                                         </div>
                                                     </div>
                                                 </draggable>
-                                                <el-button v-if="canAddTask" slot="footer" role="people" @click="addTask(stage)" style="width:300px;" size="small" icon="el-icon-plus"></el-button>
+                                                <el-button v-if="canAddTask && user.companyId != '3092'" slot="footer" role="people" @click="addTask(stage)" style="width:300px;" size="small" icon="el-icon-plus"></el-button>
                                                 <el-label v-if="!canAddTask && (stage.taskList.length == 0)" style="width:300px;color:#666;">{{ $t('zan-wu-ren-wu') }}</el-label>
                                             </div>
                                         </v-flex>
@@ -1146,13 +1146,14 @@
             </div>
         </el-dialog>
         
-        <el-dialog title="设置分组预估工时" v-if="modGroupManDayDialog" :visible.sync="modGroupManDayDialog" :close-on-click-modal="false" customClass="customWidth" width="450px">
-            <el-table :data="groupList" size="small" :key="Math.random()" :height="'400px'" show-summary="true">
+        <el-dialog title="设置分组预估工时" v-if="modGroupManDayDialog" :visible.sync="modGroupManDayDialog" :close-on-click-modal="false" customClass="customWidth" width="500px">
+            <el-table :data="groupList" :key="modGroupManDayKey" size="small" :height="'400px'" show-summary="true">
                 <el-table-column prop="name" label="分组名称">
                 </el-table-column>
                 <el-table-column prop="manDay" width="200" label="预估工时" >
                     <template slot-scope="scope">
-                        <el-input v-model="scope.row.manDay" type="number"  :placeholder="$t('peaseenterthe')" maxlength="10" :max="99999" style="width:120px;"></el-input>&nbsp;人天
+                        <el-input v-model="scope.row.manDay" type="number" :placeholder="$t('peaseenterthe')" maxlength="10" :max="99999" style="width:120px;" :disabled="scope.row.disabled"></el-input>&nbsp;人天&nbsp;
+                        <i v-if="user.companyId=3092 && scope.row.disabled"  @click="changeBudget(scope.row)"  class="el-icon-circle-plus-outline"></i>
                     </template>
                 </el-table-column>
             </el-table>
@@ -1161,6 +1162,28 @@
                 <el-button type="primary" @click="setManDayData()" style="width:100%;" >{{ $t('save') }}</el-button>
             </div>
         </el-dialog>
+
+        <el-dialog title="预估工时变更" v-if="changeBudgetDig" :visible.sync="changeBudgetDig" :close-on-click-modal="false" customClass="customWidth" width="500px">
+            <el-form :model="groupBudgetData" label-width="120px">
+                <el-form-item :label="'原预估工时'"><span>{{groupBudgetData.manDay}}{{ '人天' }}</span></el-form-item>
+                <el-form-item :label="'预估工时修改'" prop="changeManDay">
+                   <el-input v-model="groupBudgetData.changeManDay" type="number" @change="changeNowManDay(groupBudgetData)" :placeholder="$t('peaseenterthe')" maxlength="10" :max="99999" style="width:120px;"></el-input>&nbsp;人天
+                </el-form-item>
+                <el-form-item :label="'变更后预估工时'"><span>{{nowManDay}}{{'人天'}}</span></el-form-item>
+                <el-form-item :label="'变更理由'">
+                    <el-input
+                        type="textarea"
+                        :rows="2"
+                        placeholder="请输入内容"
+                        v-model="groupBudgetData.remark">
+                    </el-input>
+                </el-form-item>
+            </el-form>
+            <div slot="footer" class="dialog-footer">
+                <el-button @click.native="changeBudgetDig = false">{{ $t('btn.cancel') }}</el-button>
+                <el-button type="primary" @click="changeBudgetTrue(groupBudgetData)" :loading="addLoading">{{ $t('btn.submit') }}</el-button>
+            </div>
+        </el-dialog>
         <el-dialog :title="$t('addtemplate')" v-if="addToTmpDialog" :visible.sync="addToTmpDialog" :close-on-click-modal="false" customClass="customWidth" width="500px">
             <el-form ref="formTmp" :model="templateForm" :rules="rules" style="margin-top:10px;">
                     <el-form-item prop="name">
@@ -1497,7 +1520,13 @@
                 wxFilterText: '',
 
                 filterNodeFlag: false,
-                filterNodePersonnel: []
+                filterNodePersonnel: [],
+
+                changeBudgetDig:false,
+                groupBudgetData:{},
+                nowManDay:0,
+
+                modGroupManDayKey: 1
             };
             
         },
@@ -2900,6 +2929,57 @@
                     });
                 });
             },
+            //预估工时变更
+            changeBudget(task){
+                this.changeBudgetDig=true,
+                this.groupBudgetData=task,
+                this.nowManDay=(this.groupBudgetData.changeManDay==null?0:parseInt(this.groupBudgetData.changeManDay))+(this.groupBudgetData.manDay==null?0:parseInt(this.groupBudgetData.manDay))
+            },
+            //预估工时变更
+            changeNowManDay(task){
+                console.log(task)
+                this.nowManDay=(this.groupBudgetData.changeManDay==null?0:parseInt(this.groupBudgetData.changeManDay))+(this.groupBudgetData.manDay==null?0:parseInt(this.groupBudgetData.manDay))
+            },
+            changeBudgetTrue(groupBudgetData){
+                let param;
+                if(groupBudgetData){
+                    param={
+                        groupId:groupBudgetData.id,
+                        oldManDay:groupBudgetData.manDay,
+                        changeManDay:groupBudgetData.changeManDay,
+                        nowManDay:this.nowManDay,
+                        remark:groupBudgetData.remark,
+                    }
+                }
+                if(!groupBudgetData.remark) {
+                    this.$message({
+                        message: '请输入变更理由',
+                        type: "error"
+                    });
+                    return
+                }
+                this.http.post('/group-budget-review/add',param,
+                res => {
+                    if (res.code == "ok") {
+                        this.$message({
+                        message: "操作成功",
+                        type: "success"
+                        });
+                        this.changeBudgetDig=false
+                    } else {
+                        this.$message({
+                        message: res.msg,
+                        type: "error"
+                        });
+                    }
+                },
+                error => {
+                    this.$message({
+                        message: error,
+                        type: "error"
+                    });
+                });
+            },
             addTask(stage) {
                 this.mileageCup = false
                 this.addFormVisible = true;
@@ -3085,6 +3165,7 @@
                 this.setInchargerDialog = true;
             },
             setManDay(item) {
+                this.modGroupManDayKey++
                 this.groupForm = JSON.parse(JSON.stringify(item));
                 this.modGroupManDayDialog = true;
             },
@@ -3233,23 +3314,33 @@
             },
             setManDayData() {
                 this.http.post('/task-group/saveManDay',{data:JSON.stringify(this.groupList)},
-                        res => {
-                            if (res.code == "ok") {
-                                this.modGroupManDayDialog = false;
-                                this.groupList = res.data;
-                            } else {
-                                this.$message({
-                                message: res.msg,
-                                type: "error"
-                                });
-                            }
-                        },
-                        error => {
-                            this.$message({
-                                message: error,
-                                type: "error"
+                res => {
+                    if (res.code == "ok") {
+                        this.modGroupManDayDialog = false;
+                        const { companyId } = JSON.parse(sessionStorage.getItem("user"))
+                        console.log(companyId)
+                        if(companyId == '3092') {
+                            res.data.forEach(item => {
+                                item.disabled = Boolean(item.manDay);
                             });
+                            this.groupList = res.data;
+                        } else {
+                            this.groupList = res.data;
+                        }
+                        console.log(this.groupList, '返回的值')
+                    } else {
+                        this.$message({
+                        message: res.msg,
+                        type: "error"
                         });
+                    }
+                },
+                error => {
+                    this.$message({
+                        message: error,
+                        type: "error"
+                    });
+                });
             },
             // 重新定义了 addGroup 方法
              addGroup(formName) {
@@ -3300,8 +3391,17 @@
                 this.http.post('/task-group/list',{projectId: this.curProjectId},
                 res => {
                     if (res.code == "ok") {
+                        const { companyId } = this.user
                         this.allGroupData = res.data;
-                        this.groupList = res.data;
+                        if(companyId == '3092') {
+                            res.data.forEach(item => {
+                                item.disabled = Boolean(item.manDay);
+                            });
+                            this.groupList = res.data;
+                        } else {
+                            this.groupList = res.data;
+                        }
+                        console.log(this.groupList, '返回的数据')
                         console.log(this.groupList,'grouplist');
                         if (this.groupList.length > 0) {
                             this.defaultGroupId = this.groupList[0].id;

+ 0 - 0
fhKeeper/formulahousekeeper/timesheet/src/views/task/list.vue


Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor