Ver código fonte

Merge remote-tracking branch 'origin/privatedev' into privatedev

# Conflicts:
#	fhKeeper/formulahousekeeper/timesheet/src/views/project/projectInside.vue
seyason 4 anos atrás
pai
commit
09c71c5d15
74 arquivos alterados com 4286 adições e 1573 exclusões
  1. 68 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/AuditWorkflowTimeSettingController.java
  2. 108 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/CustomerInfoController.java
  3. 38 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/EarningSnapshotController.java
  4. 0 51
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ImageProcessingController.java
  5. 69 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ProjectBasecostController.java
  6. 108 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ProjectBasecostSettingController.java
  7. 21 14
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ProjectController.java
  8. 0 57
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ScreenshotController.java
  9. 9 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/UserController.java
  10. 12 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/WeiXinCorpController.java
  11. 57 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/AuditWorkflowTimeSetting.java
  12. 7 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/Company.java
  13. 78 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/CustomerInfo.java
  14. 17 37
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/EarningSnapshot.java
  15. 13 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/Project.java
  16. 60 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/ProjectBasecost.java
  17. 48 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/ProjectBasecostSetting.java
  18. 19 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/vo/CustomerProject.java
  19. 16 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/AuditWorkflowTimeSettingMapper.java
  20. 20 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/CustomerInfoMapper.java
  21. 16 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/ProjectBasecostMapper.java
  22. 16 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/ProjectBasecostSettingMapper.java
  23. 6 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/ProjectMapper.java
  24. 16 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/AuditWorkflowTimeSettingService.java
  25. 16 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/CustomerInfoService.java
  26. 16 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/ProjectBasecostService.java
  27. 16 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/ProjectBasecostSettingService.java
  28. 7 6
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/ProjectService.java
  29. 0 30
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/ScreenshotService.java
  30. 6 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/UserService.java
  31. 20 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/AuditWorkflowTimeSettingServiceImpl.java
  32. 20 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/CustomerInfoServiceImpl.java
  33. 11 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/DingDingServiceImpl.java
  34. 7 2
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/FinanceServiceImpl.java
  35. 20 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ProjectBasecostServiceImpl.java
  36. 20 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ProjectBasecostSettingServiceImpl.java
  37. 196 48
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ProjectServiceImpl.java
  38. 0 778
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ScreenshotServiceImpl.java
  39. 148 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/UserServiceImpl.java
  40. 1 42
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/task/TimingTask.java
  41. 1 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/util/CodeGenerator.java
  42. 2 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/util/Constant.java
  43. 36 36
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/util/OpenOfficeService.java
  44. 5 9
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/application-prod.yml
  45. 2 2
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/application.yml
  46. 21 0
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/AuditWorkflowTimeSettingMapper.xml
  47. 2 1
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/CompanyMapper.xml
  48. 26 0
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/CustomerInfoMapper.xml
  49. 5 9
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/EarningSnapshotMapper.xml
  50. 19 0
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/ProjectBasecostMapper.xml
  51. 17 0
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/ProjectBasecostSettingMapper.xml
  52. 49 1
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/ProjectMapper.xml
  53. BIN
      fhKeeper/formulahousekeeper/management-platform/财务人员成本模板_已填写.xlsx
  54. 9 9
      fhKeeper/formulahousekeeper/timesheet/package-lock.json
  55. 1 1
      fhKeeper/formulahousekeeper/timesheet/package.json
  56. 118 3
      fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/demo_index.html
  57. 23 3
      fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.css
  58. 1 1
      fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.js
  59. 35 0
      fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.json
  60. BIN
      fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.ttf
  61. BIN
      fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.woff
  62. BIN
      fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.woff2
  63. 6 2
      fhKeeper/formulahousekeeper/timesheet/src/main.js
  64. 26 2
      fhKeeper/formulahousekeeper/timesheet/src/routes.js
  65. 199 28
      fhKeeper/formulahousekeeper/timesheet/src/views/corpreport/list.vue
  66. 461 0
      fhKeeper/formulahousekeeper/timesheet/src/views/customer/list.vue
  67. 98 210
      fhKeeper/formulahousekeeper/timesheet/src/views/project/earning.vue
  68. 7 5
      fhKeeper/formulahousekeeper/timesheet/src/views/project/fileCenter.vue
  69. 51 16
      fhKeeper/formulahousekeeper/timesheet/src/views/project/info.vue
  70. 246 57
      fhKeeper/formulahousekeeper/timesheet/src/views/project/list.vue
  71. 1070 102
      fhKeeper/formulahousekeeper/timesheet/src/views/project/projectInside.vue
  72. 168 7
      fhKeeper/formulahousekeeper/timesheet/src/views/workReport/daily.vue
  73. 234 0
      fhKeeper/formulahousekeeper/timesheet/src/views/workflow/report.vue
  74. 22 0
      fhKeeper/formulahousekeeper/timesheet_h5/public/index.html

+ 68 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/AuditWorkflowTimeSettingController.java

@@ -0,0 +1,68 @@
+package com.management.platform.controller;
+
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.management.platform.entity.AuditWorkflowTimeSetting;
+import com.management.platform.mapper.AuditWorkflowTimeSettingMapper;
+import com.management.platform.mapper.UserMapper;
+import com.management.platform.util.HttpRespMsg;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import java.util.List;
+
+/**
+ * <p>
+ *  前端控制器
+ * </p>
+ *
+ * @author Seyason
+ * @since 2021-07-25
+ */
+@RestController
+@RequestMapping("/audit-workflow-time-setting")
+public class AuditWorkflowTimeSettingController {
+    @Resource
+    private HttpServletRequest request;
+    @Resource
+    AuditWorkflowTimeSettingMapper auditWorkflowTimeSettingMapper;
+    @Resource
+    UserMapper userMapper;
+
+    @RequestMapping("/add")
+    public HttpRespMsg add(String json) {
+        String token = request.getHeader("TOKEN");
+        Integer companyId = userMapper.selectById(token).getCompanyId();
+        auditWorkflowTimeSettingMapper.delete(new QueryWrapper<AuditWorkflowTimeSetting>().eq("company_id", companyId));
+        JSONArray array = JSONArray.parseArray(json);
+
+        for (int i=0;i<array.size(); i++) {
+            JSONObject obj = array.getJSONObject(i);
+            AuditWorkflowTimeSetting auditWorkflowTimeSetting = JSONObject.toJavaObject(obj, AuditWorkflowTimeSetting.class);
+            auditWorkflowTimeSetting.setCompanyId(companyId);
+            auditWorkflowTimeSetting.setSeq(i+1);
+            auditWorkflowTimeSettingMapper.insert(auditWorkflowTimeSetting);
+        }
+        return new HttpRespMsg();
+
+    }
+
+
+    @RequestMapping("/get")
+    public HttpRespMsg get() {
+        String token = request.getHeader("TOKEN");
+        Integer companyId = userMapper.selectById(token).getCompanyId();
+        List<AuditWorkflowTimeSetting> auditWorkflowTimeSettings = auditWorkflowTimeSettingMapper.selectList(new QueryWrapper<AuditWorkflowTimeSetting>().eq("company_id", companyId).orderByAsc("seq"));
+        HttpRespMsg msg = new HttpRespMsg();
+        msg.data = auditWorkflowTimeSettings;
+        return msg;
+    }
+
+
+}
+

+ 108 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/CustomerInfoController.java

@@ -0,0 +1,108 @@
+package com.management.platform.controller;
+
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.management.platform.entity.CustomerInfo;
+import com.management.platform.entity.Project;
+import com.management.platform.entity.User;
+import com.management.platform.mapper.CustomerInfoMapper;
+import com.management.platform.mapper.ProjectMapper;
+import com.management.platform.mapper.UserMapper;
+import com.management.platform.util.HttpRespMsg;
+import org.springframework.util.StringUtils;
+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;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <p>
+ *  前端控制器
+ * </p>
+ *
+ * @author Seyason
+ * @since 2021-07-31
+ */
+@RestController
+@RequestMapping("/customer-info")
+public class CustomerInfoController {
+    @Resource
+    private HttpServletRequest request;
+    @Resource
+    UserMapper userMapper;
+    @Resource
+    ProjectMapper projectMapper;
+    @Resource
+    CustomerInfoMapper customerInfoMapper;
+
+    @RequestMapping("/addOrMod")
+    public HttpRespMsg addOrMod(CustomerInfo info) {
+        HttpRespMsg msg = new HttpRespMsg();
+        String token = request.getHeader("TOKEN");
+        User user = userMapper.selectById(token);
+        if (info.getId() == null) {
+            info.setCompanyId(user.getCompanyId());
+            customerInfoMapper.insert(info);
+        } else {
+            info.setCompanyId(user.getCompanyId());
+            customerInfoMapper.updateById(info);
+            //更新项目表中的客户名称
+            Project p = new Project();
+            p.setCustomerName(info.getCustomerName());
+            projectMapper.update(p, new QueryWrapper<Project>().eq("customer_id", info.getId()));
+        }
+        return msg;
+    }
+
+    @RequestMapping("/delete")
+    public HttpRespMsg delete(Integer id) {
+        HttpRespMsg msg = new HttpRespMsg();
+        String token = request.getHeader("TOKEN");
+        User user = userMapper.selectById(token);
+        int r = customerInfoMapper.delete(new QueryWrapper<CustomerInfo>().eq("id", id).eq("company_id", user.getCompanyId()));
+        if (r <= 0) {
+            msg.setError("无权删除");
+        }
+        return msg;
+    }
+
+    @RequestMapping("/list")
+    public HttpRespMsg list(@RequestParam Integer pageIndex, @RequestParam Integer pageSize, String keyword) {
+        HttpRespMsg msg = new HttpRespMsg();
+        String token = request.getHeader("TOKEN");
+        User user = userMapper.selectById(token);
+        QueryWrapper<CustomerInfo> queryWrapper = new QueryWrapper<CustomerInfo>().eq("company_id", user.getCompanyId()).orderByDesc("id");
+        if (!StringUtils.isEmpty(keyword)) {
+            queryWrapper.like("customer_name", keyword);
+        }
+        IPage<CustomerInfo> projectIPage = customerInfoMapper.selectPage(new Page<>(pageIndex, pageSize),
+                queryWrapper);
+        List<CustomerInfo> list = projectIPage.getRecords();
+        Long total = projectIPage.getTotal();
+        Map<String, Object> map = new HashMap<>();
+        map.put("records", list);
+        map.put("total", total);
+        msg.data = map;
+        return msg;
+    }
+
+    @RequestMapping("/getAll")
+    public HttpRespMsg getAll() {
+        HttpRespMsg msg = new HttpRespMsg();
+        String token = request.getHeader("TOKEN");
+        User user = userMapper.selectById(token);
+        List<CustomerInfo> all = customerInfoMapper.getAll(user.getCompanyId());
+        msg.data = all;
+        return msg;
+    }
+
+}
+

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

@@ -1,21 +1,27 @@
 package com.management.platform.controller;
 
 
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.management.platform.entity.EarningSnapshot;
 import com.management.platform.entity.Project;
+import com.management.platform.entity.ProjectBasecost;
 import com.management.platform.entity.User;
 import com.management.platform.mapper.ProjectMapper;
 import com.management.platform.mapper.UserMapper;
 import com.management.platform.service.EarningSnapshotService;
 import com.management.platform.service.FinanceService;
 import com.management.platform.util.HttpRespMsg;
+import com.management.platform.util.ListUtil;
 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;
 
 /**
  * <p>
@@ -45,12 +51,43 @@ public class EarningSnapshotController {
         HttpRespMsg msg = new HttpRespMsg();
         Project project = projectMapper.selectById(projectId);
         if (userId.equals(project.getInchargerId()) || userId.equals(project.getCreatorId()) || user.getRole() > 0) {
-            msg.data = earningSnapshotService.list(new QueryWrapper<EarningSnapshot>().eq("project_id", projectId).orderByDesc("id"));
+            List<EarningSnapshot> list = earningSnapshotService.list(new QueryWrapper<EarningSnapshot>().eq("project_id", projectId).orderByDesc("id"));
+            for (EarningSnapshot snapshot : list) {
+                if (snapshot.getCostData() != null) {
+                    JSONArray array = JSONArray.parseArray(snapshot.getCostData());
+                    List<ProjectBasecost> costList = new ArrayList<>();
+                    for (int i=0;i<array.size();i++) {
+                        ProjectBasecost projectBasecost = JSONObject.toJavaObject(array.getJSONObject(i), ProjectBasecost.class);
+                        costList.add(projectBasecost);
+                    }
+                    snapshot.setCostList(costList);
+                    snapshot.setCostData(null);
+                }
+            }
+            msg.data = list;
         } else {
             msg.setError("无权查看");
         }
 
         return msg;
     }
+
+    @RequestMapping("/delete")
+    public HttpRespMsg delete(Integer projectId, String ids) {
+        String userId = request.getHeader("Token");
+        User user = userMapper.selectById(userId);
+
+
+        HttpRespMsg msg = new HttpRespMsg();
+        Project project = projectMapper.selectById(projectId);
+        if (userId.equals(project.getInchargerId()) || userId.equals(project.getCreatorId()) || user.getRole() > 0) {
+            List<Integer> idArray = ListUtil.convertIntegerIdsArrayToList(ids);
+            earningSnapshotService.removeByIds(idArray);
+        } else {
+            msg.setError("无权操作");
+        }
+
+        return msg;
+    }
 }
 

+ 0 - 51
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ImageProcessingController.java

@@ -1,51 +0,0 @@
-package com.management.platform.controller;
-
-import com.management.platform.entity.vo.ScreenshotVO;
-import com.management.platform.service.ScreenshotService;
-import com.management.platform.util.HttpRespMsg;
-import org.springframework.scheduling.annotation.EnableScheduling;
-import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import javax.annotation.Resource;
-
-/**
- * Author: 吴涛涛
- * Date : 2020 - 01 - 03 9:38
- * Description:<描述>
- * Version: 1.0
- */
-@RestController
-@RequestMapping("/imageProcessing")
-@EnableScheduling
-public class ImageProcessingController {
-
-    @Resource
-    private ScreenshotService screenshotService;
-
-    /**
-     * 参数:uid 用户id
-     * indate 截图时间 如 "2018-08-01 22:32:57"
-     * file 上传的图片文件
-     */
-    @RequestMapping("/saveAndProcessImage")
-    public HttpRespMsg pictureDetectionTask(ScreenshotVO screenshotvo) {
-        return screenshotService.saveAndProcessImage(screenshotvo);
-    }
-
-    @RequestMapping("/reTestPic")
-    public HttpRespMsg reTestPic(Integer id) {
-        return screenshotService.reTestPicMatch(id);
-    }
-    /**
-     * 初始化redis图片搜索的关键词,
-     * 防止数据库初始添加了其他字段导致redis里的数据不是最新的,
-     * 做定时在系统不忙时进行更新redis里的最新图片关键词(注意:如果想要立即更新可手动调用)
-     */
-    @RequestMapping("/updateKeyWords")
-    @Scheduled(cron = "0 0 23 * * ?")//配置时间点触发(每日23点)
-    public HttpRespMsg updateRedisPicContentKeywords() {
-        return screenshotService.updateRedisPicContentKeywords();
-    }
-
-}

+ 69 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ProjectBasecostController.java

@@ -0,0 +1,69 @@
+package com.management.platform.controller;
+
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.management.platform.entity.ProjectBasecost;
+import com.management.platform.entity.ProjectBasecostSetting;
+import com.management.platform.entity.User;
+import com.management.platform.mapper.ProjectBasecostMapper;
+import com.management.platform.mapper.ProjectBasecostSettingMapper;
+import com.management.platform.mapper.UserMapper;
+import com.management.platform.util.HttpRespMsg;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * <p>
+ *  前端控制器
+ * </p>
+ *
+ * @author Seyason
+ * @since 2021-08-02
+ */
+@RestController
+@RequestMapping("/project-basecost")
+public class ProjectBasecostController {
+
+    @Resource
+    ProjectBasecostMapper projectBasecostMapper;
+    @Resource
+    ProjectBasecostSettingMapper projectBasecostSettingMapper;
+    @Resource
+    UserMapper userMapper;
+    @Resource
+    HttpServletRequest request;
+
+    @RequestMapping("/get")
+    public HttpRespMsg get(Integer projectId) {
+        HttpRespMsg msg = new HttpRespMsg();
+        List<ProjectBasecost> list = projectBasecostMapper.selectList(new QueryWrapper<ProjectBasecost>().eq("project_id", projectId));
+        //检查最新的字段是否有
+        User user = userMapper.selectById(request.getHeader("TOKEN"));
+        List<ProjectBasecostSetting> allSettings = projectBasecostSettingMapper.selectList(new QueryWrapper<ProjectBasecostSetting>().eq("company_id", user.getCompanyId()));
+        List<ProjectBasecost> additionalList = new ArrayList<>();
+        allSettings.forEach(all->{
+            if (!list.stream().filter(costItem->costItem.getBaseId().equals(all.getId())).findAny().isPresent()) {
+                ProjectBasecost add = new ProjectBasecost();
+                add.setBaseName(all.getName());
+                add.setBaseId(all.getId());
+                add.setProjectId(projectId);
+                add.setBaseAmount(0);
+                additionalList.add(add);
+            }
+        });
+        if (additionalList.size() > 0) {
+            list.addAll(additionalList);
+        }
+        msg.data = list;
+        return msg;
+    }
+
+
+}
+

+ 108 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ProjectBasecostSettingController.java

@@ -0,0 +1,108 @@
+package com.management.platform.controller;
+
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.management.platform.entity.ProjectBasecost;
+import com.management.platform.entity.ProjectBasecostSetting;
+import com.management.platform.mapper.ProjectBasecostMapper;
+import com.management.platform.mapper.ProjectBasecostSettingMapper;
+import com.management.platform.mapper.UserMapper;
+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.List;
+
+/**
+ * <p>
+ *  前端控制器
+ * </p>
+ *
+ * @author Seyason
+ * @since 2021-08-02
+ */
+@RestController
+@RequestMapping("/project-basecost-setting")
+public class ProjectBasecostSettingController {
+    @Resource
+    private HttpServletRequest request;
+    @Resource
+    UserMapper userMapper;
+    @Resource
+    ProjectBasecostSettingMapper projectBasecostSettingMapper;
+
+    @Resource
+    ProjectBasecostMapper projectBasecostMapper;
+
+    @RequestMapping("/addOrMod")
+    public HttpRespMsg addOrMod(ProjectBasecostSetting setting) {
+        HttpRespMsg msg = new HttpRespMsg();
+        if (StringUtils.isEmpty(setting.getName())) {
+            msg.setError("名称不能为空");
+            return msg;
+        }
+        Integer companyId = userMapper.selectById(request.getHeader("TOKEN")).getCompanyId();
+        if (setting.getId() == null) {
+            setting.setCompanyId(companyId);
+            int count = projectBasecostSettingMapper.selectCount(new QueryWrapper<ProjectBasecostSetting>().eq("name", setting.getName()).eq("company_id", setting.getCompanyId()));
+            if (count > 0) {
+                msg.setError("该名称已存在");
+            } else {
+                projectBasecostSettingMapper.insert(setting);
+                msg.data = projectBasecostSettingMapper.selectList(new QueryWrapper<ProjectBasecostSetting>().eq("company_id", companyId));
+            }
+        } else {
+            int count = projectBasecostSettingMapper.selectCount(new QueryWrapper<ProjectBasecostSetting>().eq("name", setting.getName())
+                    .eq("company_id", companyId).ne("id", setting.getId()));
+            if (count > 0) {
+                msg.setError("该名称已存在");
+            } else {
+                //检查名称是否有变化
+                ProjectBasecostSetting oldSetting = projectBasecostSettingMapper.selectById(setting.getId());
+                if (!setting.getName().equals(oldSetting.getName())) {
+                    projectBasecostSettingMapper.updateById(setting);
+                    ProjectBasecost cost = new ProjectBasecost();
+                    cost.setBaseName(setting.getName());
+                    projectBasecostMapper.update(cost, new QueryWrapper<ProjectBasecost>().eq("base_id", setting.getId()));
+                }
+                msg.data = projectBasecostSettingMapper.selectList(new QueryWrapper<ProjectBasecostSetting>().eq("company_id", companyId));
+            }
+        }
+
+        return msg;
+    }
+
+    @RequestMapping("/list")
+    public HttpRespMsg list() {
+        HttpRespMsg msg = new HttpRespMsg();
+
+        Integer companyId = userMapper.selectById(request.getHeader("TOKEN")).getCompanyId();
+        List<ProjectBasecostSetting> list = projectBasecostSettingMapper.selectList(new QueryWrapper<ProjectBasecostSetting>().eq("company_id", companyId));
+        msg.data = list;
+
+        return msg;
+    }
+
+    @RequestMapping("/delete")
+    public HttpRespMsg delete(Integer id) {
+        HttpRespMsg msg = new HttpRespMsg();
+        ProjectBasecostSetting projectBasecostSetting = projectBasecostSettingMapper.selectById(id);
+        Integer companyId = userMapper.selectById(request.getHeader("TOKEN")).getCompanyId();
+        if (!projectBasecostSetting.getCompanyId().equals(companyId)) {
+            msg.setError("无权操作");
+        } else {
+            projectBasecostSettingMapper.deleteById(id);
+        }
+
+        return msg;
+    }
+
+
+
+
+}
+

+ 21 - 14
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ProjectController.java

@@ -63,26 +63,19 @@ public class ProjectController {
                                    String planEndDate,
                                    Integer level,
                                    Integer contractAmount,
-                                   Integer baseMan,
-                                   Integer baseFee,
-                                   Integer baseOutsourcing,
-                                   Integer baseRisk1,
-                                   Integer baseRisk2,
-                                   Integer budget
+                                   Integer budget,
+                                   Integer customerId,
+                                   String projectBaseCostData
                                    ) {
         return projectService.editProject(id, name, code, userId, inchargerId, planStartDate, planEndDate, level, contractAmount,
-                 baseMan,
-                 baseFee,
-                 baseOutsourcing,
-                 baseRisk1,
-                 baseRisk2,
-                 budget,request);
+                projectBaseCostData,
+                 budget,customerId,request);
     }
 
     @RequestMapping("/adjustBase")
-    public HttpRespMsg adjustBase(Project project
+    public HttpRespMsg adjustBase(String baseCostData, Project project
     ) {
-        return projectService.adjustBase(project,request);
+        return projectService.adjustBase(baseCostData, project,request);
     }
 
 
@@ -242,17 +235,31 @@ public class ProjectController {
     public HttpRespMsg getProjectInAndOut(@RequestParam Integer pageIndex, @RequestParam Integer pageSize) {
         return projectService.getProjectInAndOut(pageIndex, pageSize, request);
     }
+
+
     //导出项目收支平衡表
     @RequestMapping("/exportProjectInAndOut")
     public HttpRespMsg exportProjectInAndOut() {
         return projectService.exportProjectInAndOut(request);
     }
 
+    //分页查询客户项目统计报表
+    @RequestMapping("/getCustomerProjectInAndOut")
+    public HttpRespMsg getCustomerProjectInAndOut(@RequestParam Integer pageIndex, @RequestParam Integer pageSize) {
+        return projectService.getCustomerProjectInAndOut(pageIndex, pageSize, request);
+    }
+    //导出项目收支平衡表
+    @RequestMapping("/exportCustomerProjectInAndOut")
+    public HttpRespMsg exportCustomerProjectInAndOut() {
+        return projectService.exportCustomerProjectInAndOut(request);
+    }
+
     @RequestMapping("/importData")
     public HttpRespMsg importData(String userId, MultipartFile file, HttpServletRequest request) {
         return projectService.importData(userId, file, request);
     }
 
 
+    //
 }
 

+ 0 - 57
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ScreenshotController.java

@@ -1,57 +0,0 @@
-package com.management.platform.controller;
-
-
-import com.management.platform.service.ScreenshotService;
-import com.management.platform.util.HttpRespMsg;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
-
-import javax.servlet.http.HttpServletRequest;
-
-/**
- * <p>
- * 前端控制器
- * </p>
- *
- * @author 吴涛涛
- * @since 2020-01-03
- */
-@RestController
-@RequestMapping("/screenshot")
-public class ScreenshotController {
-    @Autowired
-    private ScreenshotService screenshotService;
-    @Autowired
-    private HttpServletRequest request;
-
-    /**
-     * 获取每个人最新的截图
-     * date 要筛选的日期 格式yyyy-mm-dd
-     */
-    @RequestMapping("/getLatestScreenshotList")
-    public HttpRespMsg getLatestScreenshotList(@RequestParam String date) {
-        return screenshotService.getLatestScreenshotList(date, request);
-    }
-
-    /**
-     * 获取某人截图列表
-     * userId 用户id
-     * date 要筛选的日期 格式yyyy-mm-dd
-     */
-    @RequestMapping("/getTodayScreenshotList")
-    public HttpRespMsg getTodayScreenshotList(@RequestParam String userId, @RequestParam String date) {
-        return screenshotService.getTodayScreenshotList(userId, date);
-    }
-
-    /**
-     * 获取最近有截图的日期
-     * date 目标日期 格式yyyy-mm-dd
-     */
-    @RequestMapping("/getScreenshotDate")
-    public HttpRespMsg getScreenshotDate(@RequestParam String date) {
-        return screenshotService.getScreenshotDate(date, request);
-    }
-}
-

+ 9 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/UserController.java

@@ -164,5 +164,14 @@ public class UserController {
     public HttpRespMsg exportUsers(Integer containInvalid) {
         return userService.exportUsers(containInvalid,request);
     }
+
+    @RequestMapping("/pushFillReport")
+    public HttpRespMsg pushFillReport(String ids, String date) {return userService.pushFillReport(ids, request, date); }
+
+    @RequestMapping("/exportMembList")
+    public HttpRespMsg exportMembList(boolean isFill, String ids, String date) {return userService.exportMembList(isFill, ids, request, date); }
+
+    @RequestMapping("/getHRList")
+    public HttpRespMsg getHRList() {return userService.getHRList(request); }
 }
 

+ 12 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/WeiXinCorpController.java

@@ -61,6 +61,8 @@ public class WeiXinCorpController {
 
     @Resource
     CompanyMapper companyMapper;
+    @Resource
+    ProjectBasecostSettingMapper projectBasecostSettingMapper;
 
     public static String SUITE_ACCESS_TOKEN = null;
     public static long suiteTokenExpireTime = 0L;
@@ -397,6 +399,16 @@ public class WeiXinCorpController {
                                 .setExpirationDate(LocalDateTime.now().plusMonths(1));
                         companyMapper.insert(company);
 
+                        //生成项目的成本基线默认条目
+                        String[] array = com.management.platform.util.Constant.DEFAULT_BASE_COST_ITEMS;
+                        for (String baseItem : array) {
+                            ProjectBasecostSetting setting = new ProjectBasecostSetting();
+                            setting.setName(baseItem);
+                            setting.setCompanyId(company.getId());
+                            projectBasecostSettingMapper.insert(setting);
+                        }
+
+
                         //生成工作时长
                         TimeType timeType = new TimeType();
                         timeType.setCompanyId(company.getId());

+ 57 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/AuditWorkflowTimeSetting.java

@@ -0,0 +1,57 @@
+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 2021-07-26
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class AuditWorkflowTimeSetting extends Model<AuditWorkflowTimeSetting> {
+
+    private static final long serialVersionUID=1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    @TableField("company_id")
+    private Integer companyId;
+
+    @TableField("role_id")
+    private Integer roleId;
+
+    @TableField("role_name")
+    private String roleName;
+
+    @TableField("seq")
+    private Integer seq;
+
+    /**
+     * 指定该节点的审核人员
+     */
+    @TableField("user_id")
+    private String userId;
+
+    @TableField("user_name")
+    private String userName;
+
+
+    @Override
+    protected Serializable pkVal() {
+        return this.id;
+    }
+
+}

+ 7 - 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 2021-05-27
+ * @since 2021-08-01
  */
 @Data
 @EqualsAndHashCode(callSuper = false)
@@ -91,6 +91,12 @@ public class Company extends Model<Company> {
     @TableField("package_expense")
     private Integer packageExpense;
 
+    /**
+     * 客户管理
+     */
+    @TableField("package_customer")
+    private Integer packageCustomer;
+
 
     @Override
     protected Serializable pkVal() {

+ 78 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/CustomerInfo.java

@@ -0,0 +1,78 @@
+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 2021-07-31
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class CustomerInfo extends Model<CustomerInfo> {
+
+    private static final long serialVersionUID=1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 客户编码
+     */
+    @TableField("customer_code")
+    private String customerCode;
+
+    /**
+     * 客户公司名称
+     */
+    @TableField("customer_name")
+    private String customerName;
+
+    /**
+     * 联系人
+     */
+    @TableField("contact_name")
+    private String contactName;
+
+    /**
+     * 联系人电话
+     */
+    @TableField("contact_phone")
+    private String contactPhone;
+
+    /**
+     * 邮箱
+     */
+    @TableField("email")
+    private String email;
+
+    /**
+     * 地址
+     */
+    @TableField("address")
+    private String address;
+
+    /**
+     * 系统公司id
+     */
+    @TableField("company_id")
+    private Integer companyId;
+
+
+    @Override
+    protected Serializable pkVal() {
+        return this.id;
+    }
+
+}

+ 17 - 37
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/EarningSnapshot.java

@@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.annotation.TableId;
 import java.time.LocalDateTime;
 import com.baomidou.mybatisplus.annotation.TableField;
 import java.io.Serializable;
+import java.util.List;
 
 import com.fasterxml.jackson.annotation.JsonFormat;
 import lombok.Data;
@@ -19,7 +20,7 @@ import org.springframework.format.annotation.DateTimeFormat;
  * </p>
  *
  * @author Seyason
- * @since 2021-05-15
+ * @since 2021-08-02
  */
 @Data
 @EqualsAndHashCode(callSuper = false)
@@ -41,8 +42,8 @@ public class EarningSnapshot extends Model<EarningSnapshot> {
      * 发生时间
      */
     @TableField("indate")
-    @DateTimeFormat(pattern = "yyyy-MM-dd")
     @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
     private LocalDateTime indate;
 
     /**
@@ -64,53 +65,32 @@ public class EarningSnapshot extends Model<EarningSnapshot> {
     private Integer contractAmount;
 
     /**
-     * 人员成本
+     * 利润
      */
-    @TableField("base_man")
-    private Integer baseMan;
+    @TableField("profit")
+    private Integer profit;
 
     /**
-     * 费用
+     * 利润率
      */
-    @TableField("base_fee")
-    private Integer baseFee;
+    @TableField("profit_percent")
+    private Double profitPercent;
 
     /**
-     * 外包费用
+     * 总成本
      */
-    @TableField("base_outsourcing")
-    private Integer baseOutsourcing;
+    @TableField("cost_total")
+    private Integer costTotal;
 
     /**
-     * 风险预留金额1
+     * 细分项
      */
-    @TableField("base_risk1")
-    private Integer baseRisk1;
+    @TableField("cost_data")
+    private String costData;
 
-    /**
-     * 风险预留金额2
-     */
-    @TableField("base_risk2")
-    private Integer baseRisk2;
-
-    /**
-     * 利润率A
-     */
-    @TableField("profit_a")
-    private Double profitA;
-
-    /**
-     * 利润率B
-     */
-    @TableField("profit_b")
-    private Double profitB;
-
-    /**
-     * 利润率C
-     */
-    @TableField("profit_c")
-    private Double profitC;
 
+    @TableField(exist = false)
+    private List<ProjectBasecost> costList;
 
     @Override
     protected Serializable pkVal() {

+ 13 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/Project.java

@@ -21,7 +21,7 @@ import org.springframework.format.annotation.DateTimeFormat;
  * </p>
  *
  * @author Seyason
- * @since 2021-06-22
+ * @since 2021-08-01
  */
 @Data
 @EqualsAndHashCode(callSuper = false)
@@ -194,6 +194,18 @@ public class Project extends Model<Project> {
 
     @TableField(exist = false)
     private List<Map<String, Object>> participationList;
+    /**
+     * 客户id
+     */
+    @TableField("customer_id")
+    private Integer customerId;
+
+    /**
+     * 客户名称
+     */
+    @TableField("customer_name")
+    private String customerName;
+
 
     @Override
     protected Serializable pkVal() {

+ 60 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/ProjectBasecost.java

@@ -0,0 +1,60 @@
+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 2021-08-02
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class ProjectBasecost extends Model<ProjectBasecost> {
+
+    private static final long serialVersionUID=1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 项目id
+     */
+    @TableField("project_id")
+    private Integer projectId;
+
+    /**
+     * 预算项id
+     */
+    @TableField("base_id")
+    private Integer baseId;
+
+    /**
+     * 预算项名称
+     */
+    @TableField("base_name")
+    private String baseName;
+
+    /**
+     * 预算金额
+     */
+    @TableField("base_amount")
+    private Integer baseAmount;
+
+
+    @Override
+    protected Serializable pkVal() {
+        return this.id;
+    }
+
+}

+ 48 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/ProjectBasecostSetting.java

@@ -0,0 +1,48 @@
+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 2021-08-02
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class ProjectBasecostSetting extends Model<ProjectBasecostSetting> {
+
+    private static final long serialVersionUID=1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 预估成本项名称
+     */
+    @TableField("name")
+    private String name;
+
+    /**
+     * 公司id
+     */
+    @TableField("company_id")
+    private Integer companyId;
+
+
+    @Override
+    protected Serializable pkVal() {
+        return this.id;
+    }
+
+}

+ 19 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/vo/CustomerProject.java

@@ -0,0 +1,19 @@
+package com.management.platform.entity.vo;
+
+import com.management.platform.entity.Project;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.util.List;
+
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class CustomerProject extends Project {
+    private Integer projectNum;
+    private String projectIds;
+    private String projectNames;
+
+    private List<CustomerProject> children;
+}

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

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

+ 20 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/CustomerInfoMapper.java

@@ -0,0 +1,20 @@
+package com.management.platform.mapper;
+
+import com.management.platform.entity.CustomerInfo;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.springframework.test.context.jdbc.Sql;
+
+import java.util.List;
+
+/**
+ * <p>
+ *  Mapper 接口
+ * </p>
+ *
+ * @author Seyason
+ * @since 2021-07-31
+ */
+public interface CustomerInfoMapper extends BaseMapper<CustomerInfo> {
+
+    public List<CustomerInfo> getAll(Integer companyId);
+}

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

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

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

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

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

@@ -2,6 +2,7 @@ package com.management.platform.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.management.platform.entity.Project;
+import com.management.platform.entity.vo.CustomerProject;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Update;
@@ -36,4 +37,9 @@ public interface ProjectMapper extends BaseMapper<Project> {
 
     List<Project> getProjectInAndOut(Integer companyId, Integer pageStart, Integer pageSize);
 
+    List<CustomerProject> getCustomerProjectInAndOut(Integer companyId, Integer pageStart, Integer pageSize);
+
+    Integer getCustomerProjectInAndOutCount(Integer companyId);
+
+    List<CustomerProject> getProjectInAndOutByRange(Integer companyId, List<Integer> ids);
 }

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

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

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

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

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

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

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

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

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

@@ -26,12 +26,9 @@ public interface ProjectService extends IService<Project> {
                             String planEndDate,
                             Integer level,
                             Integer contractAmount,
-                            Integer baseMan,
-                            Integer baseFee,
-                            Integer baseOutsourcing,
-                            Integer baseRisk1,
-                            Integer baseRisk2,
+                            String projectBaseCostData,
                             Integer budget,
+                            Integer customerId,
                             HttpServletRequest request);
 
     HttpRespMsg deleteProject(Integer id);
@@ -56,7 +53,7 @@ public interface ProjectService extends IService<Project> {
 
     HttpRespMsg addMemb(Integer id, String[] userId);
 
-    HttpRespMsg adjustBase(Project project, HttpServletRequest request);
+    HttpRespMsg adjustBase(String baseCostData, Project project, HttpServletRequest request);
 
     HttpRespMsg exportProfit(HttpServletRequest request);
 
@@ -75,4 +72,8 @@ public interface ProjectService extends IService<Project> {
     HttpRespMsg exportProjectInAndOut(HttpServletRequest request);
 
     HttpRespMsg importData(String userId, MultipartFile file, HttpServletRequest request);
+
+    HttpRespMsg getCustomerProjectInAndOut(Integer pageIndex, Integer pageSize, HttpServletRequest request);
+
+    HttpRespMsg exportCustomerProjectInAndOut(HttpServletRequest request);
 }

+ 0 - 30
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/ScreenshotService.java

@@ -1,30 +0,0 @@
-package com.management.platform.service;
-
-import com.baomidou.mybatisplus.extension.service.IService;
-import com.management.platform.entity.Screenshot;
-import com.management.platform.entity.vo.ScreenshotVO;
-import com.management.platform.util.HttpRespMsg;
-
-import javax.servlet.http.HttpServletRequest;
-
-/**
- * <p>
- * 服务类
- * </p>
- *
- * @author 吴涛涛
- * @since 2020-01-02
- */
-public interface ScreenshotService extends IService<Screenshot> {
-    HttpRespMsg getLatestScreenshotList(String date, HttpServletRequest request);
-
-    HttpRespMsg getTodayScreenshotList(String userId, String date);
-
-    HttpRespMsg getScreenshotDate(String date, HttpServletRequest request);
-
-    HttpRespMsg saveAndProcessImage(ScreenshotVO screenshotvo);
-
-    HttpRespMsg reTestPicMatch(int id);
-
-    HttpRespMsg updateRedisPicContentKeywords();
-}

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

@@ -49,4 +49,10 @@ public interface UserService extends IService<User> {
     HttpRespMsg exportUsers(Integer containInvalid, HttpServletRequest request);
 
     HttpRespMsg sendVcode(String mobile);
+
+    HttpRespMsg pushFillReport(String ids, HttpServletRequest request, String date);
+
+    HttpRespMsg exportMembList(boolean isFill, String ids, HttpServletRequest request, String date);
+
+    HttpRespMsg getHRList(HttpServletRequest request);
 }

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

@@ -0,0 +1,20 @@
+package com.management.platform.service.impl;
+
+import com.management.platform.entity.AuditWorkflowTimeSetting;
+import com.management.platform.mapper.AuditWorkflowTimeSettingMapper;
+import com.management.platform.service.AuditWorkflowTimeSettingService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ *  服务实现类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2021-07-25
+ */
+@Service
+public class AuditWorkflowTimeSettingServiceImpl extends ServiceImpl<AuditWorkflowTimeSettingMapper, AuditWorkflowTimeSetting> implements AuditWorkflowTimeSettingService {
+
+}

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

@@ -0,0 +1,20 @@
+package com.management.platform.service.impl;
+
+import com.management.platform.entity.CustomerInfo;
+import com.management.platform.mapper.CustomerInfoMapper;
+import com.management.platform.service.CustomerInfoService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ *  服务实现类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2021-07-31
+ */
+@Service
+public class CustomerInfoServiceImpl extends ServiceImpl<CustomerInfoMapper, CustomerInfo> implements CustomerInfoService {
+
+}

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

@@ -64,6 +64,8 @@ public class DingDingServiceImpl implements DingDingService {
     private UserService userService;
     @Resource
     private ProjectMapper projectMapper;
+    @Resource
+    private ProjectBasecostSettingMapper projectBasecostSettingMapper;
 
     @Override
     @Async
@@ -94,6 +96,15 @@ public class DingDingServiceImpl implements DingDingService {
             TimeType timeType = new TimeType();
             timeType.setCompanyId(company.getId());
             timeTypeMapper.insert(timeType);
+
+            //生成项目的成本基线默认条目
+            String[] array = com.management.platform.util.Constant.DEFAULT_BASE_COST_ITEMS;
+            for (String baseItem : array) {
+                ProjectBasecostSetting setting = new ProjectBasecostSetting();
+                setting.setName(baseItem);
+                setting.setCompanyId(company.getId());
+                projectBasecostSettingMapper.insert(setting);
+            }
         }
 
 

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

@@ -359,7 +359,11 @@ public class FinanceServiceImpl extends ServiceImpl<FinanceMapper, Finance> impl
                     medical = userFinance.getInsuranceMedical().multiply(new BigDecimal(workingTime)).divide(userTime.get(creatorId).workingTime, 4, BigDecimal.ROUND_HALF_UP);
                     loseJob = userFinance.getInsuranceLosejob().multiply(new BigDecimal(workingTime)).divide(userTime.get(creatorId).workingTime, 4, BigDecimal.ROUND_HALF_UP);
                     house = userFinance.getHouseFund().multiply(new BigDecimal(workingTime)).divide(userTime.get(creatorId).workingTime, 4, BigDecimal.ROUND_HALF_UP);
-                    other = userFinance.getOthers().multiply(new BigDecimal(workingTime)).divide(userTime.get(creatorId).workingTime, 4, BigDecimal.ROUND_HALF_UP);
+                    if (userFinance.getOthers() == null) {
+                        other = new BigDecimal(0);
+                    } else {
+                        other = userFinance.getOthers().multiply(new BigDecimal(workingTime)).divide(userTime.get(creatorId).workingTime, 4, BigDecimal.ROUND_HALF_UP);
+                    }
                 } else {
                     System.out.println("财务数据中未找到用户:"+creatorId);
 
@@ -463,7 +467,7 @@ public class FinanceServiceImpl extends ServiceImpl<FinanceMapper, Finance> impl
                         BigDecimal medical = userFinance.getInsuranceMedical().multiply(new BigDecimal(workingTime)).divide(userTime.get(creatorId).workingTime, 4, BigDecimal.ROUND_HALF_UP);
                         BigDecimal loseJob = userFinance.getInsuranceLosejob().multiply(new BigDecimal(workingTime)).divide(userTime.get(creatorId).workingTime, 4, BigDecimal.ROUND_HALF_UP);
                         BigDecimal house = userFinance.getHouseFund().multiply(new BigDecimal(workingTime)).divide(userTime.get(creatorId).workingTime, 4, BigDecimal.ROUND_HALF_UP);
-                        BigDecimal other = userFinance.getOthers().multiply(new BigDecimal(workingTime)).divide(userTime.get(creatorId).workingTime, 4, BigDecimal.ROUND_HALF_UP);
+                        BigDecimal other = userFinance.getOthers() == null?new BigDecimal(0):userFinance.getOthers().multiply(new BigDecimal(workingTime)).divide(userTime.get(creatorId).workingTime, 4, BigDecimal.ROUND_HALF_UP);
 
                         membRowData.add(us.getName());
                         membRowData.add(workingTime+"");
@@ -504,6 +508,7 @@ public class FinanceServiceImpl extends ServiceImpl<FinanceMapper, Finance> impl
 
             httpRespMsg.data = resp;
         } catch (NullPointerException e) {
+            e.printStackTrace();
             httpRespMsg.setError("验证失败");
             return httpRespMsg;
         }

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

@@ -0,0 +1,20 @@
+package com.management.platform.service.impl;
+
+import com.management.platform.entity.ProjectBasecost;
+import com.management.platform.mapper.ProjectBasecostMapper;
+import com.management.platform.service.ProjectBasecostService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ *  服务实现类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2021-08-02
+ */
+@Service
+public class ProjectBasecostServiceImpl extends ServiceImpl<ProjectBasecostMapper, ProjectBasecost> implements ProjectBasecostService {
+
+}

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

@@ -0,0 +1,20 @@
+package com.management.platform.service.impl;
+
+import com.management.platform.entity.ProjectBasecostSetting;
+import com.management.platform.mapper.ProjectBasecostSettingMapper;
+import com.management.platform.service.ProjectBasecostSettingService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ *  服务实现类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2021-08-02
+ */
+@Service
+public class ProjectBasecostSettingServiceImpl extends ServiceImpl<ProjectBasecostSettingMapper, ProjectBasecostSetting> implements ProjectBasecostSettingService {
+
+}

+ 196 - 48
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ProjectServiceImpl.java

@@ -1,10 +1,13 @@
 package com.management.platform.service.impl;
 
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.management.platform.entity.*;
+import com.management.platform.entity.vo.CustomerProject;
 import com.management.platform.entity.vo.ProjectDataItem;
 import com.management.platform.entity.vo.ProjectVO;
 import com.management.platform.mapper.*;
@@ -74,6 +77,10 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
     @Resource
     private TimeTypeMapper timeTypeMapper;
     @Resource
+    CustomerInfoMapper customerInfoMapper;
+    @Resource
+    ProjectBasecostMapper projectBasecostMapper;
+    @Resource
     private HttpServletResponse response;
 
     @Value(value = "${upload.path}")
@@ -98,7 +105,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
     //分页获取项目列表
     @Override
     public HttpRespMsg getProjectPage(Integer pageIndex, Integer pageSize, String keyword, Integer searchField,
-                                      Integer status,HttpServletRequest request) {
+                                      Integer status, HttpServletRequest request) {
         HttpRespMsg httpRespMsg = new HttpRespMsg();
         try {
             //通过公司id获取该公司所有的项目列表
@@ -170,12 +177,9 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                                    String planEndDate,
                                    Integer level,
                                    Integer contractAmount,
-                                   Integer baseMan,
-                                   Integer baseFee,
-                                   Integer baseOutsourcing,
-                                   Integer baseRisk1,
-                                   Integer baseRisk2,
+                                   String projectBaseCostData,
                                    Integer budget,
+                                   Integer customerId,
                                    HttpServletRequest request) {
         HttpRespMsg httpRespMsg = new HttpRespMsg();
         User user = userMapper.selectById(request.getHeader("Token"));
@@ -200,44 +204,37 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                             .setCreateDate(LocalDate.now())
                             .setContractAmount(contractAmount)
                             .setBudget(budget)
-                            .setBaseFee(baseFee)
-                            .setBaseMan(baseMan)
-                            .setBaseOutsourcing(baseOutsourcing)
-                            .setBaseRisk1(baseRisk1)
-                            .setBaseRisk2(baseRisk2);
+                            .setCustomerId(customerId);
                     if (!StringUtils.isEmpty(planStartDate)) {
                         project.setPlanStartDate(LocalDate.parse(planStartDate));
                     }
                     if (!StringUtils.isEmpty(planEndDate)) {
                         project.setPlanEndDate(LocalDate.parse(planEndDate));
                     }
+                    if (customerId != null && customerId != 0) {
+                        project.setCustomerName(customerInfoMapper.selectById(customerId).getCustomerName());
+                    } else {
+                        project.setCustomerName("");
+                    }
                     if (projectMapper.insert(project) == 0) {
                         httpRespMsg.setError("操作失败");
                     } else {
+                        updateProjectBaseCostData(projectBaseCostData, project.getId());
+
                         //创建项目涉及到基线成本数据,要填写到快照表中
                         EarningSnapshot snapshot = new EarningSnapshot();
                         snapshot.setProjectId(project.getId());
                         snapshot.setContractAmount(project.getContractAmount());
-                        snapshot.setBaseMan(project.getBaseMan());
-                        snapshot.setBaseOutsourcing(project.getBaseOutsourcing());
-                        snapshot.setBaseFee(project.getBaseFee());
-                        snapshot.setBaseRisk1(project.getBaseRisk1());
-                        snapshot.setBaseRisk2(project.getBaseRisk2());
+                        snapshot.setCostData(projectBaseCostData);
                         snapshot.setCreatorId(user.getId());
                         snapshot.setCreatorName(user.getName());
+                        snapshot.setCostTotal(budget);
 
                         if (project.getContractAmount() == null || project.getContractAmount() == 0 ) {
                             //无需处理
                         } else {
-                            int bf = getNotNullInt(project.getBaseFee());
-                            int bm = getNotNullInt(project.getBaseMan());
-                            int bos = getNotNullInt(project.getBaseOutsourcing());
-                            int br1 = getNotNullInt(project.getBaseRisk1());
-                            int br2 = getNotNullInt(project.getBaseRisk2());
-                            int total = bf + +bm + bos +br1 + br2;
-                            snapshot.setProfitA(100.0*(project.getContractAmount() - total)/project.getContractAmount());
-                            snapshot.setProfitB(100.0*(project.getContractAmount() - total-br1)/project.getContractAmount());
-                            snapshot.setProfitC(100.0*(project.getContractAmount() - total-br1 - br2)/project.getContractAmount());
+                            snapshot.setProfit(project.getContractAmount() - budget);
+                            snapshot.setProfitPercent(100.0*(project.getContractAmount() - budget)/project.getContractAmount());
                             earningSnapshotMapper.insert(snapshot);
                         }
                     }
@@ -248,10 +245,9 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
             //修改项目
             //检查项目编号不能重复
             Integer count = 0;
-            if (code != null) {
+            if (!StringUtils.isEmpty(code)) {
                 count = projectMapper.selectCount(new QueryWrapper<Project>().eq("company_id", companyId).eq("project_code", code).ne("id", id));
             }
-
             if (count > 0) {
                 httpRespMsg.setError("提交失败:项目编号已存在");
             } else {
@@ -260,17 +256,18 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                         .setLevel(level)
                         .setContractAmount(contractAmount)
                         .setBudget(budget)
-                        .setBaseFee(baseFee)
-                        .setBaseMan(baseMan)
-                        .setBaseOutsourcing(baseOutsourcing)
-                        .setBaseRisk1(baseRisk1)
-                        .setBaseRisk2(baseRisk2);;
+                        .setCustomerId(customerId);
                 if (!StringUtils.isEmpty(planStartDate)) {
                     p.setPlanStartDate(LocalDate.parse(planStartDate));
                 }
                 if (!StringUtils.isEmpty(planEndDate)) {
                     p.setPlanEndDate(LocalDate.parse(planEndDate));
                 }
+                if (customerId != null && customerId != 0) {
+                    p.setCustomerName(customerInfoMapper.selectById(customerId).getCustomerName());
+                } else {
+                    p.setCustomerName("");
+                }
                 if (projectMapper.updateById(p) == 0) {
                     httpRespMsg.setError("操作失败");
                 } else {
@@ -278,6 +275,56 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                     ProjectTimer timer = new ProjectTimer();
                     timer.setProjectName(name);
                     projectTimerMapper.update(timer, new QueryWrapper<ProjectTimer>().eq("project_id", id));
+
+                    List<ProjectBasecost> costList = updateProjectBaseCostData(projectBaseCostData, p.getId());
+
+                    //如果不存在基线成本快照,则生成
+                    List<EarningSnapshot> earningSnapshots = earningSnapshotMapper.selectList(new QueryWrapper<EarningSnapshot>().eq("project_id", p.getId()).orderByDesc("id").last("limit 1"));
+                    boolean shouldAdd = false;
+                    if (earningSnapshots.size() == 0) {
+                        shouldAdd = true;
+                    } else {
+                        //检查是否发生变化
+                        String data = earningSnapshots.get(0).getCostData();
+                        if (data == null) {
+                            shouldAdd = true;
+                        } else {
+                            JSONArray oldArray = JSONArray.parseArray(data);
+                            if (oldArray.size() != costList.size()) {
+                                //条目数量有变化,需要新增
+                                shouldAdd = true;
+                            } else {
+                                for (int i=0; i<oldArray.size(); i++) {
+                                    JSONObject jsonObject = oldArray.getJSONObject(i);
+                                    ProjectBasecost projectBasecost = JSONObject.toJavaObject(jsonObject, ProjectBasecost.class);
+                                    Optional<ProjectBasecost> first = costList.stream().filter(cost -> cost.getBaseId().equals(projectBasecost.getBaseId())).findFirst();
+                                    if (first.isPresent()) {
+                                        if (!first.get().getBaseAmount().equals(projectBasecost.getBaseAmount())) {
+                                            shouldAdd = true;
+                                            break;
+                                        }
+                                    } else {
+                                        //有新增的条目,需要增加
+                                        shouldAdd = true;
+                                        break;
+                                    }
+                                }
+                            }
+
+                        }
+                    }
+                    if (shouldAdd) {
+                        EarningSnapshot record = new EarningSnapshot();
+                        record.setProjectId(p.getId());
+                        record.setCreatorId(user.getId());
+                        record.setCreatorName(user.getName());
+                        record.setContractAmount(p.getContractAmount());
+                        record.setCostData(projectBaseCostData);
+                        record.setCostTotal(p.getBudget());
+                        record.setProfit(p.getContractAmount() - p.getBudget());
+                        record.setProfitPercent(100.0*(p.getContractAmount() - p.getBudget())/p.getContractAmount());
+                        earningSnapshotMapper.insert(record);
+                    }
                 }
             }
         }
@@ -293,6 +340,20 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
         return httpRespMsg;
     }
 
+    //更新项目的基线成本数据
+    private List<ProjectBasecost> updateProjectBaseCostData(String data, Integer projectId) {
+        JSONArray array = JSONArray.parseArray(data);
+        projectBasecostMapper.delete(new QueryWrapper<ProjectBasecost>().eq("project_id", projectId));
+        List<ProjectBasecost> costList = new ArrayList<>();
+        for (int i=0;i<array.size(); i++) {
+            ProjectBasecost projectBasecost = JSONObject.toJavaObject(array.getJSONObject(i), ProjectBasecost.class);
+            projectBasecost.setProjectId(projectId);
+            projectBasecostMapper.insert(projectBasecost);
+            costList.add(projectBasecost);
+        }
+        return costList;
+    }
+
     private int getNotNullInt(Integer integer) {
         return integer==null?0:integer.intValue();
     }
@@ -518,15 +579,24 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
     }
 
     @Override
-    public HttpRespMsg adjustBase(Project project, HttpServletRequest request) {
+    public HttpRespMsg adjustBase(String baseCostData, Project project, HttpServletRequest request) {
         HttpRespMsg msg = new HttpRespMsg();
         if (project.getContractAmount() == 0) {
             msg.setError("项目金额不能为0");
             return msg;
         }
         //计算项目总成本
-        project.setBudget(project.getBaseFee()+project.getBaseMan()
-                    +project.getBaseOutsourcing()+project.getBaseRisk1()+project.getBaseRisk2());
+        projectBasecostMapper.delete(new QueryWrapper<ProjectBasecost>().eq("project_id", project.getId()));
+        JSONArray array = JSONArray.parseArray(baseCostData);
+        int totalBudget = 0;
+        for (int i=0;i<array.size(); i++) {
+            JSONObject obj = array.getJSONObject(i);
+            ProjectBasecost cost = JSONObject.toJavaObject(obj, ProjectBasecost.class);
+            cost.setProjectId(project.getId());
+            projectBasecostMapper.insert(cost);
+            totalBudget += cost.getBaseAmount();
+        }
+        project.setBudget(totalBudget);
         projectMapper.updateById(project);
         //增加基线快照
         User user = userMapper.selectById(request.getHeader("Token"));
@@ -535,18 +605,11 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
         record.setCreatorId(user.getId());
         record.setCreatorName(user.getName());
         record.setContractAmount(project.getContractAmount());
-        record.setBaseFee(project.getBaseFee());
-        record.setBaseMan(project.getBaseMan());
-        record.setBaseOutsourcing(project.getBaseOutsourcing());
-        record.setBaseRisk1(project.getBaseRisk1());
-        record.setBaseRisk2(project.getBaseRisk2());
-        int total = project.getBaseFee()+project.getBaseMan()+project.getBaseOutsourcing()+project.getBaseRisk1()+project.getBaseRisk2();
-
-        record.setProfitA(100.0*(project.getContractAmount() - total)/project.getContractAmount());
-        record.setProfitB(100.0*(project.getContractAmount() - total-project.getBaseRisk1())/project.getContractAmount());
-        record.setProfitC(100.0*(project.getContractAmount() - total-project.getBaseRisk1() - project.getBaseRisk2())/project.getContractAmount());
+        record.setCostData(baseCostData);
+        record.setCostTotal(project.getBudget());
+        record.setProfit(project.getContractAmount() - totalBudget);
+        record.setProfitPercent(100.0*(project.getContractAmount() - totalBudget)/project.getContractAmount());
         earningSnapshotMapper.insert(record);
-
         return new HttpRespMsg();
     }
 
@@ -770,12 +833,10 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
         User user = userMapper.selectById(request.getHeader("Token"));
         Integer companyId = user.getCompanyId();
         //撤销的项目不算
-        //撤销的项目不算
         QueryWrapper<Project> queryWrapper = new QueryWrapper<Project>().eq("company_id", companyId);
         queryWrapper.and(wrapper->wrapper.isNull("status").or().ne("status", 3));
         int total = projectMapper.selectCount(queryWrapper);
         int pageStart = (pageIndex -1) * pageSize;
-        System.out.println("companyId="+companyId+", pageStart="+pageStart+", pageSize="+pageSize);
         List projectTask = projectMapper.getProjectInAndOut(companyId, pageStart, pageSize);
         HttpRespMsg httpRespMsg = new HttpRespMsg();
         Map<String, Object> map = new HashMap<>();
@@ -785,6 +846,26 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
         return httpRespMsg;
     }
 
+    @Override
+    public HttpRespMsg getCustomerProjectInAndOut(Integer pageIndex, Integer pageSize, HttpServletRequest request) {
+        User user = userMapper.selectById(request.getHeader("Token"));
+        Integer companyId = user.getCompanyId();
+
+        int total = projectMapper.getCustomerProjectInAndOutCount(companyId);
+        int pageStart = (pageIndex -1) * pageSize;
+        List<CustomerProject> list = projectMapper.getCustomerProjectInAndOut(companyId, pageStart, pageSize);
+        list.forEach(data->{
+            List<Integer> integers = ListUtil.convertIntegerIdsArrayToList(data.getProjectIds());
+            data.setChildren(projectMapper.getProjectInAndOutByRange(companyId, integers));
+        });
+        HttpRespMsg httpRespMsg = new HttpRespMsg();
+        Map<String, Object> map = new HashMap<>();
+        map.put("records", list);
+        map.put("total", total);
+        httpRespMsg.data = map;
+        return httpRespMsg;
+    }
+
     @Override
     public HttpRespMsg exportProjectInAndOut(HttpServletRequest request) {
         HttpRespMsg httpRespMsg = new HttpRespMsg();
@@ -825,6 +906,73 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
         return httpRespMsg;
     }
 
+    @Override
+    public HttpRespMsg exportCustomerProjectInAndOut(HttpServletRequest request) {
+        HttpRespMsg httpRespMsg = new HttpRespMsg();
+        //通过公司id获取该公司所有的项目列表
+        User user = userMapper.selectById(request.getHeader("Token"));
+        Integer companyId = user.getCompanyId();
+
+        List<CustomerProject> projectList = projectMapper.getCustomerProjectInAndOut(companyId, null, null);
+        List<List<String>> exportList = new ArrayList<>();
+        String[] titles = {"客户名称", "相关项目", "合同金额", "人工成本", "一般费用", "差旅费用","外包费用", "总费用", "利润", "利润率"};
+        exportList.add(Lists.list(titles));
+        for (CustomerProject project : projectList) {
+            List<String> data = new ArrayList<>();
+            data.add(project.getCustomerName());
+            //客户上把项目空着
+            data.add("");
+            data.add(project.getContractAmount() != null?project.getContractAmount().toString():"");
+            data.add(project.getFeeMan().toString());
+            data.add(project.getFeeNormal().toString());
+            data.add(project.getFeeTravel().toString());
+            data.add(project.getFeeOutsourcing().toString());
+            double totalFee = project.getFeeMan() + project.getFeeNormal()+ project.getFeeTravel()+ project.getFeeOutsourcing();
+            data.add(totalFee+"");
+            if (project.getContractAmount() != null && project.getContractAmount() > 0) {
+                double profitAmt = project.getContractAmount() - totalFee;
+                data.add(profitAmt+"");
+                data.add(new java.text.DecimalFormat("#.0").format((100*profitAmt/project.getContractAmount()))+"%");
+            } else {
+                double profitAmt = -totalFee;
+                data.add(profitAmt+"");
+                data.add("");
+            }
+            exportList.add(data);
+
+            //查找项目,项目上把客户空着
+            List<CustomerProject> projectInAndOutByRange = projectMapper.getProjectInAndOutByRange(companyId, ListUtil.convertIntegerIdsArrayToList(project.getProjectIds()));
+            projectInAndOutByRange.forEach(child->{
+                List<String> dataChild = new ArrayList<>();
+                dataChild.add("");
+                //客户上把项目空着
+                dataChild.add(child.getProjectNames());
+                dataChild.add(child.getContractAmount() != null?child.getContractAmount().toString():"");
+                dataChild.add(child.getFeeMan().toString());
+                dataChild.add(child.getFeeNormal().toString());
+                dataChild.add(child.getFeeTravel().toString());
+                dataChild.add(child.getFeeOutsourcing().toString());
+                double totalFeeChild = child.getFeeMan() + child.getFeeNormal()+ child.getFeeTravel()+ child.getFeeOutsourcing();
+                dataChild.add(totalFeeChild+"");
+                if (child.getContractAmount() != null && child.getContractAmount() > 0) {
+                    double profitAmt = child.getContractAmount() - totalFeeChild;
+                    dataChild.add(profitAmt+"");
+                    dataChild.add(new java.text.DecimalFormat("#.0").format((100*profitAmt/project.getContractAmount()))+"%");
+                } else {
+                    double profitAmt = -totalFeeChild;
+                    dataChild.add(profitAmt+"");
+                    dataChild.add("");
+                }
+                exportList.add(dataChild);
+            });
+
+        }
+        String fileName = "客户项目利润报表_"+System.currentTimeMillis();
+        ExcelUtil.exportGeneralExcelByTitleAndList(fileName, exportList, path);
+        httpRespMsg.data =  pathPrefix + fileName+".xls";
+        return httpRespMsg;
+    }
+
     @Override
     public HttpRespMsg importData(String userId, MultipartFile multipartFile, HttpServletRequest request) {
         HttpRespMsg msg = new HttpRespMsg();

+ 0 - 778
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ScreenshotServiceImpl.java

@@ -1,778 +0,0 @@
-package com.management.platform.service.impl;
-
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.management.platform.constant.Constant;
-import com.management.platform.constant.Parameter;
-import com.management.platform.entity.PicContentKeywords;
-import com.management.platform.entity.Screenshot;
-import com.management.platform.entity.TimeCalculation;
-import com.management.platform.entity.TimeCalculationShow;
-import com.management.platform.entity.vo.ScreenshotVO;
-import com.management.platform.mapper.*;
-import com.management.platform.service.ScreenshotService;
-import com.management.platform.util.*;
-import org.apache.log4j.Logger;
-import org.springframework.beans.BeanUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import javax.annotation.Resource;
-import javax.imageio.ImageIO;
-import javax.servlet.http.HttpServletRequest;
-import java.awt.image.BufferedImage;
-import java.io.*;
-import java.text.SimpleDateFormat;
-import java.time.LocalDate;
-import java.time.LocalTime;
-import java.time.format.DateTimeFormatter;
-import java.time.temporal.ChronoUnit;
-import java.util.*;
-import java.util.regex.Pattern;
-
-/**
- * <p>
- * 服务实现类
- * </p>
- *
- * @author 吴涛涛
- * @since 2020-01-02
- */
-@Service
-@Transactional
-public class ScreenshotServiceImpl extends ServiceImpl<ScreenshotMapper, Screenshot> implements ScreenshotService {
-    public static List<String> nKeyWordsList = new ArrayList<String>();
-    public static Logger log = Logger.getLogger(ScreenshotServiceImpl.class);
-
-    //检测时间间隔秒数
-    private static Integer DETECTION_INTERVAL = 600;
-
-    @Value(value = "${upload.path}")
-    private String path;
-    @Value(value = "${picrecongnize.browser}")
-    private String browserFolder;
-    @Value(value = "${picrecongnize.develop}")
-    private String developFolder;
-    @Value(value = "${picrecongnize.im}")
-    private String imFolder;
-    @Value(value = "${picrecongnize.design}")
-    private String designFolder;
-
-    @Value("classpath:novel_words.data")
-    private org.springframework.core.io.Resource novelWords;
-    @Autowired
-    private RedisUtil redisUtil;
-
-    @Resource
-    private ScreenshotMapper screenshotMapper;
-    @Resource
-    private PicContentKeywordsMapper picContentKeywordsMapper;
-    @Resource
-    private TimeCalculationMapper timeCalculationMapper;
-    @Resource
-    private UserMapper userMapper;
-    @Resource
-    private TimeCalculationShowMapper timeCalculationShowMapper;
-
-    //每次获取到截屏后计算并处理
-    private void calculateTime(Screenshot screenshot) {
-        try {
-            //首先拿去处理show表
-            calculateShowTime(screenshot);
-
-            //如果图片类型为空 则认为是 -1 - 其他
-            if (null == screenshot.getPicType()) {
-                screenshot.setPicType(-1);
-            }
-            //默认状态为不连续 如果下面判断是连续才会修改为true
-            Boolean isConsecutive = false,
-                    isSameType = false;
-            //获取本人当天结束时间为准的最后一条记录
-            TimeCalculation latestRecord = timeCalculationMapper.selectOne(new QueryWrapper<TimeCalculation>()
-                    .eq("user_id", screenshot.getUid())
-                    .eq("date", screenshot.getIndate().toLocalDate())
-                    .orderByDesc("id")
-                    .last("LIMIT 1"));
-            //截图时间
-            LocalTime currentTime = screenshot.getIndate().toLocalTime();
-            //如果有上一条记录
-            if (latestRecord != null) {
-                //前后两张是否相同类型
-                isSameType = latestRecord.getActionType().equals(screenshot.getPicType());
-                //前后两张时间是否连续 这个目前为600秒
-                LocalTime estimatedTime = latestRecord.getEndTime();
-                Integer durationSecond = ((currentTime.getHour() - estimatedTime.getHour()) * 3600
-                        + (currentTime.getMinute() - estimatedTime.getMinute()) * 60
-                        + (currentTime.getSecond() - estimatedTime.getSecond()));
-                //断层不大于一定时间的话  用来判断是否连续
-                isConsecutive = durationSecond <= DETECTION_INTERVAL;
-            }
-            if (isConsecutive && isSameType) {
-                //如果时间连续 且是同一类型的话 修改上一条记录的最后时间和持续时间
-                LocalTime startTime = latestRecord.getStartTime();
-                //计算新的间隔
-                Integer duration = ((currentTime.getHour() - startTime.getHour()) * 3600
-                        + (currentTime.getMinute() - startTime.getMinute()) * 60
-                        + (currentTime.getSecond() - startTime.getSecond()));
-                //设置新的结束时间和持续时间 保存记录
-                latestRecord.setEndTime(currentTime).setDuration(duration);
-                timeCalculationMapper.updateById(latestRecord);
-            } else {
-                //如果不是连续的话 新增一个记录
-                TimeCalculation timeCalculation = new TimeCalculation();
-                timeCalculation
-                        .setUserId(screenshot.getUid())
-                        //根据截图种类设置行为代号
-                        .setActionType(screenshot.getPicType())
-                        .setDate(screenshot.getIndate().toLocalDate())
-                        //设置开始时间和结束时间都为当前时间
-                        .setStartTime(currentTime)
-                        .setEndTime(currentTime)
-                        //第一次的持续时间默认为最少单位1秒
-                        .setDuration(1)
-                        .setPicUrl(screenshot.getPicUrl());
-                timeCalculationMapper.insert(timeCalculation);
-                if (isConsecutive) {
-                    //然后如果只是类型不同但是能连上的话
-                    LocalTime startTime = latestRecord.getStartTime();
-                    //计算新的间隔
-                    Integer duration = ((currentTime.getHour() - startTime.getHour()) * 3600
-                            + (currentTime.getMinute() - startTime.getMinute()) * 60
-                            + (currentTime.getSecond() - startTime.getSecond()));
-                    //设置新的结束时间和持续时间 保存记录
-                    latestRecord.setEndTime(currentTime).setDuration(duration);
-                    timeCalculationMapper.updateById(latestRecord);
-                }
-            }
-            /*之后可能还需要处理跨越一天的情况*/
-        } catch (NullPointerException e) {
-            //凡是有空指针说明缺少用户id或者时间数据
-            log.info("工作时长统计失败 缺少用户或时间数据");
-        }
-    }
-
-    //每次获取到截屏后计算并处理
-    private void calculateShowTime(Screenshot screenshot) {
-        try {
-            //如果图片类型为空 则认为是 -1 - 其他
-            if (null == screenshot.getPicType()) {
-                screenshot.setPicType(-1);
-            }
-            //默认状态为不连续 如果下面判断是连续才会修改为true
-            Boolean isConsecutive = false;
-            //获取本人当天结束时间为准的最后一条记录
-            TimeCalculationShow latestRecord = timeCalculationShowMapper.selectOne(
-                    new QueryWrapper<TimeCalculationShow>()
-                            .eq("user_id", screenshot.getUid())
-                            .eq("date", screenshot.getIndate().toLocalDate())
-                            .orderByDesc("id")
-                            .last("LIMIT 1"));
-            //截图时间
-            LocalTime currentTime = screenshot.getIndate().toLocalTime();
-            //如果有上一条记录
-            if (latestRecord != null) {
-                //前后两张时间是否连续 这个目前为600秒
-                LocalTime estimatedTime = latestRecord.getEndTime();
-                Integer durationSecond = ((currentTime.getHour() - estimatedTime.getHour()) * 3600
-                        + (currentTime.getMinute() - estimatedTime.getMinute()) * 60
-                        + (currentTime.getSecond() - estimatedTime.getSecond()));
-                //断层不大于一定时间的话  用来判断是否连续
-                isConsecutive = durationSecond <= DETECTION_INTERVAL;
-            }
-
-            if (isConsecutive) {
-                //如果是连续的话 修改上一条记录的最后时间和持续时间
-                LocalTime startTime = latestRecord.getStartTime();
-                //计算新的间隔
-                Integer duration = ((currentTime.getHour() - startTime.getHour()) * 3600
-                        + (currentTime.getMinute() - startTime.getMinute()) * 60
-                        + (currentTime.getSecond() - startTime.getSecond()));
-                //设置新的结束时间和持续时间 保存记录
-                latestRecord.setEndTime(currentTime).setDuration(duration);
-                timeCalculationShowMapper.updateById(latestRecord);
-            } else {
-                //如果不是连续的话 新增一个记录
-                TimeCalculationShow timeCalculationShow = new TimeCalculationShow();
-                timeCalculationShow
-                        .setUserId(screenshot.getUid())
-                        .setDate(screenshot.getIndate().toLocalDate())
-                        //设置开始时间和结束时间都为当前时间
-                        .setStartTime(currentTime)
-                        .setEndTime(currentTime)
-                        //第一次的持续时间默认为最少单位1秒
-                        .setDuration(1);
-                timeCalculationShowMapper.insert(timeCalculationShow);
-            }
-            /*之后可能还需要处理跨越一天的情况*/
-        } catch (NullPointerException e) {
-            //凡是有空指针说明缺少用户id或者时间数据
-            log.info("工作时长统计失败 缺少用户或时间数据");
-        }
-    }
-
-    //列表截图
-    @Override
-    public HttpRespMsg getLatestScreenshotList(String date, HttpServletRequest request) {
-        HttpRespMsg httpRespMsg = new HttpRespMsg();
-        //获取某天每一个人最后一张截图
-        try {
-            List<Map<String, Object>> dataMap = screenshotMapper
-                    .getLatestScreenshotList(userMapper.selectById(request.getHeader("Token")).getCompanyId(), date);
-            // LocalDate.now(ZoneOffset.of("+8")).format(DateTimeFormatter.ofPattern("yyyy-MM-dd");
-            for (Map<String, Object> map : dataMap) {
-                //对于每一张图 将时间戳转换为时间
-                map.put("time", new SimpleDateFormat("HH:mm:ss").format(map.get("indate")));
-                map.remove("indate");
-            }
-            httpRespMsg.data = dataMap;
-        } catch (NullPointerException e) {
-            httpRespMsg.setError("验证失败");
-            return httpRespMsg;
-        }
-        return httpRespMsg;
-    }
-
-    //获取个人截图页
-    @Override
-    public HttpRespMsg getTodayScreenshotList(String userId, String date) {
-        HttpRespMsg httpRespMsg = new HttpRespMsg();
-        Map<String, Object> resultMap = new HashMap<>();
-        List<String> srcList = new ArrayList<>();
-        List<Object> dataList = new ArrayList<>();
-        List<Screenshot> screenshotList = screenshotMapper.selectList(new QueryWrapper<Screenshot>()
-                .eq("date_str", date)
-                .eq("uid", userId)
-                .orderByDesc("indate"));
-        for (Screenshot screenshot : screenshotList) {
-            srcList.add(screenshot.getPicUrl());
-            Map<String, Object> map = new HashMap<>();
-            map.put("time", screenshot.getIndate().toLocalTime());
-            map.put("type", screenshot.getPicType() == null ? 0 : screenshot.getPicType());
-            dataList.add(map);
-        }
-        resultMap.put("srcList", srcList);
-        resultMap.put("data", dataList);
-        httpRespMsg.data = resultMap;
-        return httpRespMsg;
-    }
-
-    @Override
-    public HttpRespMsg getScreenshotDate(String date, HttpServletRequest request) {
-        HttpRespMsg httpRespMsg = new HttpRespMsg();
-        try {
-            List<Integer> userIdList = screenshotMapper.getCompanyUserId(request.getHeader("Token"));
-            if (screenshotMapper.selectCount(new QueryWrapper<Screenshot>()
-                    .eq("date_str", date)
-                    .in("uid", userIdList)) > 0) {
-                //当天有截图
-                httpRespMsg.data = date;
-            } else {
-                Screenshot futureScreenshot = screenshotMapper.selectOne(new QueryWrapper<Screenshot>()
-                        .gt("date_str", date)
-                        .in("uid", userIdList)
-                        .orderByAsc("date_str")
-                        .last("LIMIT 1"));
-                Screenshot historyScreenshot = screenshotMapper.selectOne(new QueryWrapper<Screenshot>()
-                        .lt("date_str", date)
-                        .in("uid", userIdList)
-                        .orderByDesc("date_str")
-                        .last("LIMIT 1"));
-                String futureDateString = futureScreenshot != null ? futureScreenshot.getDateStr() : null;
-                String historyDateString = historyScreenshot != null ? historyScreenshot.getDateStr() : null;
-                if (futureDateString == null && historyDateString == null) {
-                    httpRespMsg.data = null;
-                } else if (futureDateString == null) {
-                    httpRespMsg.data = historyDateString;
-                } else if (historyDateString == null) {
-                    httpRespMsg.data = futureDateString;
-                } else {
-                    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
-                    LocalDate localDate = LocalDate.parse(date, dateTimeFormatter);
-                    LocalDate futureDate = LocalDate.parse(futureDateString, dateTimeFormatter);
-                    LocalDate historyDate = LocalDate.parse(historyDateString, dateTimeFormatter);
-                    Long future = ChronoUnit.DAYS.between(localDate, futureDate);
-                    Long history = ChronoUnit.DAYS.between(historyDate, localDate);
-                    if (future >= history) {
-                        httpRespMsg.data = historyDateString;
-                    } else {
-                        httpRespMsg.data = futureDateString;
-                    }
-                }
-            }
-        } catch (NullPointerException e) {
-            httpRespMsg.setError("验证失败");
-            return httpRespMsg;
-        }
-        return httpRespMsg;
-    }
-
-    @Override
-    public HttpRespMsg saveAndProcessImage(ScreenshotVO screenshotvo) {
-        Map<String, Object> fileMap = UploadFileToFileNameUtil.uploadFile(screenshotvo.getFile(), path);
-        String filePath = (String) fileMap.get("sqlFilePath");
-        Screenshot screenshot = new Screenshot();
-        BeanUtils.copyProperties(screenshotvo, screenshot);
-        screenshot.setPicUrl(filePath);
-        screenshot.setDateStr(DateTimeFormatter.ofPattern("yyyy-MM-dd").format(screenshotvo.getIndate()));
-        String accessToken = "";
-        if (redisUtil.existsKey(Parameter.ACCESS_TOKEN.getName())) {
-            accessToken = redisUtil.getKey(Parameter.ACCESS_TOKEN.getName());
-        } else {
-            Map<String, Object> map = AuthService.getAuth(Constant.API_KEY, Constant.SECRET_KEY);
-            accessToken = (String) map.get(Parameter.ACCESS_TOKEN.getName());
-            System.out.println(accessToken);
-            redisUtil.setKeyWithExpireTime(Parameter.ACCESS_TOKEN.getName(), accessToken, (Long) map.get(Parameter.EXPIRES_IN.getName()));
-        }
-        log.info("accessToken-->" + accessToken);
-        //利用token去检测
-//        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
-//        LocalDateTime l = LocalDateTime.parse("2019-02-03",dateTimeFormatter);
-//        Set<Object> members = new HashSet<>();
-//        if (redisUtil.existsKey(Constant.COMMON_SOFTWARE_KEYWORDS)) {
-//            members = redisUtil.members(Constant.COMMON_SOFTWARE_KEYWORDS);
-//        } else {
-//            List<PicContentKeywords> picContentKeywords = picContentKeywordsMapper.selectList(null);
-//            for (PicContentKeywords keyWord : picContentKeywords) {
-//                redisUtil.sSetJsonString("keyWords", keyWord);
-//            }
-//            //由于存入数据库的对象被序列化成了json字符串,所以从redis里拿方便
-//            members = redisUtil.members(Constant.COMMON_SOFTWARE_KEYWORDS);
-//        }
-        File picFile = new File((String) fileMap.get("newFile"));
-        System.out.println("File:" + picFile.getAbsolutePath());
-
-        List<String> textContents = new ArrayList<String>();
-
-        if (isIM(picFile) != null) {
-            screenshot.setPicType(9);//聊天
-        } else {
-            Map<String, Object> picResultMap = CheckPicUtil.generalPicTextContentMap(path + filePath.substring("/upload/".length()), accessToken);
-            if (picResultMap != null) {
-                textContents = (List<String>) picResultMap.get("wordsList");
-                screenshot.setPicContext((String) picResultMap.get("picContent"));
-            }
-            if (isNovel(textContents)) {
-                screenshot.setPicType(6);
-            } else if (isDocument(textContents)) {
-                screenshot.setPicType(2);//看文档
-            } else if (isDevelop(picFile) != null) {//开发
-                screenshot.setPicType(0);
-            } else if (isDesign(picFile) != null) {//设计
-                screenshot.setPicType(3);
-            }
-            screenshot.setIsHandle(1);
-            if (screenshot.getPicType() == null && isEntertainmentColorMode(picFile)) {
-                //判断是否是娱乐:看电影, 打游戏
-                String uid = screenshotvo.getUid();
-                Screenshot preShot = screenshotMapper.selectOne(new QueryWrapper<Screenshot>().eq("uid", uid).orderByDesc("indate").last("limit 1"));
-                if (preShot != null) {
-                    String prePath = path + preShot.getPicUrl().substring(preShot.getPicUrl().lastIndexOf("/"));
-                    File f = new File(prePath);
-                    if (f.exists()) {
-                        ImageCompare comp = new ImageCompare();
-                        if (comp.isMoviePlay((String) fileMap.get("newFile"), prePath)) {
-                            screenshot.setPicType(7);
-                            //前面那条也更新
-                            if (preShot.getPicType() != null && preShot.getPicType() != 7) {
-                                preShot.setPicType(7);
-                                screenshotMapper.updateById(preShot);
-                            }
-                        }
-                    }
-                }
-            }
-            if (screenshot.getPicType() == null) {
-                try {
-                    String browserName = isBrowser(picFile);
-                    if (browserName != null) {
-                        screenshot.setPicType(1);
-                    }
-                } catch (Exception e) {
-                    e.printStackTrace();
-                }
-            }
-        }
-
-        //将获取到的截图进行时间计算
-        calculateTime(screenshot);
-        screenshotMapper.insert(screenshot);
-        return new HttpRespMsg();
-    }
-
-    @Override
-    public HttpRespMsg reTestPicMatch(int id) {
-        Screenshot item = screenshotMapper.selectById(id);
-        String fileName = item.getPicUrl().replaceAll("/upload/", "");
-        String filePath = path + fileName;
-        File pic = new File(filePath);
-        String imName = isIM(pic);
-        HttpRespMsg msg = new HttpRespMsg();
-        if (imName != null) {
-            msg.data = imName;
-        } else {
-            String devName = isDevelop(pic);
-            if (devName != null) {
-                msg.data = devName;
-            } else {
-                try {
-                    String browserName = isBrowser(pic);
-                    if (browserName != null) {
-                        msg.data = browserName;
-                    }
-                } catch (Exception e) {
-                    e.printStackTrace();
-                }
-            }
-        }
-        return msg;
-    }
-
-    @Override
-    public HttpRespMsg updateRedisPicContentKeywords() {
-        List<PicContentKeywords> picContentKeywords = picContentKeywordsMapper.selectList(null);
-        for (PicContentKeywords keyWord : picContentKeywords) {
-            redisUtil.sSetJsonString("keyWords", keyWord);
-        }
-        HttpRespMsg msg = new HttpRespMsg();
-        msg.data = redisUtil.members("keyWords");
-        return msg;
-    }
-
-    //判断文字内容是否是小说
-    private boolean isNovel(List<String> textContents) {
-        /**先粗糙地比较一下, 小说常规包含的词库,匹配频率高,则认为是小说。
-         * 第一步, 90%应该都是中文
-         */
-        int total = 0;
-        int chWNum = 0;
-        for (String w : textContents) {
-            char[] ch = w.toCharArray();
-            for (char c : ch) {
-                total++;
-                if (c >= 0x4E00 && c <= 0x9FBF) {
-                    chWNum++;
-                }
-            }
-        }
-        //小说一页中文字至少200个
-        if (chWNum < 200) {
-            return false;
-        }
-        int percent = chWNum * 100 / total;
-        log.info("中文比例:" + percent);
-        if (percent < 60) {
-            //英文太多,不是小说; 不考虑英文小说。
-            return false;
-        }
-
-        //第二步,匹配小说常见词汇,超过5次,认为是小说
-        try {
-            //填充小说关键字到内存,减少重复读取
-            if (nKeyWordsList.size() == 0) {
-                InputStream ins = novelWords.getInputStream();
-                BufferedReader br = new BufferedReader(new InputStreamReader(ins));
-                String line = br.readLine();
-                while (line != null) {
-                    nKeyWordsList.add(line);
-                    line = br.readLine();
-                    System.out.println(line);
-                }
-            }
-            int totalKNum = 0;
-            for (String k : textContents) {
-                int kNum = 0;
-                for (String nk : nKeyWordsList) {
-                    if (k.contains(nk)) {
-                        kNum++;
-                    }
-                }
-                totalKNum += kNum;
-                //存在第几章这样的关键字, +1分
-                if (matchCategory(k)) {
-                    totalKNum += 1;
-                }
-            }
-            log.info("文章小说匹配得分为==" + totalKNum);
-            if (totalKNum >= 5) {
-                return true;
-            }
-        } catch (IOException e) {
-            e.printStackTrace();
-        }
-        return false;
-    }
-
-    public static boolean matchCategory(String str) {
-        String pattern = "^第(.*)章(.*)";
-        // 创建 Pattern 对象
-        return Pattern.matches(pattern, str.trim());
-    }
-
-    public static void main(String[] args) throws Exception {
-//        String b = isDesign(new File("C:\\Users\\seya\\Desktop\\mock.jpg"));
-//        System.out.println("结果:"+b);
-    }
-
-
-    private static boolean isPureColor(BufferedImage img, int colorPixel) {
-        int with = img.getWidth();
-        int height = img.getHeight();
-        boolean hasDifferent = false;
-        for (int i = 0; i < with; i++) {
-            for (int y = 0; y < height; y++) {
-                int pixel = img.getRGB(i, y); // 下面三行代码将一个数字转换为RGB数字
-                if (pixel != colorPixel) {
-                    hasDifferent = true;
-                    break;
-                }
-            }
-            if (hasDifferent) {
-                break;
-            }
-        }
-        return !hasDifferent;
-    }
-
-    /**
-     * 是否全是汉字<br>
-     * 根据汉字编码范围进行判断<br>
-     * CJK统一汉字(不包含中文的,。《》()“‘'”、!¥等符号)<br>
-     *
-     * @param str
-     * @return
-     */
-    public static boolean isChineseByReg(String str) {
-        if (str == null) {
-            return false;
-        }
-        Pattern pattern = Pattern.compile("[\\u4E00-\\u9FBF]+");
-        return pattern.matcher(str).matches();
-    }
-
-    //判断是否是浏览器
-    private String isBrowser(File pic) throws Exception {
-//        System.out.println("picrecongnizeFolder=="+browserFolder);
-        File folder = new File(browserFolder);
-//        File folder = new File("C:/picrecongnize/browser/");
-        if (!folder.exists()) {
-            throw new Exception("没有设置图片上传的浏览器比对模板库");
-        } else {
-            File[] files = folder.listFiles();
-            String browserName = null;
-            for (File subFolder : files) {
-                File[] targetFile = subFolder.listFiles();
-                boolean isMatch = false;
-                for (File targetPic : targetFile) {
-                    boolean matchPic = ImageReconizeUtil.isTemplateMatch(pic.getAbsolutePath(), targetPic.getAbsolutePath());
-                    if (matchPic) {
-                        isMatch = true;
-                        break;
-                    }
-                }
-                if (isMatch) {
-                    browserName = subFolder.getName();
-                    break;
-                }
-            }
-            return browserName;
-        }
-    }
-
-    //判断是否是开发
-    private String isDevelop(File pic) {
-        File folder = new File(developFolder);
-//        File folder = new File("C:\\picrecongnize\\develop\\");
-        if (!folder.exists()) {
-            try {
-                throw new Exception("没有设置图片上传的开发工具比对模板库");
-            } catch (Exception e) {
-                e.printStackTrace();
-            }
-        } else {
-            File[] files = folder.listFiles();
-            String toolName = null;
-            boolean isMatch = false;
-            for (File targetPic : files) {
-//                System.out.println("targetPic==" + targetPic.getAbsolutePath());
-                boolean matchPic = ImageReconizeUtil.isTemplateMatch(pic.getAbsolutePath(), targetPic.getAbsolutePath());
-                if (matchPic) {
-                    toolName = targetPic.getName();
-                    break;
-                }
-            }
-            return toolName;
-        }
-        return null;
-    }
-
-    private String isDesign(File pic) {
-        File folder = new File(designFolder);
-//        File folder = new File("C:\\picrecongnize\\design\\");
-        if (!folder.exists()) {
-            try {
-                throw new Exception("没有设置图片上传的设计工具比对模板库");
-            } catch (Exception e) {
-                e.printStackTrace();
-            }
-        } else {
-            File[] files = folder.listFiles();
-            String toolName = null;
-            boolean isMatch = false;
-            for (File targetPic : files) {
-//                System.out.println("targetPic==" + targetPic.getAbsolutePath());
-                boolean matchPic = ImageReconizeUtil.isTemplateMatch(pic.getAbsolutePath(), targetPic.getAbsolutePath());
-                if (matchPic) {
-                    toolName = targetPic.getName();
-                    break;
-                }
-            }
-            return toolName;
-        }
-        return null;
-    }
-
-    //判断是否是聊天
-    private String isIM(File pic) {
-        File folder = new File(imFolder);
-//        File folder = new File("C:\\picrecongnize\\im\\");
-        if (!folder.exists()) {
-            try {
-                throw new Exception("没有设置图片上传的聊天比对模板库");
-            } catch (Exception e) {
-                e.printStackTrace();
-            }
-        } else {
-            File[] files = folder.listFiles();
-            String toolName = null;
-            boolean isMatch = false;
-            for (File targetPic : files) {
-//                System.out.println("targetPic==" + targetPic.getAbsolutePath());
-                boolean matchPic = ImageReconizeUtil.isWholeTemplateMatch(pic.getAbsolutePath(), targetPic.getAbsolutePath());
-                if (matchPic) {
-                    toolName = targetPic.getName();
-                    break;
-                }
-            }
-            return toolName;
-        }
-        return null;
-    }
-
-    /**
-     * 判断是否是看文档, 具体类型为word, excel, pdf, ppt
-     *
-     * @param textContents
-     * @return
-     */
-    public static boolean isDocument(List<String> textContents) {
-        boolean find = false;
-        for (int i = 0; i < textContents.size() && i <= 2; i++) {//出现在前三行
-            String text = textContents.get(i).trim();
-            if (text.contains("Word")
-                    || text.contains("Excel")
-                    || text.contains("Ecel")
-                    || text.contains("Power Point")
-                    || text.contains("Adobe Reader")) {
-                find = true;
-                break;
-            }
-        }
-        return find;
-    }
-
-    //娱乐类: 电影+游戏; 画面比较丰富的
-    public static boolean isEntertainmentColorMode(File pic) {
-        try {
-            int[] rgb = new int[3];
-            if (!pic.exists()) {
-                System.err.println("文件不存在" + pic.getAbsolutePath());
-            } else {
-                System.out.println("找到文件" + pic.getAbsolutePath());
-            }
-            BufferedImage img = ImageIO.read(pic);
-            int width = img.getWidth();
-            int height = img.getHeight();
-            int minx = img.getMinX();
-            int miny = img.getMinY();
-//            System.out.println("width=" + width + ",height=" + height + ".");
-//            System.out.println("minx=" + minx + ",miniy=" + miny + ".");
-            //统计出现最多的一个色值,计算所占比重
-            int totalPixl = 0;
-            HashMap<Integer, Integer> colorCntMap = new HashMap<Integer, Integer>();
-            for (int i = minx; i < width; i++) {
-                for (int j = miny; j < height; j++) {
-                    totalPixl++;
-                    int pixel = img.getRGB(i, j); // 下面三行代码将一个数字转换为RGB数字
-                    if (colorCntMap.get(pixel) == null) {
-                        colorCntMap.put(pixel, 1);
-                    } else {
-                        colorCntMap.put(pixel, colorCntMap.get(pixel) + 1);
-                    }
-                }
-            }
-
-            Map<Integer, Integer> sMap = new TreeMap<Integer, Integer>();
-            int maxCnt = 0;
-            int key = 0;
-            Set<Map.Entry<Integer, Integer>> entry2 = colorCntMap.entrySet();
-            for (Map.Entry<Integer, Integer> temp : entry2) {
-//                System.out.println("sortedMap:"+temp.getKey()+" 值"+temp.getValue());
-                if (temp.getValue() > maxCnt) {
-                    maxCnt = temp.getValue();
-                    key = temp.getKey();
-                }
-                sMap.put(temp.getValue(), temp.getKey());
-            }
-            sMap = ((TreeMap) sMap).descendingMap();
-            Iterator it = sMap.keySet().iterator();
-            Integer k1 = (Integer) it.next();
-            Integer k2 = (Integer) it.next();
-            Integer color1 = sMap.get(k1);
-            Integer color2 = sMap.get(k2);
-//            System.out.println("kkkk==" + k1 + "," + color1 + "," + k2 + "," + color2);
-//            System.out.println("最.." + maxCnt + ", key=" + key);
-            rgb[0] = (key & 0xff0000) >> 16;
-            rgb[1] = (key & 0xff00) >> 8;
-            rgb[2] = (key & 0xff);
-//            System.out.println("色值为: " + rgb[0] + ", " + rgb[1] + ", " + rgb[2]);
-            //计算比例, 应该不低于50%
-            int colorPercent = maxCnt * 100 / totalPixl;
-            if (colorPercent < 50) {
-                //可能存在2中底色, 大布局的底色和小模块的底色,都算底色。
-                int secPercent = k2 * 100 / totalPixl;
-                rgb[0] = (color2 & 0xff0000) >> 16;
-                rgb[1] = (color2 & 0xff00) >> 8;
-                rgb[2] = (color2 & 0xff);
-//                System.out.println("二级底色色值为: " + rgb[0] + ", " + rgb[1] + ", " + rgb[2]);
-//                System.out.println("二级底色比例==" + secPercent);
-                colorPercent = (k1 + k2) * 100 / totalPixl;
-            }
-            System.out.println("总底色比例==" + colorPercent);
-            //计算底色是否是连续分布的
-            int windowSize = 50;
-            int pureColorBlockCnt = 0;
-            int totalBlockCnt = 0;
-            for (int i = minx; i < width - windowSize; i += windowSize) {
-                for (int j = miny; j < height - windowSize; j += windowSize) {
-                    totalBlockCnt++;
-                    BufferedImage rect = img.getSubimage(i, j, windowSize, windowSize);
-                    if (isPureColor(rect, key)) {
-                        pureColorBlockCnt++;
-                    }
-                }
-            }
-//            log.info("pureColorBlockCnt===" + pureColorBlockCnt);
-            int pureColorBlackPercent = pureColorBlockCnt * 100 / totalBlockCnt;
-//            log.info("pureColorBlackPercent===" + pureColorBlackPercent);
-            if (colorPercent < 50 && pureColorBlackPercent < 30) {
-                return true;
-            }
-        } catch (IOException e) {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
-        }
-        return false;
-    }
-}

+ 148 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/UserServiceImpl.java

@@ -12,6 +12,11 @@ import com.management.platform.mapper.*;
 import com.management.platform.service.ReportService;
 import com.management.platform.service.UserService;
 import com.management.platform.util.*;
+import me.chanjar.weixin.mp.api.WxMpInMemoryConfigStorage;
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
+import me.chanjar.weixin.mp.bean.template.WxMpTemplateData;
+import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage;
 import org.apache.poi.hssf.usermodel.*;
 import org.apache.poi.ss.usermodel.CellType;
 import org.apache.poi.xssf.usermodel.XSSFCell;
@@ -90,6 +95,8 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
     private UserSalaryMapper userSalaryMapper;
     @Resource
     private UserVcodeMapper userVcodeMapper;
+    @Resource
+    private ProjectBasecostSettingMapper projectBasecostSettingMapper;
     //登录网页端
     @Override
     public HttpRespMsg loginAdmin(String username, String password) {
@@ -348,6 +355,14 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
                     .setRole(1)
                     .setColor(ColorUtil.randomColor())
                     .setCompanyId(company.getId());
+            //生成项目的成本基线默认条目
+            String[] array = com.management.platform.util.Constant.DEFAULT_BASE_COST_ITEMS;
+            for (String baseItem : array) {
+                ProjectBasecostSetting setting = new ProjectBasecostSetting();
+                setting.setName(baseItem);
+                setting.setCompanyId(company.getId());
+                projectBasecostSettingMapper.insert(setting);
+            }
 
             if (userMapper.insert(user) == 0) {
                 httpRespMsg.setError("操作失败");
@@ -958,4 +973,137 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
         }
         return msg;
     }
+
+    @Override
+    public HttpRespMsg pushFillReport(String ids, HttpServletRequest request, String date) {
+        List<String> strings = ListUtil.convertLongIdsArrayToList(ids);
+        String token = request.getHeader("TOKEN");
+        User user = userMapper.selectById(token);
+        List<Department> deptList = departmentMapper.selectList(new QueryWrapper<Department>().eq("company_id", user.getCompanyId()));
+        List<User> userList = userMapper.selectList(new QueryWrapper<User>().in("id", strings));
+        HttpRespMsg msg = new HttpRespMsg();
+        for (User u : userList) {
+            if (!StringUtils.isEmpty(u.getWxOpenid())) {
+                Optional<Department> first = deptList.stream().filter(d -> d.getDepartmentId().equals(u.getDepartmentId())).findFirst();
+                if (first.isPresent()) {
+                    u.setDepartmentName(first.get().getDepartmentName());
+                }
+                boolean result = push(u, date);
+                if (!result) {
+                    System.out.println("!!!!!!!!!!!==================");
+                    msg.setError("推送失败,请检查日志");
+                }
+            }
+        }
+        return msg;
+    }
+
+    @Override
+    public HttpRespMsg exportMembList(boolean isFill, String ids, HttpServletRequest request, String date) {
+        HttpRespMsg httpRespMsg = new HttpRespMsg();
+        try {
+            String userId = request.getHeader("Token");
+            User user = userMapper.selectById(userId);
+            List<String> strings = ListUtil.convertLongIdsArrayToList(ids);
+            List<Department> deptList = departmentMapper.selectList(new QueryWrapper<Department>().eq("company_id", user.getCompanyId()));
+            List<User> userList = userMapper.selectList(new QueryWrapper<User>().in("id", strings));
+            userList.forEach(u->{
+                Optional<Department> first = deptList.stream().filter(d -> d.getDepartmentId().equals(u.getDepartmentId())).findFirst();
+                if (first.isPresent()) {
+                    u.setDepartmentName(first.get().getDepartmentName());
+                }
+            });
+            //准备导出
+            HSSFWorkbook workbook = new HSSFWorkbook();
+            HSSFSheet sheet = workbook.createSheet("人员列表");
+            //创建表头
+            HSSFRow headRow = sheet.createRow(0);
+            //设置列宽 setColumnWidth的第二个参数要乘以256 这个参数的单位是1/256个字符宽度
+            sheet.setColumnWidth(0, 5 * 256);
+            sheet.setColumnWidth(1, 10 * 256);
+            sheet.setColumnWidth(2, 20 * 256);
+            //设置为居中加粗
+            HSSFCellStyle headStyle = workbook.createCellStyle();
+            HSSFFont font = workbook.createFont();
+            font.setBold(true);
+            headStyle.setFont(font);
+            //表头
+            HSSFCell headCell;
+            headCell = headRow.createCell(0);
+            headCell.setCellValue("序号");
+            headCell.setCellStyle(headStyle);
+            headCell = headRow.createCell(1);
+            headCell.setCellValue("姓名");
+            headCell.setCellStyle(headStyle);
+            headCell = headRow.createCell(2);
+            headCell.setCellValue("部门");
+            headCell.setCellStyle(headStyle);
+
+            //新增数据行 并且装填数据
+            int rowNum = 1;
+            for (User item : userList) {
+                HSSFRow row = sheet.createRow(rowNum);
+                row.createCell(0).setCellValue(rowNum);
+                row.createCell(1).setCellValue(item.getName());
+                row.createCell(2).setCellValue(item.getDepartmentName());
+                rowNum++;
+            }
+            //生成Excel文件
+            String fileUrlSuffix = date+(isFill?"已填":"未填")+"人员列表" + System.currentTimeMillis() + ".xls";
+            FileOutputStream fos = new FileOutputStream(path + fileUrlSuffix);
+            workbook.write(fos);
+            fos.flush();
+            fos.close();
+            //返回生成的文件地址/upload文件夹下
+            httpRespMsg.data = "/upload/" + fileUrlSuffix;
+        } catch (NullPointerException e) {
+            httpRespMsg.setError("验证失败或缺少数据");
+            return httpRespMsg;
+        } catch (IOException e) {
+            httpRespMsg.setError("文件生成错误");
+            return httpRespMsg;
+        }
+        return httpRespMsg;
+    }
+
+    @Override
+    public HttpRespMsg getHRList(HttpServletRequest request) {
+        HttpRespMsg msg = new HttpRespMsg();
+        String token = request.getHeader("TOKEN");
+        int companyId = userMapper.selectById(token).getCompanyId();
+        List<User> userList = userMapper.selectList(new QueryWrapper<User>().eq("company_id", companyId).eq("role", 4));
+        msg.data = userList;
+        return msg;
+    }
+
+
+    public boolean push(User user, String date) {
+        //1,配置
+        WxMpInMemoryConfigStorage wxStorage = new WxMpInMemoryConfigStorage();
+        wxStorage.setAppId(appId);
+        wxStorage.setSecret(appSecret);
+        WxMpService wxMpService = new WxMpServiceImpl();
+        wxMpService.setWxMpConfigStorage(wxStorage);
+
+        //2,推送消息
+        WxMpTemplateMessage templateMessage = WxMpTemplateMessage.builder()
+                .toUser(user.getWxOpenid())//要推送的用户openid
+                .templateId(TEMPLATE_REPORT_FILL)//模版id
+                .url("http://mobworktime.ttkuaiban.com/#/edit")//点击模版消息要访问的网址
+                .build();
+        //3,如果是正式版发送模版消息,这里需要配置你的信息
+        templateMessage.addData(new WxMpTemplateData("first", "您"+date+"的工时报告还未填写", "#FF00FF"));
+        templateMessage.addData(new WxMpTemplateData("keyword1", user.getName(), "#000000"));
+        templateMessage.addData(new WxMpTemplateData("keyword2", user.getDepartmentName(), "#000000"));
+        templateMessage.addData(new WxMpTemplateData("remark", "请尽快填报", "#000000"));
+        //                templateMessage.addData(new WxMpTemplateData(name2, value2, color2));
+        try {
+            wxMpService.getTemplateMsgService().sendTemplateMsg(templateMessage);
+        } catch (Exception e) {
+            System.out.println("推送失败:" + e.getMessage());
+            e.printStackTrace();
+            return false;
+        }
+        return true;
+    }
 }

+ 1 - 42
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/task/TimingTask.java

@@ -1,15 +1,11 @@
 package com.management.platform.task;
 
-import java.time.LocalDate;
-import java.time.ZoneOffset;
 import java.time.format.DateTimeFormatter;
 
-import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.management.platform.constant.Constant;
 import com.management.platform.entity.*;
 import com.management.platform.mapper.*;
-import com.management.platform.service.ScreenshotService;
 import com.management.platform.util.AuthService;
 import com.management.platform.util.CheckPicUtil;
 import com.management.platform.util.RedisUtil;
@@ -20,16 +16,12 @@ import me.chanjar.weixin.mp.bean.template.WxMpTemplateData;
 import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
-import org.springframework.format.annotation.DateTimeFormat;
-import org.springframework.http.*;
 import org.springframework.scheduling.annotation.EnableScheduling;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;
 
 import javax.annotation.Resource;
 import java.time.LocalDateTime;
-import java.time.format.DateTimeFormatter;
-import java.time.temporal.TemporalAccessor;
 import java.util.*;
 
 /**
@@ -65,39 +57,6 @@ public class TimingTask {
     @Value(value = "${upload.path}")
     private String path;
 
-    //    @Scheduled(cron = "0 */5 * * * ?")//配置时间段触发(每五分钟触发一次)
-    public void pictureDetectionTask() {
-        String accessToken = "";
-
-        if (redisUtil.existsKey("accessToken")) {
-            accessToken = redisUtil.getKey("accessToken");
-        } else {
-            Map<String, Object> map = AuthService.getAuth(Constant.API_KEY, Constant.SECRET_KEY);
-            accessToken = (String) map.get("access_token");
-            Long expiresTimeOut = (Long) map.get("expires_in");
-            redisUtil.setKeyWithExpireTime("accessToken", accessToken, expiresTimeOut);
-        }
-        //利用token去检测
-//        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
-//        LocalDateTime l = LocalDateTime.parse("2019-02-03",dateTimeFormatter);
-        List<Screenshot> screenshots = screenshotMapper.selectList(new QueryWrapper<Screenshot>()
-                .eq("date_str", DateTimeFormatter.ofPattern("yyyy-MM-dd").format(LocalDateTime.now()))
-                .eq("is_handle", Constant.UN_HANDLE));
-        for (Screenshot screenshot : screenshots) {
-            List<String> textContents = CheckPicUtil.generalPicTextContent(path + screenshot.getPicUrl().substring("/upload/".length()), accessToken);
-            Set<Object> members = redisUtil.members(Constant.COMMON_SOFTWARE_KEYWORDS);
-            for (String textContent : textContents) {
-                for (Object member : members) {
-                    if (textContent.contains((String) member)) {
-                        //包含关键字们可以简单认为是在用常用开发软件
-                        //to do 确定图片是哪个类型的图片
-                    }
-                }
-            }
-        }
-    }
-
-
 
     //每分钟校验是否有需要提醒的填报
     @Scheduled(fixedRate = 60 * 1000)
@@ -139,7 +98,7 @@ public class TimingTask {
                 .url("http://mobworktime.ttkuaiban.com/#/edit")//点击模版消息要访问的网址
                 .build();
         //3,如果是正式版发送模版消息,这里需要配置你的信息
-        templateMessage.addData(new WxMpTemplateData("first", "您今天的工时填报还未完成", "#FF00FF"));
+        templateMessage.addData(new WxMpTemplateData("first", "您今天的工时报告还未填写", "#FF00FF"));
         templateMessage.addData(new WxMpTemplateData("keyword1", (String)user.get("name"), "#000000"));
         templateMessage.addData(new WxMpTemplateData("keyword2", (String)user.get("departmentName"), "#000000"));
         templateMessage.addData(new WxMpTemplateData("remark", "请尽快填报", "#000000"));

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

@@ -96,7 +96,7 @@ public class CodeGenerator {
 //        dsc.setSchemaName("public");
         dsc.setDriverName("com.mysql.cj.jdbc.Driver");
         dsc.setUsername("root");
-        dsc.setPassword("Ziyu1026!@");
+        dsc.setPassword("Ziyu20141026!@");
         mpg.setDataSource(dsc);
 
         // 包配置

+ 2 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/util/Constant.java

@@ -7,4 +7,6 @@ public class Constant {
     public static final int ROLE_SENIOR = 3;
     public static final int ROLE_HR = 4;
     public static final int ROLE_PMP = 5;
+
+    public static String[] DEFAULT_BASE_COST_ITEMS = {"人工成本","一般费用","外包费用","其他"};
 }

+ 36 - 36
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/util/OpenOfficeService.java

@@ -17,16 +17,16 @@ public class OpenOfficeService {
 	//32位windows系统默认安装路径
 	public static String OpenOffice_HOME_32 = "C://Program Files/OpenOffice 4/";
 	public static String OpenOffice_HOME_UNIX = "/opt/openoffice4/";
-
+	public static int PORT = 12312;
 	private static OfficeManager officeManager;
 
 	public static boolean canTransferToPdf(String suffix) {
 		if (".doc".equals(suffix) || ".docx".equals(suffix)
-		|| ".xls".equals(suffix) || ".xlsx".equals(suffix)
-		|| ".ppt".equals(suffix) || ".pptx".equals(suffix)
-		|| ".jpg".equals(suffix) || ".png".equals(suffix)
-		|| ".bmp".equals(suffix) || ".jpeg".equals(suffix)
-		|| ".txt".equals(suffix)) {
+				|| ".xls".equals(suffix) || ".xlsx".equals(suffix)
+				|| ".ppt".equals(suffix) || ".pptx".equals(suffix)
+				|| ".jpg".equals(suffix) || ".png".equals(suffix)
+				|| ".bmp".equals(suffix) || ".jpeg".equals(suffix)
+				|| ".txt".equals(suffix)) {
 			return true;
 		} else {
 			return false;
@@ -39,14 +39,14 @@ public class OpenOfficeService {
 		try {
 			log.info("===Openoffice实例启动中...");
 			DefaultOfficeManagerConfiguration config = new DefaultOfficeManagerConfiguration();
-	        String officeHome = getOfficeHome();
+			String officeHome = getOfficeHome();
 			log.info("officeHome====="+officeHome);
-	        config.setOfficeHome(officeHome);
-	        int randomPort = new Random().nextInt(1000);
-	        randomPort += 8000;
-	        config.setPortNumber(randomPort);
-	        officeManager = config.buildOfficeManager();
-	        officeManager.start();
+			config.setOfficeHome(officeHome);
+//	        int randomPort = new Random().nextInt(1000);
+//	        randomPort += 8000;
+			config.setPortNumber(PORT);
+			officeManager = config.buildOfficeManager();
+			officeManager.start();
 			log.info("Openoffice实例启动成功!");
 		} catch (Exception e) {
 			e.printStackTrace();
@@ -55,22 +55,22 @@ public class OpenOfficeService {
 	}
 
 	public static String getOfficeHome() {
-        String osName = System.getProperty("os.name");
-        if (Pattern.matches("Linux.*", osName)) {
-            return OpenOffice_HOME_UNIX;
-        } else if (Pattern.matches("Windows.*", osName)) {
-        	String arch = System.getProperty("os.arch");
-        	boolean is64bit = (System.getenv("ProgramFiles(x86)") != null);
-        	if (is64bit) {
-        		return OpenOffice_HOME_64;
-        	} else {
-        		return OpenOffice_HOME_32;
-        	}
-        } else if (Pattern.matches("Mac.*", osName)) {
-            return "/Application/OpenOffice.org.app/Contents";
-        }
-        return null;
-    }
+		String osName = System.getProperty("os.name");
+		if (Pattern.matches("Linux.*", osName)) {
+			return OpenOffice_HOME_UNIX;
+		} else if (Pattern.matches("Windows.*", osName)) {
+			String arch = System.getProperty("os.arch");
+			boolean is64bit = (System.getenv("ProgramFiles(x86)") != null);
+			if (is64bit) {
+				return OpenOffice_HOME_64;
+			} else {
+				return OpenOffice_HOME_32;
+			}
+		} else if (Pattern.matches("Mac.*", osName)) {
+			return "/Application/OpenOffice.org.app/Contents";
+		}
+		return null;
+	}
 
 	/**
 	 * 文档转换
@@ -94,13 +94,13 @@ public class OpenOfficeService {
 		if (!outputFile.getParentFile().exists()) {
 			outputFile.getParentFile().mkdirs();
 		}
-        File inputFile = new File(inputFilePath);
-        if (inputFile.exists()) {// 找不到源文件, 则返回
-            converter.convert(inputFile, outputFile);
-        } else {
-        	return -1;
-        }
-        return 0;
+		File inputFile = new File(inputFilePath);
+		if (inputFile.exists()) {// 找不到源文件, 则返回
+			converter.convert(inputFile, outputFile);
+		} else {
+			return -1;
+		}
+		return 0;
 	}
 
 	/**

+ 5 - 9
fhKeeper/formulahousekeeper/management-platform/src/main/resources/application-prod.yml

@@ -15,7 +15,7 @@ spring:
     driver-class-name: com.mysql.cj.jdbc.Driver
     url: jdbc:mysql://47.100.37.243:7644/man_hour_manager?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
     username: root
-    password: Ziyu1026!@
+    password: Ziyu20141026!@
     hikari:
       maximum-pool-size: 10
       minimum-idle: 3
@@ -48,11 +48,11 @@ spring:
 logging:
   level:
     root: info
-    org.mybatis: debug
-    java.sql: debug
+    org.mybatis: info
+    java.sql: info
     org.springframework.web: trace
     #打印sql语句
-    com.management.platform.mapper: debug
+    com.management.platform.mapper: info
   path: /log/
   file: worktime.log
 ##########
@@ -81,11 +81,7 @@ mybatis:
 #####配置图片上传路径####
 upload:
   path: /www/staticproject/timesheet/upload/
-picrecongnize:
-  browser: /www/webapps/worktime/picrecongnize/browser/
-  develop: /www/webapps/worktime/picrecongnize/develop/
-  im: /www/webapps/worktime/picrecongnize/im/
-  design: /www/webapps/worktime/picrecongnize/design/
+
 
 
 

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

@@ -14,9 +14,9 @@ spring:
       location: C:/upload/
   datasource:
     driver-class-name: com.mysql.cj.jdbc.Driver
-    url: jdbc:mysql://47.100.37.243:7644/man_jiushi?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
+    url: jdbc:mysql://47.100.37.243:7644/man_dev?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
     username: root
-    password: Ziyu1026!@
+    password: Ziyu20141026!@
     hikari:
       maximum-pool-size: 10
       minimum-idle: 3

+ 21 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/AuditWorkflowTimeSettingMapper.xml

@@ -0,0 +1,21 @@
+<?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.AuditWorkflowTimeSettingMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.management.platform.entity.AuditWorkflowTimeSetting">
+        <id column="id" property="id" />
+        <result column="company_id" property="companyId" />
+        <result column="role_id" property="roleId" />
+        <result column="role_name" property="roleName" />
+        <result column="seq" property="seq" />
+        <result column="user_id" property="userId" />
+        <result column="user_name" property="userName" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, company_id, role_id, role_name, seq, user_id, user_name
+    </sql>
+
+</mapper>

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

@@ -15,11 +15,12 @@
         <result column="package_oa" property="packageOa" />
         <result column="package_etimecard" property="packageEtimecard" />
         <result column="package_expense" property="packageExpense" />
+        <result column="package_customer" property="packageCustomer" />
     </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
+        id, company_name, staff_count_max, expiration_date, set_meal, package_worktime, package_project, package_contract, package_oa, package_etimecard, package_expense, package_customer
     </sql>
 
 </mapper>

+ 26 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/CustomerInfoMapper.xml

@@ -0,0 +1,26 @@
+<?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.CustomerInfoMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.management.platform.entity.CustomerInfo">
+        <id column="id" property="id" />
+        <result column="customer_code" property="customerCode" />
+        <result column="customer_name" property="customerName" />
+        <result column="contact_name" property="contactName" />
+        <result column="contact_phone" property="contactPhone" />
+        <result column="email" property="email" />
+        <result column="address" property="address" />
+        <result column="company_id" property="companyId" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, customer_code, customer_name, contact_name, contact_phone, email, address, company_id
+    </sql>
+    <select id="getAll" resultMap="BaseResultMap">
+        select id, customer_name from customer_info where company_id = #{companyId}
+        ORDER BY id DESC
+    </select>
+
+</mapper>

+ 5 - 9
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/EarningSnapshotMapper.xml

@@ -10,19 +10,15 @@
         <result column="creator_id" property="creatorId" />
         <result column="creator_name" property="creatorName" />
         <result column="contract_amount" property="contractAmount" />
-        <result column="base_man" property="baseMan" />
-        <result column="base_fee" property="baseFee" />
-        <result column="base_outsourcing" property="baseOutsourcing" />
-        <result column="base_risk1" property="baseRisk1" />
-        <result column="base_risk2" property="baseRisk2" />
-        <result column="profit_a" property="profitA" />
-        <result column="profit_b" property="profitB" />
-        <result column="profit_c" property="profitC" />
+        <result column="profit" property="profit" />
+        <result column="profit_percent" property="profitPercent" />
+        <result column="cost_total" property="costTotal" />
+        <result column="cost_data" property="costData" />
     </resultMap>
 
     <!-- 通用查询结果列 -->
     <sql id="Base_Column_List">
-        id, project_id, indate, creator_id, creator_name, contract_amount, base_man, base_fee, base_outsourcing, base_risk1, base_risk2, profit_a, profit_b, profit_c
+        id, project_id, indate, creator_id, creator_name, contract_amount, profit, profit_percent, cost_total, cost_data
     </sql>
 
 </mapper>

+ 19 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/ProjectBasecostMapper.xml

@@ -0,0 +1,19 @@
+<?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.ProjectBasecostMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.management.platform.entity.ProjectBasecost">
+        <id column="id" property="id" />
+        <result column="project_id" property="projectId" />
+        <result column="base_id" property="baseId" />
+        <result column="base_name" property="baseName" />
+        <result column="base_amount" property="baseAmount" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, project_id, base_id, base_name, base_amount
+    </sql>
+
+</mapper>

+ 17 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/ProjectBasecostSettingMapper.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.ProjectBasecostSettingMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.management.platform.entity.ProjectBasecostSetting">
+        <id column="id" property="id" />
+        <result column="name" property="name" />
+        <result column="company_id" property="companyId" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, name, company_id
+    </sql>
+
+</mapper>

+ 49 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/ProjectMapper.xml

@@ -29,11 +29,25 @@
         <result column="fee_travel" property="feeTravel" />
         <result column="fee_outsourcing" property="feeOutsourcing" />
         <result column="fee_man" property="feeMan" />
+        <result column="customer_id" property="customerId" />
+        <result column="customer_name" property="customerName" />
     </resultMap>
 
+    <resultMap id="CustomerResultMap" type="com.management.platform.entity.vo.CustomerProject" >
+        <result column="customer_id" property="customerId" />
+        <result column="customer_name" property="customerName" />
+        <result column="contract_amount" property="contractAmount" />
+        <result column="fee_normal" property="feeNormal" />
+        <result column="fee_travel" property="feeTravel" />
+        <result column="fee_outsourcing" property="feeOutsourcing" />
+        <result column="fee_man" property="feeMan" />
+        <result column="project_num" property="projectNum" />
+        <result column="project_ids" property="projectIds" />
+        <result column="project_names" property="projectNames" />
+    </resultMap>
     <!-- 通用查询结果列 -->
     <sql id="Base_Column_List">
-        id, project_name, company_id, project_code, incharger_id, plan_start_date, plan_end_date, progress, level, status, finish_date, creator_id, creator_name, create_date, contract_amount, budget, base_man, base_outsourcing, base_risk1, base_risk2, base_fee, fee_normal, fee_travel, fee_outsourcing, fee_man
+        id, project_name, company_id, project_code, incharger_id, plan_start_date, plan_end_date, progress, level, status, finish_date, creator_id, creator_name, create_date, contract_amount, budget, base_man, base_outsourcing, base_risk1, base_risk2, base_fee, fee_normal, fee_travel, fee_outsourcing, fee_man, customer_id, customer_name
     </sql>
 
     <!--获取查询者所在公司每个项目的工时成本-->
@@ -124,4 +138,38 @@
             LIMIT #{pageStart},#{pageSize}
         </if>
     </select>
+
+    <!--分页获取客户项目的成本利润报表 -->
+    <select id="getCustomerProjectInAndOut" resultMap="CustomerResultMap">
+        SELECT customer_id, customer_name, COUNT(1) AS project_num, GROUP_CONCAT( project.id) AS project_ids, GROUP_CONCAT( project_name) AS project_names,
+        SUM(contract_amount) AS contract_amount ,
+        SUM((SELECT IFNULL(SUM(cost),0) FROM report WHERE state = 1 AND project_id = project.id)) AS fee_man,
+        SUM((SELECT IFNULL(SUM(amount),0) FROM expense_item , expense_sheet WHERE project_id = project.id AND  expense_sheet.id = expense_item.`expense_id` AND expense_sheet.type = 0)) AS fee_normal,
+        SUM((SELECT IFNULL(SUM(amount),0) FROM expense_item , expense_sheet WHERE project_id = project.id AND  expense_sheet.id = expense_item.`expense_id` AND expense_sheet.type = 1)) AS fee_travel,
+        SUM((SELECT IFNULL(SUM(amount),0) FROM expense_item , expense_sheet WHERE project_id = project.id AND  expense_sheet.id = expense_item.`expense_id` AND expense_sheet.type = 2)) AS fee_outsourcing
+        FROM project WHERE project.`company_id` = #{companyId} AND customer_id > 0
+        AND (project.status &lt;&gt; 3 OR project.status IS NULL)
+        GROUP BY customer_id
+        <if test="pageStart != null and pageSize != null">
+            LIMIT #{pageStart},#{pageSize}
+        </if>
+    </select>
+
+    <select id="getCustomerProjectInAndOutCount" resultType="java.lang.Integer">
+        SELECT COUNT(DISTINCT customer_id) FROM project WHERE project.`company_id` = #{companyId} AND customer_id > 0
+        AND (project.status &lt;&gt; 3 OR project.status IS NULL)
+    </select>
+
+    <!--分页获取项目收支平衡 -->
+    <select id="getProjectInAndOutByRange" resultMap="CustomerResultMap">
+        SELECT project.id as id, project.id as project_ids, project_code, project_name as project_names,contract_amount,
+        (SELECT IFNULL(SUM(cost),0) FROM report WHERE state = 1 AND project_id = project.id) AS fee_man,
+        (SELECT IFNULL(SUM(amount),0) FROM expense_item , expense_sheet WHERE project_id = project.id AND  expense_sheet.id = expense_item.`expense_id` AND expense_sheet.type = 0) AS fee_normal,
+        (SELECT IFNULL(SUM(amount),0) FROM expense_item , expense_sheet WHERE project_id = project.id AND  expense_sheet.id = expense_item.`expense_id` AND expense_sheet.type = 1) AS fee_travel,
+        (SELECT IFNULL(SUM(amount),0) FROM expense_item , expense_sheet WHERE project_id = project.id AND  expense_sheet.id = expense_item.`expense_id` AND expense_sheet.type = 2) AS fee_outsourcing
+        FROM project WHERE project.`company_id` = #{companyId}
+        and id IN <foreach collection="ids" close=")" open="(" separator="," index="" item="item">
+        #{item}
+        </foreach>
+    </select>
 </mapper>

BIN
fhKeeper/formulahousekeeper/management-platform/财务人员成本模板_已填写.xlsx


+ 9 - 9
fhKeeper/formulahousekeeper/timesheet/package-lock.json

@@ -565,7 +565,7 @@
     },
     "async-validator": {
       "version": "1.8.5",
-      "resolved": "https://registry.npm.taobao.org/async-validator/download/async-validator-1.8.5.tgz?cache=0&sync_timestamp=1575620599372&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fasync-validator%2Fdownload%2Fasync-validator-1.8.5.tgz",
+      "resolved": "https://registry.nlark.com/async-validator/download/async-validator-1.8.5.tgz",
       "integrity": "sha1-3D4I7B/Q3dtn5ghC8CwM0c7G1/A=",
       "requires": {
         "babel-runtime": "6.x"
@@ -832,7 +832,7 @@
     },
     "babel-helper-vue-jsx-merge-props": {
       "version": "2.0.3",
-      "resolved": "https://registry.npm.taobao.org/babel-helper-vue-jsx-merge-props/download/babel-helper-vue-jsx-merge-props-2.0.3.tgz",
+      "resolved": "https://registry.nlark.com/babel-helper-vue-jsx-merge-props/download/babel-helper-vue-jsx-merge-props-2.0.3.tgz",
       "integrity": "sha1-Iq69OzOQIyjlEyk6jkmSs4T58bY="
     },
     "babel-helpers": {
@@ -2818,7 +2818,7 @@
     },
     "deepmerge": {
       "version": "1.5.2",
-      "resolved": "https://registry.npm.taobao.org/deepmerge/download/deepmerge-1.5.2.tgz",
+      "resolved": "https://registry.npm.taobao.org/deepmerge/download/deepmerge-1.5.2.tgz?cache=0&sync_timestamp=1612354180346&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdeepmerge%2Fdownload%2Fdeepmerge-1.5.2.tgz",
       "integrity": "sha1-EEmdhohEza1P7ghC34x/bwyVp1M="
     },
     "define-property": {
@@ -3073,9 +3073,9 @@
       "dev": true
     },
     "element-ui": {
-      "version": "2.13.0",
-      "resolved": "https://registry.npm.taobao.org/element-ui/download/element-ui-2.13.0.tgz",
-      "integrity": "sha1-9rsE5bCnbqX2JGYES3dEB7pOvS0=",
+      "version": "2.15.3",
+      "resolved": "https://registry.nlark.com/element-ui/download/element-ui-2.15.3.tgz?cache=0&sync_timestamp=1624954448804&other_urls=https%3A%2F%2Fregistry.nlark.com%2Felement-ui%2Fdownload%2Felement-ui-2.15.3.tgz",
+      "integrity": "sha1-VRCKuCo7zGRuewVwhxxIupYwBlI=",
       "requires": {
         "async-validator": "~1.8.1",
         "babel-helper-vue-jsx-merge-props": "^2.0.0",
@@ -5875,7 +5875,7 @@
     },
     "normalize-wheel": {
       "version": "1.0.1",
-      "resolved": "https://registry.npm.taobao.org/normalize-wheel/download/normalize-wheel-1.0.1.tgz",
+      "resolved": "https://registry.nlark.com/normalize-wheel/download/normalize-wheel-1.0.1.tgz",
       "integrity": "sha1-rsiGr/2wRQcNhWRH32Ls+GFG7EU="
     },
     "npmlog": {
@@ -7826,7 +7826,7 @@
     },
     "resize-observer-polyfill": {
       "version": "1.5.1",
-      "resolved": "https://registry.npm.taobao.org/resize-observer-polyfill/download/resize-observer-polyfill-1.5.1.tgz",
+      "resolved": "https://registry.nlark.com/resize-observer-polyfill/download/resize-observer-polyfill-1.5.1.tgz",
       "integrity": "sha1-DpAg3T0hAkRY1OvSfiPkAmmBBGQ="
     },
     "resolve": {
@@ -8598,7 +8598,7 @@
     },
     "throttle-debounce": {
       "version": "1.1.0",
-      "resolved": "https://registry.npm.taobao.org/throttle-debounce/download/throttle-debounce-1.1.0.tgz",
+      "resolved": "https://registry.nlark.com/throttle-debounce/download/throttle-debounce-1.1.0.tgz",
       "integrity": "sha1-UYU9o3vmihVctugns1FKPEIuic0="
     },
     "through2": {

+ 1 - 1
fhKeeper/formulahousekeeper/timesheet/package.json

@@ -15,7 +15,7 @@
     "dayjs": "^1.10.4",
     "dingtalk-jsapi": "^2.13.42",
     "echarts": "^3.8.5",
-    "element-ui": "^2.13.0",
+    "element-ui": "^2.15.3",
     "font-awesome": "^4.7.0",
     "jquery": "^3.4.1",
     "nprogress": "^0.2.0",

+ 118 - 3
fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/demo_index.html

@@ -54,6 +54,36 @@
       <div class="content unicode" style="display: block;">
           <ul class="icon_lists dib-box">
           
+            <li class="dib">
+              <span class="icon iconfont">&#xe634;</span>
+                <div class="name">流程</div>
+                <div class="code-name">&amp;#xe634;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe60e;</span>
+                <div class="name">长箭头</div>
+                <div class="code-name">&amp;#xe60e;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe6e3;</span>
+                <div class="name">App_New_Line</div>
+                <div class="code-name">&amp;#xe6e3;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe609;</span>
+                <div class="name">line</div>
+                <div class="code-name">&amp;#xe609;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe61d;</span>
+                <div class="name">Insert Line</div>
+                <div class="code-name">&amp;#xe61d;</div>
+              </li>
+          
             <li class="dib">
               <span class="icon iconfont">&#xe611;</span>
                 <div class="name">密 码</div>
@@ -342,9 +372,9 @@
 <pre><code class="language-css"
 >@font-face {
   font-family: 'iconfont';
-  src: url('iconfont.woff2?t=1624604148407') format('woff2'),
-       url('iconfont.woff?t=1624604148407') format('woff'),
-       url('iconfont.ttf?t=1624604148407') format('truetype');
+  src: url('iconfont.woff2?t=1627295057848') format('woff2'),
+       url('iconfont.woff?t=1627295057848') format('woff'),
+       url('iconfont.ttf?t=1627295057848') format('truetype');
 }
 </code></pre>
           <h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
@@ -370,6 +400,51 @@
       <div class="content font-class">
         <ul class="icon_lists dib-box">
           
+          <li class="dib">
+            <span class="icon iconfont firerock-iconliucheng"></span>
+            <div class="name">
+              流程
+            </div>
+            <div class="code-name">.firerock-iconliucheng
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont firerock-iconright"></span>
+            <div class="name">
+              长箭头
+            </div>
+            <div class="code-name">.firerock-iconright
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont firerock-iconApp_New_Line"></span>
+            <div class="name">
+              App_New_Line
+            </div>
+            <div class="code-name">.firerock-iconApp_New_Line
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont firerock-icon0"></span>
+            <div class="name">
+              line
+            </div>
+            <div class="code-name">.firerock-icon0
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont firerock-iconInsertLine"></span>
+            <div class="name">
+              Insert Line
+            </div>
+            <div class="code-name">.firerock-iconInsertLine
+            </div>
+          </li>
+          
           <li class="dib">
             <span class="icon iconfont firerock-iconmima"></span>
             <div class="name">
@@ -802,6 +877,46 @@
       <div class="content symbol">
           <ul class="icon_lists dib-box">
           
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#firerock-iconliucheng"></use>
+                </svg>
+                <div class="name">流程</div>
+                <div class="code-name">#firerock-iconliucheng</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#firerock-iconright"></use>
+                </svg>
+                <div class="name">长箭头</div>
+                <div class="code-name">#firerock-iconright</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#firerock-iconApp_New_Line"></use>
+                </svg>
+                <div class="name">App_New_Line</div>
+                <div class="code-name">#firerock-iconApp_New_Line</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#firerock-icon0"></use>
+                </svg>
+                <div class="name">line</div>
+                <div class="code-name">#firerock-icon0</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#firerock-iconInsertLine"></use>
+                </svg>
+                <div class="name">Insert Line</div>
+                <div class="code-name">#firerock-iconInsertLine</div>
+            </li>
+          
             <li class="dib">
                 <svg class="icon svg-icon" aria-hidden="true">
                   <use xlink:href="#firerock-iconmima"></use>

+ 23 - 3
fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.css

@@ -1,8 +1,8 @@
 @font-face {
   font-family: "iconfont"; /* Project id 2390497 */
-  src: url('iconfont.woff2?t=1624604148407') format('woff2'),
-       url('iconfont.woff?t=1624604148407') format('woff'),
-       url('iconfont.ttf?t=1624604148407') format('truetype');
+  src: url('iconfont.woff2?t=1627295057848') format('woff2'),
+       url('iconfont.woff?t=1627295057848') format('woff'),
+       url('iconfont.ttf?t=1627295057848') format('truetype');
 }
 
 .iconfont {
@@ -13,6 +13,26 @@
   -moz-osx-font-smoothing: grayscale;
 }
 
+.firerock-iconliucheng:before {
+  content: "\e634";
+}
+
+.firerock-iconright:before {
+  content: "\e60e";
+}
+
+.firerock-iconApp_New_Line:before {
+  content: "\e6e3";
+}
+
+.firerock-icon0:before {
+  content: "\e609";
+}
+
+.firerock-iconInsertLine:before {
+  content: "\e61d";
+}
+
 .firerock-iconmima:before {
   content: "\e611";
 }

Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 1
fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.js


+ 35 - 0
fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.json

@@ -5,6 +5,41 @@
   "css_prefix_text": "firerock-icon",
   "description": "",
   "glyphs": [
+    {
+      "icon_id": "1868952",
+      "name": "流程",
+      "font_class": "liucheng",
+      "unicode": "e634",
+      "unicode_decimal": 58932
+    },
+    {
+      "icon_id": "9651039",
+      "name": "长箭头",
+      "font_class": "right",
+      "unicode": "e60e",
+      "unicode_decimal": 58894
+    },
+    {
+      "icon_id": "17223736",
+      "name": "App_New_Line",
+      "font_class": "App_New_Line",
+      "unicode": "e6e3",
+      "unicode_decimal": 59107
+    },
+    {
+      "icon_id": "261001",
+      "name": "line",
+      "font_class": "0",
+      "unicode": "e609",
+      "unicode_decimal": 58889
+    },
+    {
+      "icon_id": "17197893",
+      "name": "Insert Line",
+      "font_class": "InsertLine",
+      "unicode": "e61d",
+      "unicode_decimal": 58909
+    },
     {
       "icon_id": "19410111",
       "name": "密 码",

BIN
fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.ttf


BIN
fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.woff


BIN
fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.woff2


+ 6 - 2
fhKeeper/formulahousekeeper/timesheet/src/main.js

@@ -46,8 +46,8 @@ import 'nprogress/nprogress.css'
 var addRouFlag = false;
 //角色权限对应关系
 var userModules = [{role:0, modules:["工时报告","自动计时","项目管理"]},
-            {role:3, modules:["工时成本统计","项目报表服务","费用报销","财务核算成本","项目管理"]},
-            {role:4, modules:["组织架构"]},
+            {role:3, modules:["工时报告","工时成本统计","项目报表服务","费用报销","财务核算成本","项目管理"]},
+            {role:4, modules:["工时报告", "组织架构"]},
             {role:5, modules:["工时报告","自动计时","项目管理"]},];
 router.beforeEach((to, from, next) => {
     NProgress.start();
@@ -76,6 +76,10 @@ router.beforeEach((to, from, next) => {
                 if (user.company.packageExpense == 0) {
                     filterRouter = allRouters.filter(r=>{return r.name != '费用报销' && r.name != '项目报表服务'});
                 }
+                if (user.company.packageCustomer == 0) {
+                    //没有客户管理功能的,需要去掉
+                    filterRouter = allRouters.filter(r=>{return r.name != '客户管理'});
+                }
 
                 if (user.role == 1 || user.role == 2) {
                     getRoutes = filterRouter;

+ 26 - 2
fhKeeper/formulahousekeeper/timesheet/src/routes.js

@@ -39,10 +39,13 @@ import PdfView from './views/pdf/pdfview';
 
 // 费用报销
 import expense from './views/expense/expense';
+//客户管理
+import customer from './views/customer/list';
 //企业报表
 import corpReport from './views/corpreport/list';
 
-
+//审批流程
+import workflow from './views/workflow/report';
 // 权限管理
 // import jurisdiction from './views/jurisdiction/jurisdiction'
 
@@ -171,6 +174,17 @@ export const allRouters = [//组织架构
             { path: '/corpreport', component: corpReport, name: '项目报表服务' }
         ]
     },
+    {
+        path: '/',
+        component: Home,
+        name: '客户管理',
+        iconCls: 'iconfont firerock-iconbaobiao',
+        leaf: true,
+        children: [
+            { path: '/customer', component: customer, name: '客户管理' }
+        ]
+    },
+    
     // 费用报销模块
     {
         path: '/',
@@ -202,7 +216,17 @@ export const allRouters = [//组织架构
     //         { path: '/role', component: role, name: '角色权限' },
     //     ]
     // },
-    
+    // {
+        
+    //     path: '/',
+    //     component: Home,
+    //     name: '',
+    //     iconCls: 'iconfont firerock-iconliucheng',
+    //     leaf: true,//只有一个节点
+    //     children: [
+    //         { path: '/workflow', component: workflow, name: '审批流程设置' },
+    //     ]
+    // },
     //设置时间类型
     {
         

+ 199 - 28
fhKeeper/formulahousekeeper/timesheet/src/views/corpreport/list.vue

@@ -20,6 +20,7 @@
               <el-menu-item index="1-2"><p @click="ssl(1)">项目任务报表</p></el-menu-item>
               <el-menu-item index="1-3"><p @click="ssl(2)">项目成本报表</p></el-menu-item>
               <el-menu-item index="1-4"><p @click="ssl(3)">项目收支平衡表</p></el-menu-item>
+              <el-menu-item index="1-5" v-if="user.company.packageCustomer == 1"><p @click="ssl(4)">客户项目利润表</p></el-menu-item>
             </el-submenu>
           </el-menu>
       </el-col>
@@ -32,17 +33,17 @@
   <div class="contents">
     <div class="headine" ref="headine">
       <h3 ref="headHe" style="padding-left: 210px">{{shuz[ins]}}</h3>
-      <p style="float: right;margin-right: 25px;"><el-button type="primary" @click="exportExcel" size="mini">报表导出</el-button></p>
+      <p style="float: right;margin-right: 25px;" ><el-button type="primary" @click="exportExcel" size="mini">报表导出</el-button></p>
     </div>
     <div ref="staff" style="margin: 5px 0px 0px 200px; width: 84%">
         <div class="staff">
             <!--项目报表 -->
-            <el-table v-show="ins == 0" border :data="list" highlight-current-row v-loading="listLoading" :height="tableHeight" style="width: 100%;">
+            <el-table v-if="ins == 0" border :data="list" highlight-current-row v-loading="listLoading" :height="tableHeight" style="width: 100%;">
                 <el-table-column  prop="projectCode" label="项目编码"  width="120"></el-table-column>
                 <el-table-column  prop="projectName" label="项目名称" ></el-table-column>
                 <el-table-column prop="inchargerName" label="负责人"  width="80">
                 </el-table-column>
-                <el-table-column prop="contractAmount" label="合同金额(元)"  width="150">
+                <el-table-column prop="contractAmount" label="合同金额(元)"  width="150" align="right">
                   <template slot-scope="scope">
                         {{scope.row.contractAmount.toFixed(2)}}
                     </template>
@@ -64,19 +65,19 @@
             </el-table>
 
             <!-- 项目任务报表 -->
-            <el-table v-show="ins == 1" border :data="list" highlight-current-row v-loading="listLoading" :height="tableHeight" style="width: 100%;">
+            <el-table v-if="ins == 1" border :data="list" highlight-current-row v-loading="listLoading" :height="tableHeight" style="width: 100%;">
                 <el-table-column  prop="project_code" label="项目编码"  width="120"></el-table-column>
                 <el-table-column  prop="project_name" label="项目名称" width="200"></el-table-column>
                 <el-table-column prop="name" label="任务名称"  width="300">
                 </el-table-column>
                 <el-table-column prop="plan_hours" label="计划工时(h)"  width="150">
                   <template slot-scope="scope">
-                        {{scope.row.plan_hours.toFixed(1)}}
+                        {{scope.row.plan_hours == null? 0:scope.row.plan_hours.toFixed(1)}}
                     </template>
                 </el-table-column>
                 <el-table-column prop="real_hours" label="实际工时(h)"  width="150">
                    <template slot-scope="scope">
-                        {{scope.row.real_hours.toFixed(1)}}
+                        {{scope.row.real_hours == null? 0:scope.row.real_hours.toFixed(1)}}
                     </template>
                 </el-table-column>
                 <el-table-column prop="task_status" label="状态" width="80" >
@@ -97,80 +98,132 @@
             </el-table>
 
             <!--项目成本报表 -->
-            <el-table v-show="ins == 2" border :data="list" highlight-current-row v-loading="listLoading" :height="tableHeight" style="width: 100%;">
+            <el-table v-if="ins == 2" border :data="list" highlight-current-row v-loading="listLoading" :height="tableHeight" style="width: 100%;">
                 <el-table-column  prop="projectCode" label="项目编码"  width="120"></el-table-column>
                 <el-table-column  prop="projectName" label="项目名称" ></el-table-column>
-                <el-table-column prop="feeMan" label="人工成本"  width="100" >
+                <el-table-column prop="feeMan" label="人工成本"  width="100"  align="right">
+                  <template slot-scope="scope">
+                        {{scope.row.feeMan==null?0:scope.row.feeMan.toFixed(2)}}
+                    </template>
+                </el-table-column>
+                <el-table-column prop="feeNormal" label="一般费用"  width="100" align="right">
+                  <template slot-scope="scope">
+                        {{scope.row.feeNormal==null?0:scope.row.feeNormal.toFixed(2)}}
+                    </template>
+                </el-table-column>
+                <el-table-column prop="feeTravel" label="差旅费用"  width="100" align="right">
+                  <template slot-scope="scope">
+                        {{scope.row.feeTravel==null?0:scope.row.feeTravel.toFixed(2)}}
+                    </template>
+                </el-table-column>
+                <el-table-column prop="feeOutsourcing" label="外包费用"  width="100" align="right">
+                  <template slot-scope="scope">
+                        {{scope.row.feeOutsourcing==null?0:scope.row.feeOutsourcing.toFixed(2)}}
+                    </template>
+                </el-table-column>
+                <el-table-column  label="总费用"  width="100" align="right">
+                  <template slot-scope="scope">
+                        {{scope.row.feeMan+scope.row.feeNormal+scope.row.feeTravel+scope.row.feeOutsourcing}}
+                    </template>
+                </el-table-column>
+            </el-table>
+            <!--项目收支平衡表 -->
+            <el-table v-if="ins == 3" border :data="list" highlight-current-row v-loading="listLoading" :height="tableHeight" style="width: 100%;">
+                <el-table-column prop="projectCode" label="项目编码"  width="120"></el-table-column>
+                <el-table-column prop="projectName" label="项目名称" ></el-table-column>
+                <el-table-column prop="contractAmount" label="合同金额" width="100" align="right">
+                  <template slot-scope="scope">
+                        {{scope.row.contractAmount.toFixed(2)}}
+                    </template>
+                </el-table-column>
+                <el-table-column prop="feeMan" label="人工成本"   width="100" align="right">
                   <template slot-scope="scope">
                         {{scope.row.feeMan.toFixed(2)}}
                     </template>
                 </el-table-column>
-                <el-table-column prop="feeNormal" label="一般费用"  width="100">
+                <el-table-column prop="feeNormal" label="一般费用"  width="100" align="right">
                   <template slot-scope="scope">
                         {{scope.row.feeNormal.toFixed(2)}}
                     </template>
                 </el-table-column>
-                <el-table-column prop="feeTravel" label="差旅费用"  width="100">
+                <el-table-column prop="feeTravel" label="差旅费用"  width="100" align="right">
                   <template slot-scope="scope">
                         {{scope.row.feeTravel.toFixed(2)}}
                     </template>
                 </el-table-column>
-                <el-table-column prop="feeOutsourcing" label="外包费用"  width="100">
+                <el-table-column prop="feeOutsourcing" label="外包费用"  width="100" align="right">
                   <template slot-scope="scope">
                         {{scope.row.feeOutsourcing.toFixed(2)}}
                     </template>
                 </el-table-column>
-                <el-table-column  label="总费用"  width="100">
+                <el-table-column  label="总费用"  width="100" align="right">
                   <template slot-scope="scope">
                         {{scope.row.feeMan+scope.row.feeNormal+scope.row.feeTravel+scope.row.feeOutsourcing}}
                     </template>
                 </el-table-column>
+                <el-table-column  label="利润"  width="100" align="right">
+                  <template slot-scope="scope">
+                        {{(scope.row.contractAmount==null?0:scope.row.contractAmount) - (scope.row.feeMan+scope.row.feeNormal+scope.row.feeTravel+scope.row.feeOutsourcing)}}
+                    </template>
+                </el-table-column>
+                <el-table-column  label="利润率"  width="100" align="right">
+                  <template slot-scope="scope">
+                        {{(scope.row.contractAmount==null||scope.row.contractAmount==0)?'-':((scope.row.contractAmount - (scope.row.feeMan+scope.row.feeNormal+scope.row.feeTravel+scope.row.feeOutsourcing))*100/scope.row.contractAmount).toFixed(1)+"%"}}
+                    </template>
+                </el-table-column>
             </el-table>
-            <!--项目收支平衡表 -->
-            <el-table v-show="ins == 3" border :data="list" highlight-current-row v-loading="listLoading" :height="tableHeight" style="width: 100%;">
-                <el-table-column prop="projectCode" label="项目编码"  width="120"></el-table-column>
-                <el-table-column prop="projectName" label="项目名称" ></el-table-column>
-                <el-table-column prop="contractAmount" label="合同金额" width="100">
+            <!--客户项目报表 -->
+            <el-table v-if="ins == 4" border :data="list" 
+            highlight-current-row v-loading="listLoading" :height="tableHeight" 
+             style="width: 100%;">
+                <el-table-column prop="customerName" label="客户名称" ></el-table-column>
+                <el-table-column prop="projectNames" label="相关项目">
+                  <template slot-scope="scope" >
+                    <el-Link @click="expandRow(scope.row, scope.$index)">{{scope.row.projectNames}}</el-Link>
+                  </template>
+                </el-table-column>
+                <el-table-column prop="contractAmount" label="合同金额" width="100" align="right">
                   <template slot-scope="scope">
                         {{scope.row.contractAmount.toFixed(2)}}
                     </template>
                 </el-table-column>
-                <el-table-column prop="feeMan" label="人工成本"   width="100">
+                <el-table-column prop="feeMan" label="人工成本"   width="100" align="right">
                   <template slot-scope="scope">
                         {{scope.row.feeMan.toFixed(2)}}
                     </template>
                 </el-table-column>
-                <el-table-column prop="feeNormal" label="一般费用"  width="100">
+                <el-table-column prop="feeNormal" label="一般费用"  width="100" align="right">
                   <template slot-scope="scope">
                         {{scope.row.feeNormal.toFixed(2)}}
                     </template>
                 </el-table-column>
-                <el-table-column prop="feeTravel" label="差旅费用"  width="100">
+                <el-table-column prop="feeTravel" label="差旅费用"  width="100" align="right">
                   <template slot-scope="scope">
                         {{scope.row.feeTravel.toFixed(2)}}
                     </template>
                 </el-table-column>
-                <el-table-column prop="feeOutsourcing" label="外包费用"  width="100">
+                <el-table-column prop="feeOutsourcing" label="外包费用"  width="100" align="right">
                   <template slot-scope="scope">
                         {{scope.row.feeOutsourcing.toFixed(2)}}
                     </template>
                 </el-table-column>
-                <el-table-column  label="总费用"  width="100">
+                <el-table-column  label="总费用"  width="100" align="right">
                   <template slot-scope="scope">
                         {{scope.row.feeMan+scope.row.feeNormal+scope.row.feeTravel+scope.row.feeOutsourcing}}
                     </template>
                 </el-table-column>
-                <el-table-column  label="利润"  width="100">
+                <el-table-column  label="利润"  width="100" align="right">
                   <template slot-scope="scope">
                         {{(scope.row.contractAmount==null?0:scope.row.contractAmount) - (scope.row.feeMan+scope.row.feeNormal+scope.row.feeTravel+scope.row.feeOutsourcing)}}
                     </template>
                 </el-table-column>
-                <el-table-column  label="利润率"  width="100">
+                <el-table-column  label="利润率"  width="100" align="right">
                   <template slot-scope="scope">
                         {{(scope.row.contractAmount==null||scope.row.contractAmount==0)?'-':((scope.row.contractAmount - (scope.row.feeMan+scope.row.feeNormal+scope.row.feeTravel+scope.row.feeOutsourcing))*100/scope.row.contractAmount).toFixed(1)+"%"}}
                     </template>
                 </el-table-column>
             </el-table>
+            
         <!--工具条-->
         <el-col :span="24" class="toolbar">
             <el-pagination
@@ -189,7 +242,58 @@
     
   </div>
   </div>
-    
+    <!--新增界面-->
+        <el-dialog :title="title" show-summary v-if="addFormVisible" :visible.sync="addFormVisible" :close-on-click-modal="false" customClass="customWidth" width="1000px">
+            <el-table border :data="childrenList" 
+            highlight-current-row v-loading="listLoading" height="400"
+             style="width: 100%;">
+                <el-table-column prop="projectNames" label="相关项目">
+                </el-table-column>
+                <el-table-column prop="contractAmount" label="合同金额" width="100" align="right">
+                  <template slot-scope="scope">
+                        {{scope.row.contractAmount.toFixed(2)}}
+                    </template>
+                </el-table-column>
+                <el-table-column prop="feeMan" label="人工成本"   width="100" align="right">
+                  <template slot-scope="scope">
+                        {{scope.row.feeMan.toFixed(2)}}
+                    </template>
+                </el-table-column>
+                <el-table-column prop="feeNormal" label="一般费用"  width="100" align="right">
+                  <template slot-scope="scope">
+                        {{scope.row.feeNormal.toFixed(2)}}
+                    </template>
+                </el-table-column>
+                <el-table-column prop="feeTravel" label="差旅费用"  width="100" align="right">
+                  <template slot-scope="scope">
+                        {{scope.row.feeTravel.toFixed(2)}}
+                    </template>
+                </el-table-column>
+                <el-table-column prop="feeOutsourcing" label="外包费用"  width="100" align="right">
+                  <template slot-scope="scope">
+                        {{scope.row.feeOutsourcing.toFixed(2)}}
+                    </template>
+                </el-table-column>
+                <el-table-column  label="总费用"  width="100" align="right">
+                  <template slot-scope="scope">
+                        {{scope.row.feeMan+scope.row.feeNormal+scope.row.feeTravel+scope.row.feeOutsourcing}}
+                    </template>
+                </el-table-column>
+                <el-table-column  label="利润"  width="100" align="right">
+                  <template slot-scope="scope">
+                        {{(scope.row.contractAmount==null?0:scope.row.contractAmount) - (scope.row.feeMan+scope.row.feeNormal+scope.row.feeTravel+scope.row.feeOutsourcing)}}
+                    </template>
+                </el-table-column>
+                <el-table-column  label="利润率"  width="100" align="right">
+                  <template slot-scope="scope">
+                        {{(scope.row.contractAmount==null||scope.row.contractAmount==0)?'-':((scope.row.contractAmount - (scope.row.feeMan+scope.row.feeNormal+scope.row.feeTravel+scope.row.feeOutsourcing))*100/scope.row.contractAmount).toFixed(1)+"%"}}
+                    </template>
+                </el-table-column>
+            </el-table>
+            <div slot="footer" class="dialog-footer;">
+                <el-button @click.native="addFormVisible = false">关闭</el-button>
+            </div>
+        </el-dialog>
   </section>
 </template>
 
@@ -200,6 +304,9 @@ export default {
   props: {},
   data() {
     return {
+      addFormVisible:false,
+      title:'',
+      childrenList:[],
       taskTypeTxt:["任务", "里程碑", "风险"],
       taskStatusTxt:["进行中","已完成","已撤销"],
       statusTxt:["-","进行中","已完成","已撤销"],
@@ -217,8 +324,9 @@ export default {
       z   : null,
       value: null,
       dialog: false, // 单据查看展示
-      shuz: ["项目报表","项目任务报表","项目成本报表","项目收支平衡表(利润表)"],
-      ins: 0
+      shuz: ["项目报表","项目任务报表","项目成本报表","项目收支平衡表(利润表)","客户项目利润报表"],
+      ins: 0,
+      user: JSON.parse(sessionStorage.user)
     };
   },
   computed: {},
@@ -236,8 +344,9 @@ export default {
     this.getProjectList();
   },
   filters: {
+      
       numberToCurrency(value) {
-          if (!value) return '0.00'
+          if (value == undefined || !value) return '0.00'
           value = value.toFixed(2)
           const intPart = Math.trunc(value)
           const intPartFormat = intPart.toString().replace(/(\d)(?=(?:\d{3})+$)/g, '$1,')
@@ -251,6 +360,37 @@ export default {
       }
   },
   methods: {
+    expandRow(row, index) {
+      this.title = '客户:'+row.customerName;
+        this.childrenList = row.children;
+        this.addFormVisible = true;
+      },
+    // load(tree, treeNode, resolve) {
+    //     // setTimeout(() => {
+    //     //   resolve()
+    //     // }, 1000)
+    //     [
+    //         {
+    //           projectIds: 31,
+    //           projectNames: '2016-05-01',
+    //           contractAmount: 0,
+    //           feeMan:0,
+    //           feeNormal:0,
+    //           feeTravel:0,
+    //           feeOutsourcing:0,
+    //         },
+    //         {
+    //           projectIds: 32,
+    //           projectNames: '2016-05-01',
+    //           contractAmount: 0,
+    //           feeMan:0,
+    //           feeNormal:0,
+    //           feeTravel:0,
+    //           feeOutsourcing:0,
+    //         },
+    //       ]
+    //   },
+
             //分页
             handleCurrentChange(val) {
                 this.page = val;
@@ -270,6 +410,8 @@ export default {
                     this.getAllProjectCost();
                 } else if (this.ins == 3) {
                     this.getProjectInAndOut();
+                } else if (this.ins == 4) {
+                    this.getCustomerProjectInAndOut();
                 }
             },
       exportExcel() {
@@ -287,6 +429,9 @@ export default {
         } else if (this.ins == 3) {
           fName = "项目收支平衡表.xls";
           url += "/exportProjectInAndOut";
+        } else if (this.ins == 4) {
+          fName = "客户项目利润报表.xls";
+          url += "/exportCustomerProjectInAndOut";
         }
           this.http.post(url, {},
             res => {
@@ -314,10 +459,36 @@ export default {
     ssl(index) {
       this.z = index
       this.ins = index;
+      this.list = [];
       this.page = 1;
       this.pageSize = 20;
       this.getList();
     },
+    getCustomerProjectInAndOut() {
+      this.listLoading = true;
+      this.http.post('/project/getCustomerProjectInAndOut', {
+                    pageIndex: this.page,
+                    pageSize: this.size,
+                    },
+        res => {
+            if (res.code == "ok") {
+                this.list = res.data.records;
+                this.total = res.data.total;
+                this.listLoading = false; 
+            } else {
+                this.$message({
+                message: res.msg,
+                type: "error"
+                });
+            }
+        },
+        error => {
+            this.$message({
+                message: error,
+                type: "error"
+            });
+        });
+    },
     getProjectInAndOut() {
       this.listLoading = true;
       this.http.post('/project/getProjectInAndOut', {

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

@@ -0,0 +1,461 @@
+<template>
+    <section>
+        <!--工具条-->
+        <el-col :span="24" class="toolbar" style="padding-bottom: 0px;">
+            <el-form :inline="true">
+                <el-form-item label="客户列表">
+                    
+                </el-form-item>
+                <el-form-item >
+                    <div>
+                    <el-input style="float:left;" v-model="keyword" class="input-with-select" placeholder="请输入客户名称关键字" clearable="true">
+                        <el-button slot="append" @click="searchList" icon="el-icon-search"></el-button>
+                    </el-input>
+                    </div>
+                </el-form-item>
+                <el-form-item style="float:right;" v-if="user.role == 1||user.role == 2||user.role == 5">
+                    <el-link type="primary" :underline="false" @click="handleAdd(-1,null)">新增客户</el-link>
+                </el-form-item>
+            </el-form>
+        </el-col>
+
+        <!--列表-->
+        <el-table :data="list" highlight-current-row v-loading="listLoading" :height="tableHeight" style="width: 100%;">
+            <el-table-column type="index" width="60">
+                <template slot-scope="scope" >
+                        {{scope.$index+1+(page-1)*size}}
+                    </template>
+            </el-table-column>
+            <el-table-column prop="customerCode" label="客户编码"  width="120"></el-table-column>
+            <el-table-column prop="customerName" label="客户名称" >
+            </el-table-column>
+            <el-table-column prop="contactName" label="联系人"  width="120">
+            </el-table-column>
+            <el-table-column prop="contactPhone" label="联系电话"  width="150">
+            </el-table-column>
+            <el-table-column prop="email" label="邮箱"  width="150">
+            </el-table-column>
+            <el-table-column prop="address" label="地址" >
+            </el-table-column>
+            
+            <el-table-column label="操作" width="150" v-if="user.role == 1||user.role == 2||user.role == 5 || user.leader">
+                <template slot-scope="scope">
+                    <el-button size="mini" v-if="user.role>0" type="primary" @click="handleAdd(scope.$index, scope.row)">编辑</el-button>
+                    <el-button v-if="user.role>0" size="mini"  @click="deletePro(scope.$index, scope.row)">删除</el-button>
+                </template>
+            </el-table-column>
+        </el-table>
+
+        <!--工具条-->
+        <el-col :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>
+
+        <!--新增界面-->
+        <el-dialog :title="title" v-if="addFormVisible" :visible.sync="addFormVisible" :close-on-click-modal="false" customClass="customWidth" width="800px">
+            <el-form ref="form1" :model="addForm" :rules="rules" label-width="120px">
+                <el-form-item label="客户编号" >
+                    <el-input v-model="addForm.customerCode" :max="20" :disabled="user.role==0" placeholder="请输入客户编号" clearable></el-input>
+                </el-form-item>
+                <el-form-item label="客户名称" prop="customerName">
+                    <el-input v-model="addForm.customerName" :max="20" :disabled="user.role==0" placeholder="请输入客户名称" clearable></el-input>
+                </el-form-item>
+                <el-form-item label="联系人" prop="contactName">
+                    <el-input v-model="addForm.contactName" :max="20" :disabled="user.role==0" placeholder="请输入客户联系人" clearable></el-input>
+                </el-form-item>
+                <el-form-item label="联系电话" prop="contactPhone">
+                    <el-input v-model="addForm.contactPhone" :max="20" :disabled="user.role==0" placeholder="请输入客户联系电话" clearable></el-input>
+                </el-form-item>
+                <el-form-item label="邮箱" prop="email">
+                    <el-input v-model="addForm.email" :max="25" :disabled="user.role==0" placeholder="请输入客户邮箱" clearable></el-input>
+                </el-form-item>
+                <el-form-item label="地址" prop="address">
+                    <el-input v-model="addForm.address" :max="50"  :disabled="user.role==0" placeholder="请输入客户联系地址" clearable></el-input>
+                </el-form-item>
+
+            </el-form>
+            <div slot="footer" class="dialog-footer;">
+                <el-button @click.native="addFormVisible = false">取消</el-button>
+                <el-button type="primary" @click="submitInsert" :loading="addLoading">提交</el-button>
+            </div>
+        </el-dialog>
+    </section>
+</template>
+<style scoped>
+.input-with-select .el-input-group__prepend {
+    background-color: #fff;
+  }
+.line {
+    padding:10px;
+}
+.line span{
+    font-size:15px;
+}
+.line span:nth-child(even){
+    float:right;
+}
+</style>
+<script>
+    import util from "../../common/js/util";
+    export default {
+        data() {
+            return {
+                roleArray:["普通员工","超级管理员", "系统管理员", "公司高层","人事管理员", "项目管理员"],
+                status:null,
+                statusTxt:["-","进行中","已完成","已撤销"],
+                importanceList:[{id:1,label:'正常'},{id:2,label:'紧急'},{id:3,label:'重要'},{id:4,label:'重要且紧急'}],
+                searchField:null,
+                keyword:null,
+                user: JSON.parse(sessionStorage.getItem("user")),
+                userDetailVisible: false,
+                userDetail:{},
+                date: new Date(),
+                users: [],
+                participator:[],
+                tableHeight: 0,
+                listLoading: false,
+                total: 0,
+                page: 1,
+                size: 20,
+                list: [],
+                subProjectVisible: false,
+                subProjectList: [],//子项目列表
+                currentProject:{},
+                addSubProject: false,
+                addFormVisible: false,
+                addLoading: false,
+                addUp: 0, // 合计
+                title: "",
+                addForm: {
+                    name: '',
+                    userId: [],
+                    level:1,
+                },
+                rules: {
+                    customerName: [{ required: true, message: "请输入客户名称", trigger: "blur" }],
+                }
+            };
+        },
+        // 过滤器
+        filters: {
+            numberToCurrency(value) {
+                if (!value) return '0.00'
+                // 将数值截取,保留两位小数
+                value = value.toFixed(2)
+                // 获取整数部分
+                const intPart = Math.trunc(value)
+                // 整数部分处理,增加,
+                const intPartFormat = intPart.toString().replace(/(\d)(?=(?:\d{3})+$)/g, '$1,')
+                // 预定义小数部分
+                let floatPart = '.00'
+                // 将数值截取为小数部分和整数部分
+                const valueArray = value.toString().split('.')
+                if (valueArray.length === 2) { // 有小数部分
+                floatPart = valueArray[1].toString() // 取得小数部分
+                return intPartFormat + '.' + floatPart
+                }
+                return intPartFormat + floatPart
+            }
+        },
+        methods: {
+            importProject(item) {
+                //首先判断文件类型
+                let str = item.file.name.split(".");
+                let format = str[str.length - 1];
+                if (format != "xls" && format != "xlsx") {
+                    this.$message({
+                        message: "请选择.xls或.xlsx文件",
+                        type: "error"
+                    });
+                } else {
+                    this.listLoading = true;
+                    let formData = new FormData();
+                    formData.append("file", item.file);
+                    formData.append("userId", this.user.id);
+                    this.http.uploadFile('/project/importData', formData,
+                    res => {
+                        this.$refs.upload.clearFiles();
+                        this.listLoading = false;
+                        if (res.code == "ok") {
+                            this.$message({
+                                message: "导入成功",
+                                type: "success"
+                            });
+                            this.getList();
+                        } else {
+                            this.$message({
+                                message: res.msg,
+                                type: "error"
+                            });
+                        }
+                    },
+                    error => {
+                        this.$refs.upload.clearFiles();
+                        this.listLoading = false;
+                        this.$message({
+                            message: error,
+                            type: "error"
+                        });
+                    });
+                }
+            },
+            number(){  
+        //      this.addForm.budget = this.addForm.budget.replace(/[^\.\d]/g,'');
+        //         this.addForm.budget = this.addForm.budget.replace('.','');
+          },
+            deleteSubPro(subProject) {
+                this.$confirm("确定要删除子项目" + subProject.name + "吗?","删除子项目", {
+                    confirmButtonText: "确定",
+                    cancelButtonText: "取消",
+                    type: "warning"
+                })
+                .then(() => {
+                    this.listLoading = true;
+                    this.http.post('/sub-project/deleteProject',{ 
+                        id: subProject.id 
+                    },
+                    res => {
+                        this.listLoading = false;
+                        if (res.code == "ok") {
+                            this.$message({
+                                message: "删除成功",
+                                type: "success"
+                            });
+                            this.subProject(this.currentProject);
+                        } else {
+                            this.$message({
+                                message: res.msg,
+                                type: "error"
+                            });
+                        }
+                    },
+                    error => {
+                        this.listLoading = false;
+                        this.$message({
+                            message: error,
+                            type: "error"
+                        });
+                        }
+                    );
+                })
+                .catch(() => {});
+            },
+            searchList() {
+                this.page = 1;
+                this.getList();
+            },
+            addNewSubProject(subProject) {
+                console.log(123);
+                if (subProject == null) {
+                    this.addForm = {projectId: this.currentProject.id, level:1}
+                } else {
+                    this.addForm = subProject;
+                }
+                this.addSubProject = true;
+            },
+            //显示子项目
+            subProject(item) {
+                this.subProjectVisible = true;
+                this.currentProject = item;
+                this.http.post('/sub-project/list', {
+                    projectId: item.id
+                },
+                res => {
+                    if (res.code == "ok") {
+                        this.subProjectList = res.data;
+                    } else {
+                        this.$message({
+                        message: res.msg,
+                        type: "error"
+                        });
+                    }
+                },
+                error => {
+                    this.$message({
+                        message: error,
+                        type: "error"
+                    });
+                });
+            },
+            //显示用户详情
+            showUser(userId) {
+                this.userDetailVisible = true;
+                this.http.post(this.port.manage.userDetail, {
+                    userId: userId
+                },
+                res => {
+                    if (res.code == "ok") {
+                        this.userDetail = res.data;
+                    } else {
+                        this.$message({
+                        message: res.msg,
+                        type: "error"
+                        });
+                    }
+                },
+                error => {
+                    this.$message({
+                        message: error,
+                        type: "error"
+                    });
+                });
+            },
+            
+            
+            //分页
+            handleCurrentChange(val) {
+                this.page = val;
+                this.getList();
+            },
+
+            handleSizeChange(val) {
+                this.size = val;
+                this.getList();
+            },
+
+            //获取项目列表
+            getList() {
+                this.listLoading = true;
+                this.http.post('/customer-info/list', {
+                    pageIndex: this.page,
+                    pageSize: this.size,
+                    keyword:this.keyword
+                },
+                res => {
+                    this.listLoading = false;
+                    if (res.code == "ok") {
+                        var list = res.data.records;
+                        this.list = list;
+                        this.total = res.data.total;
+                    } else {
+                        this.$message({
+                            message: res.msg,
+                            type: "error"
+                        });
+                    }
+                },
+                error => {
+                    this.listLoading = false;
+                    this.$message({
+                        message: error,
+                        type: "error"
+                    });
+                });
+            },
+
+            //显示新增界面
+            handleAdd(i, item) {
+                if(i == -1) {
+                    this.title = "新增客户";
+                    this.addForm = {
+                    }
+                } else {
+                    this.title = "修改客户";
+                    this.addForm = JSON.parse(JSON.stringify(item));
+                }
+                this.addFormVisible = true;
+            },
+
+            submitInsert() {
+                this.$refs.form1.validate(valid => {
+                    if (valid) {
+                        this.addLoading = true;
+                        this.http.post('/customer-info/addOrMod', this.addForm,
+                        res => {
+                            this.addLoading = false;
+                            if (res.code == "ok") {
+                                this.addFormVisible = false;
+                                this.getList();
+                            } else {
+                                this.$message({
+                                    message: res.msg,
+                                    type: "error"
+                                });
+                            }
+                        },
+                        error => {
+                            this.addLoading = false;
+                            this.$message({
+                                message: error,
+                                type: "error"
+                            });
+                        });
+                        }
+                });
+            },
+
+            // 删除
+            deletePro(i, item) {
+                this.$confirm("确定要客户" + item.customerName + "吗?","删除客户", {
+                    confirmButtonText: "确定",
+                    cancelButtonText: "取消",
+                    type: "warning"
+                })
+                .then(() => {
+                    this.listLoading = true;
+                    this.http.post('/customer-info/delete',{ 
+                        id: item.id 
+                    },
+                    res => {
+                        this.listLoading = false;
+                        if (res.code == "ok") {
+                            this.$message({
+                                message: "删除成功",
+                                type: "success"
+                            });
+                            this.getList();
+                        } else {
+                            this.$message({
+                                message: res.msg,
+                                type: "error"
+                            });
+                        }
+                    },
+                    error => {
+                        this.listLoading = false;
+                        this.$message({
+                            message: error,
+                            type: "error"
+                        });
+                        }
+                    );
+                })
+                .catch(() => {});
+            },
+        },
+        created() {
+            let height = window.innerHeight;
+            this.tableHeight = height - 195;
+            const that = this;
+            window.onresize = function temp() {
+                that.tableHeight = window.innerHeight - 195;
+            };
+        },
+        mounted() {
+            this.getList();
+        }
+    };
+</script>
+
+<style lang="scss" scoped>
+.rg_span{
+    display: inline-block;
+}
+.rg_span span {
+    text-align: right;
+    box-sizing: border-box;
+    padding-right: 10px;
+}
+.el-dialog__title {
+    display: inline-table;
+    margin-top: 20px;
+}
+</style>

+ 98 - 210
fhKeeper/formulahousekeeper/timesheet/src/views/project/earning.vue

@@ -5,50 +5,46 @@
             <el-col :span="24">    
             <div class="box" style="height:650px;">
                 <div >
-                    <div class="lableTxt">项目利润快照</div>
+                    <div class="lableTxt">项目利润快照<el-button type="default" size="small" style="float:right;margin-left:10px;" @click="cancelDelete" v-if="deleteTxt == '确认删除'">取消操作</el-button><el-button type="default" size="small" style="float:right;" @click="showDeleteBox">{{deleteTxt}}</el-button></div>
                     <el-divider></el-divider>
                     <!--利润率列表-->
-                    <el-table :data="list" highlight-current-row v-loading="listLoading" max-height="300" style="width: 100%;">
+                    <el-table :data="list" highlight-current-row v-loading="listLoading" max-height="300" :height="300" style="width: 100%;" @selection-change="handleSelectionChange">
                         <el-table-column prop="indate" label="校准日期"  ></el-table-column>
-                        <el-table-column prop="profitA"  >
+                        <el-table-column prop="profit" align="right" >
                             <template slot="header">
-                               <span>利润率A</span>
-                               <el-popover placement="top" width="250" trigger="hover" content="利润率A = (合同金额 - 总成本)/合同金额">
+                               <span>利润</span>
+                               <el-popover placement="top" width="250" trigger="hover" content="利润 = (合同金额 - 总成本)">
                                    <i class="el-icon-question" slot="reference" />
                                </el-popover>
                             </template>
-                            <template slot-scope="scope">
-                                {{scope.row.profitA}}%
+                            <template slot-scope="scope" >
+                               ¥{{scope.row.profit | numberToCurrency}}
                             </template>
                         </el-table-column>
-                        <el-table-column prop="profitB" label="利润率B"  >
+                        <el-table-column prop="profitPercent" label="利润率B"  align="right">
                             <template slot="header">
-                               <span>利润率B</span>
-                               <el-popover placement="top" width="350" trigger="hover" content="利润率B = (合同金额 - 总成本 - 预留金额1)/合同金额">
+                               <span>利润率</span>
+                               <el-popover placement="top" width="350" trigger="hover" content="利润率 = (合同金额 - 总成本)/合同金额">
                                    <i class="el-icon-question" slot="reference" />
                                </el-popover>
                             </template>
                             <template slot-scope="scope">
-                                {{scope.row.profitB}}%
-                            </template>
-                        </el-table-column>
-                        <el-table-column prop="profitC" label="利润率C"  >
-                            <template slot="header">
-                               <span>利润率C</span>
-                               <el-popover placement="top" width="430" trigger="hover" content="利润率C = (合同金额 - 总成本 - 预留金额1 - 预留金额2)/合同金额">
-                                   <i class="el-icon-question" slot="reference" />
-                               </el-popover>
-                            </template>
-                            <template slot-scope="scope">
-                                {{scope.row.profitC}}%
+                                {{scope.row.profitPercent| numberToCurrency}}%
                             </template>
                         </el-table-column>
+                        
                         <el-table-column prop="contractAmount" label="合同金额" width="110" >
                             <template slot-scope="scope">
-                               <span style="font-size: 10px">¥{{scope.row.contractAmount | numberToCurrency}}</span>
+                               <span >¥{{scope.row.contractAmount | numberToCurrency}}</span>
                             </template>
                         </el-table-column>
-                        <el-table-column  label="基线成本" >
+                        <el-table-column label="基线成本" align="center">
+                            <el-table-column v-for="item in costFields" :prop="contractAmount" :label="item.baseName" :key="item.id" align="right">
+                                <template slot-scope="scope">
+                                ¥{{scope.row.costList.filter(c=>c.baseId == item.baseId)[0].baseAmount | numberToCurrency}}
+                                </template>
+                            </el-table-column>
+<!-- 
                             <el-table-column prop="baseMan" label="人员成本">
                                 <template slot-scope="scope">
                                 ¥{{scope.row.baseMan | numberToCurrency}}
@@ -73,6 +69,9 @@
                                 <template slot-scope="scope">
                                 ¥{{scope.row.baseRisk2 | numberToCurrency}}
                                 </template>
+                            </el-table-column> -->
+                            <el-table-column  label="选择" width="55" type="selection" v-if="deleteTxt == '确认删除'">
+                                
                             </el-table-column>
                         </el-table-column>
                     </el-table>
@@ -121,14 +120,15 @@
     export default {
         data() {
             return {
+                costFields:[],
+                selectionArray:[],
+                deleteTxt:"删除记录",
                 yList3:[],
                 yList2:[],
                 yList1:[],
                 xList:[],
                 list:[],
-                costChart:null,
-                stagesChart: null,
-                executorChart: null,
+                profitChart:null,
                 pVisible:false,
                 taskSum:{},
                 users:[],
@@ -163,21 +163,84 @@
             }
         },
         methods: {
+            handleSelectionChange(value) {
+                this.selectionArray = value;
+                console.log(this.selectionArray);
+            },
+            cancelDelete() {
+                this.deleteTxt = "删除记录";
+            },
+            showDeleteBox() {
+                if (this.deleteTxt == '删除记录') {
+                    this.deleteTxt = "确认删除";
+                } else {
+                    if (this.selectionArray.length == 0) {
+                        this.$message({
+                            message: '请先选择要删除的记录',
+                            type: "error"
+                        });
+                        return;
+                    }
+                    
+                    this.$confirm("确定要删除该记录吗吗?","删除记录", {
+                        confirmButtonText: "确定",
+                        cancelButtonText: "取消",
+                        type: "warning"
+                    })
+                    .then(() => {
+                        //调接口删除
+                        this.listLoading = true;
+                        var ids = '';
+                        this.deleteTxt = "删除记录";
+                        for (var i=0;i<this.selectionArray.length; i++) {
+                            ids += this.selectionArray[i].id+',';
+                        }
+                        this.http.post('/earning-snapshot/delete',{ 
+                            ids: ids, projectId:this.curProjectId
+                        },
+                        res => {
+                            this.listLoading = false;
+                            if (res.code == "ok") {
+                                this.getProfitSnapshot();
+                            } else {
+                                this.$message({
+                                    message: res.msg,
+                                    type: "error"
+                                });
+                            }
+                        },
+                        error => {
+                            this.listLoading = false;
+                            this.$message({
+                                message: error,
+                                type: "error"
+                            });
+                            }
+                        );
+                    }
+                    );
+                }
+
+            },
             getProfitSnapshot() {
                 let _this = this;
+                this.xList = [];
+                this.yList1 = [];
                 this.http.post('/earning-snapshot/list', {projectId: this.curProjectId},
                 res => {
                     if (res.code == "ok") {
                         var list = JSON.parse(JSON.stringify(res.data)).reverse();
+                        if (list.length > 0) {
+                            this.costFields = list[0].costList;
+                        }
                         _this.list = res.data;
                         for (var m=0;m<list.length; m++) {
                             this.xList.push(list[m].indate);
-                            this.yList1.push(list[m].profitA);
-                            this.yList2.push(list[m].profitB);
-                            this.yList3.push(list[m].profitC);
+                            this.yList1.push(list[m].profitPercent);
                         }
                         //图表展示
                         var myChart = echarts.init(document.getElementById("chartPanel"));
+                        this.profitChart = myChart;
                         myChart.setOption({
                             title: {
                                 textStyle: {
@@ -201,7 +264,7 @@
                                trigger: 'axis'
                             },
                             legend: {
-                                data: ['利润率A', '利润率B', '利润率C']
+                                data: ['利润率(%)']
                             },
                             grid: {
                                 left: '3%',
@@ -219,78 +282,12 @@
                             },
                             series : [
                                 {
-                                    name: '利润率A',
+                                    name: '利润率(%)',
                                     type: 'line',
                                     stack: '百分比',
                                     data: this.yList1
                                 },
-                                {
-                                    name: '利润率B',
-                                    type: 'line',
-                                    stack: '百分比',
-                                    data: this.yList2
-                                },
-                                {
-                                    name: '利润率C',
-                                    type: 'line',
-                                    stack: '百分比',
-                                    data: this.yList3
-                                },
-                            ]
-                        })
-                    } else {
-                        this.$message({
-                            message: res.msg,
-                            type: "error"
-                        });
-                    }
-                },
-                error => {
-                    this.$message({
-                        message: error,
-                        type: "error"
-                    });
-                });
-            },
-            getStagesPanel(){
-                let _this = this;
-                this.http.post('/task/getStagesPanel', {projectId: this.curProjectId},
-                res => {
-                    if (res.code == "ok") {
-                        var list = res.data;
-                        var myChart = echarts.init(document.getElementById("stagesPanel"));
-                        _this.stagesChart = myChart;
-                        myChart.setOption({
-                            title: {
-                                show:list.length == 0,
-                                textStyle: {
-                                    color: "#666666",
-                                    fontSize: 18,
-                                    fontWeight: 'normal',
-                                 },
-                              text: list.length == 0?"暂无数据":"任务列表统计",
-                              left: "center",
-                              top: "center"
-                            },
-                            toolbox: {
-                                show: true,
-                                feature:{
-                                    saveAsImage:{
-                                        show:true
-                                    },
-                                }
-                            },
-                            tooltip:{
-                                trigger:'item',
-                                formatter: "{b}<br/>任务数:{c} ({d}%)",
-                            },
-                            series : [
-                                {
-                                    name: '任务列表',
-                                    type: 'pie',
-                                    radius: '55%',
-                                    data:list
-                                }
+                                
                             ]
                         })
                     } else {
@@ -307,119 +304,13 @@
                     });
                 });
             },
-            getExecutorPanel(){
-                let _this = this;
-                this.http.post('/task/getExecutorPanel', {projectId: this.curProjectId},
-                res => {
-                    if (res.code == "ok") {
-                        var xList = [], yList = [], list = res.data;
-                        for(var i in list) {
-                            xList.push(list[i].executorName);
-                            yList.push({
-                                "value": list[i].taskCount,
-                                "id": list[i].executorId
-                            });
-                        }
-                        var myChart = echarts.init(document.getElementById("executorPanel"));
-                        _this.executorChart = myChart;
-                        var option = {
-                            title: {
-                                show:list.length == 0,
-                                textStyle: {
-                                    color: "#666666",
-                                    fontSize: 18,
-                                    fontWeight: 'normal',
-                                 },
-                              text: list.length == 0?"暂无数据":"执行人分配图",
-                              left: "center",
-                              top: "center"
-                            },
-                            toolbox: {
-                                show: true,
-                                feature:{
-                                    saveAsImage:{
-                                        show:true
-                                    },
-                                    restore:{
-                                        show:true
-                                    },
-                                    magicType:{
-                                        type:['line','bar']
-                                    },
-                                }
-                            },
-                            tooltip:{
-                                trigger:'axis',
-                                formatter: function (params,ticket,callback) {
-                                    var res = params[0].name + ""+" : " + params[0].data.value 
-                                    + "个";
-                                    _this.params = params;
-                                    return res;
-                                }
-                            },
-                            xAxis: {
-                                data: xList,
-                                axisLabel: {
-                                    interval:0,rotate:20
-                                }
-                            },
-                            yAxis: [{
-                                type : 'value',
-                                axisLabel: {
-                                    formatter:'{value} '
-                                }
-                            }],
-                            series: [{
-                                name: '任务数量(个)',
-                                type: 'bar',
-                                barMaxWidth: 30,
-                                data: yList,
-                            }]
-                        };
-                        myChart.setOption(option);
-                        console.log('===这是完成');
-                    } else {
-                        this.$message({
-                            message: res.msg,
-                            type: "error"
-                        });
-                    }
-                },
-                error => {
-                    this.$message({
-                        message: error,
-                        type: "error"
-                    });
-                });
-            },
-            getProjectTaskSum() {
-                this.http.post('/project/taskSum', {
-                    id: this.curProjectId
-                },
-                res => {
-                    if (res.code == "ok") {
-                        this.taskSum = res.data;
-                    } else {
-                        this.$message({
-                        message: res.msg,
-                        type: "error"
-                        });
-                    }
-                },
-                error => {
-                    this.$message({
-                        message: error,
-                        type: "error"
-                    });
-                });
-            },
+            
             refreshPage() {
                 this.curProjectId = parseInt(this.$route.params.id);
                 this.getProfitSnapshot();
             }
         },
         created() {
-            console.log('created===');
             let height = window.innerHeight;
             this.tableHeight = height - 160;
             const that = this;
@@ -428,13 +319,10 @@
             };
         },
         mounted() {
-            console.log('=========图表mounted===');
             this.curProjectId = parseInt(this.$route.params.id);
             var _this = this;
             window.addEventListener("resize", function() {
-                _this.executorChart.resize();
-                _this.stagesChart.resize();
-                _this.costChart.resize();
+                _this.profitChart.resize();
             });
             this.getProfitSnapshot(); // 调用图表方法
         }

+ 7 - 5
fhKeeper/formulahousekeeper/timesheet/src/views/project/fileCenter.vue

@@ -29,11 +29,12 @@
             <el-table :data="recentFiles" highlight-current-row :height="tableHeight">
                 <el-table-column prop="documentName" label="近期文件" sortable="true">
                     <template slot-scope="scope">
-                        <el-link @click.stop.native="viewOnline(scope.row)">
+                        <!-- <el-link @click.stop.native="viewOnline(scope.row)"> -->
                         <i v-if="scope.row.documentType == -1" class="iconfont firerock-iconfile fileTypeIcon"></i>
                         <i v-if="scope.row.documentType != -1" :class="docTypeList[scope.row.documentType]+' fileTypeIcon'" ></i>
-                        <span style="margin-left:8px;color:#262626;" @click="viewOnline(scope.row)">{{scope.row.documentName}}</span>
-                        </el-link>
+                        <span style="margin-left:8px;color:#262626;" >{{scope.row.documentName}}</span>
+                        <!-- <span style="margin-left:8px;color:#262626;" @click="viewOnline(scope.row)">{{scope.row.documentName}}</span> -->
+                        <!-- </el-link> -->
                     </template>
                 </el-table-column>
                 <el-table-column width="60">
@@ -50,10 +51,11 @@
                             <i class="el-icon-folder fileTypeIcon"></i><span style="margin-left:8px;color:#262626;" >{{scope.row.documentName}}</span>
                         </div>
                         <div v-if="scope.row.isFolder==0">
-                            <el-link @click.stop.native="viewOnline(scope.row)">
+                            <!-- <el-link @click.stop.native="viewOnline(scope.row)"> -->
                             <i v-if="scope.row.documentType == -1" class="iconfont firerock-iconfile fileTypeIcon"></i>
                             <i v-if="scope.row.documentType != -1" :class="docTypeList[scope.row.documentType]+' fileTypeIcon'"></i>
-                            <span style="margin-left:8px;color:#262626;" >{{scope.row.documentName}}</span></el-link>
+                            <span style="margin-left:8px;color:#262626;" >{{scope.row.documentName}}</span>
+                            <!-- </el-link> -->
                         </div>
                     </template>
                 </el-table-column>

+ 51 - 16
fhKeeper/formulahousekeeper/timesheet/src/views/project/info.vue

@@ -48,7 +48,12 @@
                 <div class="box info" style="margin-top:10px;">
                     <div><label>成本基线<el-link v-if="user.id == project.creatorId || user.id == project.inchargerId" @click="showEditBase" style="float:right;"><i class="el-icon-edit"  ></i></el-link></label>
                     <el-row :gutter="10">
-                        <el-col :span="5" ><span class="gray_label">人工成本:</span></el-col><el-col :span="7" ><span>
+                        <div v-for="item in projectBaseCostData" :key="item.id">
+                        <el-col :span="5" ><span class="gray_label">{{item.baseName}}:</span></el-col>
+                        <el-col :span="7" align="right" ><span style="padding-right:20px;">
+                            ¥{{item.baseAmount==null?'-':item.baseAmount | numberToCurrency}}</span></el-col>
+                        </div>
+                        <!-- <el-col :span="5" ><span class="gray_label">人工成本:</span></el-col><el-col :span="7" ><span>
                             ¥{{project.baseMan==null?'-':project.baseMan | numberToCurrency}}</span></el-col>
                         <el-col :span="5" ><span class="gray_label">费用:</span></el-col><el-col :span="7" ><span>
                         ¥{{project.baseFee==null?'-':project.baseFee | numberToCurrency}}</span></el-col></el-row>
@@ -59,7 +64,7 @@
                         <el-row :gutter="10"><el-col :span="5" ><span class="gray_label">风险预留金额2:</span></el-col><el-col :span="7" ><span>
                         ¥{{project.baseRisk2==null?'-':project.baseRisk2 | numberToCurrency}}</span></el-col>
                         <el-col :span="5" ><span class="gray_label">总成本:</span></el-col><el-col :span="7" ><span>
-                        ¥{{project.budget==null?'-':project.budget | numberToCurrency}}</span></el-col>
+                        ¥{{project.budget==null?'-':project.budget | numberToCurrency}}</span></el-col> -->
                     </el-row>
                     </div>
                 </div>
@@ -169,8 +174,11 @@
         </el-dialog>
 
         <el-dialog title="校正成本基线" v-if="addBaseFormVisible" :visible.sync="addBaseFormVisible" :close-on-click-modal="false" customClass="customWidth" width="600px">
-            <el-form ref="basicInfoForm" :model="addForm" :rules="rules" label-width="120px">
-                <el-form-item label="人工成本" >
+            <el-form ref="basicInfoForm" label-width="120px">
+                <el-form-item v-for="item in modBaseCostData" :label="item.baseName" :key="item.id">
+                    <el-input v-model="item.baseAmount"  placeholder="请输入" clearable></el-input>
+                </el-form-item>
+                <!-- <el-form-item label="人工成本" >
                     <el-input v-model="addForm.baseMan"  placeholder="请输入" clearable></el-input>
                 </el-form-item>
                 <el-form-item label="费用" prop="baseFee">
@@ -184,7 +192,8 @@
                 </el-form-item>
                 <el-form-item label="风险预留金额2" prop="baseRisk2">
                     <el-input v-model="addForm.baseRisk2"  placeholder="请输入" clearable></el-input>
-                </el-form-item>
+                </el-form-item> -->
+                
             </el-form>
             <div slot="footer" class="dialog-footer">
                 <el-button @click.native="addBaseFormVisible = false">取消</el-button>
@@ -261,6 +270,8 @@
     export default {
         data() {
             return {
+                modBaseCostData:[],
+                projectBaseCostData:[],
                 roleArray:["普通员工","超级管理员", "系统管理员", "公司高层","人事管理员", "项目管理员"],
                 addBaseFormVisible:false,
                 addMembVisible:false,
@@ -311,33 +322,55 @@
             }
         },
         methods: {
+            getProjectBaseData(projectId) {
+                this.http.post('/project-basecost/get',{projectId: projectId},
+                        res => {
+                            if (res.code == "ok") {
+                               this.projectBaseCostData = res.data;
+                            } else {
+                                this.$message({
+                                    message: res.msg,
+                                    type: "error"
+                                });
+                            }
+                        },
+                        error => {
+                            this.$message({
+                                message: error,
+                                type: "error"
+                            });
+                            }
+                        );
+            },
             adjustBase() {
                 //如果没有做修改,不提交数据
-                if (this.addForm.baseMan == this.project.baseMan 
-                        && this.addForm.baseFee == this.project.baseFee
-                        && this.addForm.baseOutsourcing == this.project.baseOutsourcing
-                        && this.addForm.baseRisk1 == this.project.baseRisk1
-                        && this.addForm.baseRisk2 == this.project.baseRisk2) {
+                var hasChangeData = false;
+                for (var i=0;i<this.modBaseCostData.length; i++) {
+                    var item = this.modBaseCostData[i];
+                    var oldAmount = this.projectBaseCostData.filter(p=>p.id == item.id)[0].baseAmount;
+                    if (item.baseAmount != oldAmount) {
+                        hasChangeData = true;
+                        break;
+                    }
+                }
+                if (!hasChangeData) {
                     this.addBaseFormVisible = false;
                     return;
                 }
                 this.http.post('/project/adjustBase', {
                     id: this.addForm.id,
                     contractAmount: this.addForm.contractAmount,
-                    baseMan: this.addForm.baseMan,
-                    baseFee:this.addForm.baseFee,
-                    baseOutsourcing:this.addForm.baseOutsourcing,
-                    baseRisk1:this.addForm.baseRisk1,
-                    baseRisk2: this.addForm.baseRisk2
+                    baseCostData:JSON.stringify(this.modBaseCostData),
                 },
                 res => {
                     if (res.code == "ok") {
-                        this.getProjectInfo();
+                        this.getProjectBaseData(this.curProjectId);
                         this.addBaseFormVisible = false;
                         this.$message({
                             message: '校准成功',
                             type: "success"
                         });
+                        this.$emit("basecost-change", null);
                     } else {
                         this.$message({
                         message: res.msg,
@@ -564,6 +597,7 @@
                 this.addForm.userId = arr;
                 this.addForm.code = this.addForm.projectCode;
                 this.addForm.name = this.addForm.projectName;
+                this.modBaseCostData = JSON.parse(JSON.stringify(this.projectBaseCostData));
                 this.addBaseFormVisible = true;
 
             },
@@ -758,6 +792,7 @@
             this.getProjectInfo();
             this.getUsers();
             this.getProjectTaskSum();
+            this.getProjectBaseData(this.curProjectId);
         }
     };
 </script>

+ 246 - 57
fhKeeper/formulahousekeeper/timesheet/src/views/project/list.vue

@@ -27,6 +27,10 @@
                             <el-option label="已撤销" value=3 ></el-option>
                         </el-select>
                 </el-form-item>
+                <!-- 项目成本基线条目 -->
+                <el-form-item style="float:right;" v-if="user.role == 1||user.role == 2||user.role == 5">
+                    <el-link type="primary" :underline="false" @click="showBaseCostItemDialog">基线成本项</el-link>
+                </el-form-item> 
                 <el-form-item style="float:right;" v-if="user.role == 1||user.role == 2||user.role == 5">
                     <el-link type="primary" style="margin-left:5px;" :underline="false" href="./upload/项目导入模板.xlsx" download="项目导入模板.xlsx">模板下载</el-link>
                 </el-form-item>
@@ -67,6 +71,9 @@
                     </v-for>
                 </template>
             </el-table-column>
+            <!-- 客户管理 -->
+            <el-table-column prop="customerName" label="客户"  v-if="user.company.packageCustomer == 1">
+            </el-table-column>
             <!--专业项目协作-->
             <el-table-column prop="status" label="状态" width="100" v-if="user.company.packageProject == 1">
                 <template slot-scope="scope">
@@ -109,6 +116,11 @@
                 <el-form-item label="项目名称" prop="name">
                     <el-input v-model="addForm.name" :disabled="user.role==0" placeholder="请输入项目名称" clearable></el-input>
                 </el-form-item>
+                <el-form-item label="客户" v-if="user.company.packageCustomer == 1">
+                    <el-select v-model="addForm.customerId" clearable="true" filterable placeholder="请选择客户" style="width:100%;" >
+                        <el-option v-for="item in customerList" :key="item.id" :label="item.customerName" :value="item.id"></el-option>
+                    </el-select>
+                </el-form-item>
                 <el-form-item label="全部参与者">
                     <el-select v-model="addForm.userId" multiple filterable placeholder="请选择参与者" style="width:100%;" @change="changeParticipator">
                         <el-option v-for="item in users" :key="item.id" :label="item.name" :value="item.id"></el-option>
@@ -158,45 +170,45 @@
                     <el-divider></el-divider>
                     <span class="el-dialog__title">成本基线</span>
                 </div>
-            <!-- 人工成本 -->
-            <span class="rg_span">
+            <!--新版 -->
+            <span class="rg_span" v-for="(item) in projectBaseCostData" :key="item.id">
+                <span style="width:120px;display: inline-block;" v-if="user.company.packageProject==1">{{item.baseName}}</span>
+                <el-input @input="addUpfun()" v-model="item.baseAmount" style="width:200px; margin-bottom: 20px"
+                placeholder="整数" clearable  @keyup.native="item.baseAmount=item.baseAmount.replace(/[^\d]/g,'');"></el-input><span style="margin-left:10px;">元</span>
+            </span>    
+
+            <!-- <span class="rg_span">
                 <span style="width:120px;display: inline-block;" v-if="user.company.packageProject==1">人工成本</span>
                 <el-input @input="addUpfun(addForm.baseMan)" v-model="addForm.baseMan" style="width:200px; margin-bottom: 20px"
                 placeholder="整数" clearable  @keyup.native="addForm.baseMan=addForm.baseMan.replace(/[^\d]/g,'');"></el-input><span style="margin-left:10px;">元</span>
             </span>
-            <!-- 费用 -->
             <span class="rg_span">
                 <span style="width:120px;display: inline-block;" v-if="user.company.packageProject==1">费用</span>
                 <el-input @input="addUpfun(addForm.baseFee)" v-model="addForm.baseFee" style="width:200px;"
                 placeholder="整数" clearable  @keyup.native="addForm.baseFee=addForm.baseFee.replace(/[^\d]/g,'');"></el-input><span style="margin-left:10px;">元</span>
             </span>
-            <!-- 外包费用 -->
             <div class="rg_span" style="margin-bottom: 20px;">
                 <span style=" width:120px;display: inline-block;" v-if="user.company.packageProject==1">外包费用</span>
                 <el-input @input="addUpfun(addForm.baseOutsourcing)" v-model="addForm.baseOutsourcing" style="width:200px;"
                 placeholder="整数" clearable @keyup.native="addForm.baseOutsourcing=addForm.baseOutsourcing.replace(/[^\d]/g,'');"></el-input><span style="margin-left:10px;">元</span>
             </div>
-            <!-- 预留风险金额1 -->
             <div style="display: inline-block;" class="rg_span">
                 <span style="width:120px;display: inline-block;text-align: right;" v-if="user.company.packageProject==1">预留风险金额1</span>
                 <el-input @input="addUpfun(addForm.baseRisk1)" v-model="addForm.baseRisk1" style="width:200px;"
                 placeholder="整数" clearable @keyup.native="addForm.baseRisk1=addForm.baseRisk1.replace(/[^\d]/g,'');"></el-input><span style="margin-left:10px;">元</span>
             </div>
-            <!-- 预留风险金额2 -->
             <div class="rg_span">
                 <span style="width:120px;display: inline-block;text-align: right;" v-if="user.company.packageProject==1">预留风险金额2</span>
                 <el-input @input="addUpfun(addForm.baseRisk2)" v-model="addForm.baseRisk2" style="width:200px;"
                 placeholder="整数" clearable @keyup.native="addForm.baseRisk2=addForm.baseRisk2.replace(/[^\d]/g,'');"></el-input><span style="margin-left:10px;">元</span>
-            </div>
+            </div> -->
             <!-- 合计 -->
-            <div style="margin-top: 20px;float:right;">
+            <div style="margin-top: 10px;float:right;">
                 <span style="margin-right:50px;margin-right:10px;" v-if="user.company.packageProject==1">合计</span>
                  <span v-if="addForm.budget <= 0 || addForm.budget == undefined">0</span>
                  <span v-else>{{addForm.budget | numberToCurrency}}</span>
                 <span style="margin-right:50px;margin-left:10px;">元</span>
             </div>
-
-
             </el-form>
             <div slot="footer" class="dialog-footer;">
                 <el-button @click.native="addFormVisible = false">取消</el-button>
@@ -251,6 +263,41 @@
                 <el-button type="primary" @click="submitInsertSubProject" :loading="addLoading">提交</el-button>
             </div>
         </el-dialog>
+
+        <!-- 项目基线成本项配置弹出框 -->
+        <el-dialog title="项目基线成本项管理" show-header="false" v-if="showBaseConfig" :visible.sync="showBaseConfig" :close-on-click-modal="false" customClass="customWidth" width="500px">
+            <el-table :data="baseCostItemList" highlight-current-row  height="400" style="width: 100%;">
+            <el-table-column type="index" width="60" label="序号">
+                <template slot-scope="scope" >
+                        {{scope.$index+1+(page-1)*size}}
+                    </template>
+            </el-table-column>
+            <el-table-column prop="name" label="名称" ></el-table-column>
+            <el-table-column label="操作" width="150">
+                <template slot-scope="scope" >
+                    <el-button size="small" type="primary" @click="addNewBaseItem(scope.row)">编辑</el-button>
+                    <el-button size="small" type="danger" @click="deleteBaseItem(scope.row)">删除</el-button>
+                </template>
+            </el-table-column>
+
+            </el-table>
+            <div slot="footer" class="dialog-footer">
+                <el-button type="primary" @click="showBaseConfig = false" >关闭</el-button>
+                <el-button type="primary" @click="addNewBaseItem()" >新增成本项</el-button>
+            </div>
+        </el-dialog>
+
+        <el-dialog title="新增/修改成本项" v-if="addBaseItemDialog" :visible.sync="addBaseItemDialog" :close-on-click-modal="false" customClass="customWidth" width="500px">
+            <el-form ref="form2" :model="addForm" :rules="rules" label-width="100px">
+                <el-form-item label="成本项名称" prop="name">
+                    <el-input v-model="addForm.name" placeholder="请输入名称" clearable></el-input>
+                </el-form-item>
+            </el-form>
+            <div slot="footer" class="dialog-footer">
+                <el-button @click.native="addBaseItemDialog = false">取消</el-button>
+                <el-button type="primary" @click="submitInsertBaseItem" :loading="addLoading">提交</el-button>
+            </div>
+        </el-dialog>
     </section>
 </template>
 <style scoped>
@@ -272,6 +319,10 @@
     export default {
         data() {
             return {
+                projectBaseCostData:[],
+                addBaseItemDialog:false,
+                showBaseConfig:false,
+                customerList:[],
                 roleArray:["普通员工","超级管理员", "系统管理员", "公司高层","人事管理员", "项目管理员"],
                 status:null,
                 statusTxt:["-","进行中","已完成","已撤销"],
@@ -304,7 +355,7 @@
                     level:1,
                 },
                 rules: {
-                    name: [{ required: true, message: "请输入项目名称", trigger: "blur" }],
+                    name: [{ required: true, message: "请输入名称", trigger: "blur" }],
                 }
             };
         },
@@ -330,6 +381,119 @@
             }
         },
         methods: {
+            getProjectBaseConfigList() {
+                this.http.post('/project-basecost-setting/list',{},
+                    res => {
+                        if (res.code == "ok") {
+                           this.baseCostItemList = res.data;
+                           this.$forceUpdate();
+                        } else {
+                            this.$message({
+                                message: res.msg,
+                                type: "error"
+                            });
+                        }
+                    },
+                    error => {
+                        this.$message({
+                            message: error,
+                            type: "error"
+                        });
+                        }
+                    );
+                
+            },
+            deleteBaseItem(row) {
+                this.$confirm("该操作可能造成已有数据丢失,确定要删除吗?","删除成本基线项", {
+                    confirmButtonText: "确定",
+                    cancelButtonText: "取消",
+                    type: "warning"
+                })
+                .then(() => {
+                    this.listLoading = true;
+                    this.http.post('/project-basecost-setting/delete',{ 
+                        id: row.id 
+                    },
+                    res => {
+                        this.listLoading = false;
+                        if (res.code == "ok") {
+                            this.$message({
+                                message: "删除成功",
+                                type: "success"
+                            });
+                            this.getProjectBaseConfigList();
+                        } else {
+                            this.$message({
+                                message: res.msg,
+                                type: "error"
+                            });
+                        }
+                    },
+                    error => {
+                        this.listLoading = false;
+                        this.$message({
+                            message: error,
+                            type: "error"
+                        });
+                        }
+                    );
+                })
+                .catch(() => {});
+            },
+            submitInsertBaseItem() {
+                this.http.post('/project-basecost-setting/addOrMod',this.addForm,
+                    res => {
+                        if (res.code == "ok") {
+                            this.addBaseItemDialog = false;
+                            this.baseCostItemList = res.data;
+                            this.$forceUpdate();
+                        } else {
+                            this.$message({
+                                message: res.msg,
+                                type: "error"
+                            });
+                        }
+                    },
+                    error => {
+                        this.$message({
+                            message: error,
+                            type: "error"
+                        });
+                        }
+                    );
+            },
+            showBaseCostItemDialog() {
+                this.showBaseConfig = true;
+            },
+            addNewBaseItem(row) {
+                this.addBaseItemDialog = true;
+                if (row == null) {
+                    this.addForm = {}
+                } else {
+                    this.addForm = row;
+                }
+            },
+            //获取客户列表
+            getCustomerList() {
+                this.http.post('/customer-info/getAll', {
+                },
+                res => {
+                    if (res.code == "ok") {
+                        this.customerList = res.data;
+                    } else {
+                        this.$message({
+                            message: res.msg,
+                            type: "error"
+                        });
+                    }
+                },
+                error => {
+                    this.$message({
+                        message: error,
+                        type: "error"
+                    });
+                });
+            },
             importProject(item) {
                 //首先判断文件类型
                 let str = item.file.name.split(".");
@@ -475,13 +639,16 @@
             //选择参与人
             changeParticipator() {
                 //检查是否在参与人中,如果没有需要加入到参与人中
-                console.log(this.addForm.userId);
-                console.log(this.addForm)
-                var find = false;
                 this.participator = [];
                 this.addForm.userId.forEach(u=>{
-                    var findUser = this.users.filter(au=>au.id == u)[0];    
-                    this.participator.push(findUser);
+                    var list = this.users.filter(au=>au.id == u);
+                    if (list.length > 0) {
+                        var findUser = list[0];    
+                        this.participator.push(findUser);
+                    } else {
+                        console.log('未找到用户: '+u);
+                    }
+                    
                 })
             },
             getUsers() {
@@ -572,6 +739,11 @@
                         code:'',
                         inchargerId:null,
                         level:1,
+                        customerId:null,
+                    }
+                    this.projectBaseCostData = [];
+                    for (var m=0;m<this.baseCostItemList.length; m++) {
+                        this.projectBaseCostData.push({baseId: this.baseCostItemList[m].id, baseName:this.baseCostItemList[m].name, baseAmount:0});
                     }
                 } else {
                     this.title = "修改项目";
@@ -579,7 +751,6 @@
                     for(var j in list) {
                         arr.push(list[j].id)
                     }
-                    
                     this.addForm = {
                         id: item.id,
                         name: item.projectName,
@@ -595,13 +766,37 @@
                         baseFee: item.baseFee,
                         baseRisk1: item.baseRisk1,
                         baseRisk2: item.baseRisk2,
-                        baseOutsourcing: item.baseOutsourcing
+                        baseOutsourcing: item.baseOutsourcing,
+                        customerId:item.customerId==0?null:item.customerId,
                     }
                     this.changeParticipator();
+                    this.getProjectBaseData(item.id);
                 }
                 this.addFormVisible = true;
             },
 
+            getProjectBaseData(projectId) {
+                this.http.post('/project-basecost/get',{projectId: projectId},
+                        res => {
+                            if (res.code == "ok") {
+                               this.projectBaseCostData = res.data;
+                            } else {
+                                this.$message({
+                                    message: res.msg,
+                                    type: "error"
+                                });
+                            }
+                        },
+                        error => {
+                            this.listLoading = false;
+                            this.$message({
+                                message: error,
+                                type: "error"
+                            });
+                            }
+                        );
+            },
+
             //提交子项目创建修改请求
             submitInsertSubProject () {
                 this.$refs.form2.validate(valid => {
@@ -634,23 +829,28 @@
                 });
             },
             // 项目基线合计
-            addUpfun(je) {
-                var a = '0'
-                var q = '0'
-                var w = '0'
-                var e = '0'
-                var r = '0'
-                //  this.addForm.baseMan === undefined || this.addForm.baseMan === NaN ? this.addForm.baseMa = '0' : this.addForm.baseMan
-                if (this.addForm.baseMan == undefined || this.addForm.baseMan == NaN) {
-                    a = 0
-                } else {
-                    a = this.addForm.baseMan
+            addUpfun() {
+                var total = 0;
+                for (var i=0;i<this.projectBaseCostData.length; i++) {
+                    total += parseInt(this.projectBaseCostData[i].baseAmount);
                 }
-                if (this.addForm.baseFee !== undefined) q = this.addForm.baseFee
-                if (this.addForm.baseOutsourcing !== undefined) w = this.addForm.baseOutsourcing
-                if (this.addForm.baseRisk1 !== undefined) e = this.addForm.baseRisk1
-                if (this.addForm.baseRisk2 !== undefined) r = this.addForm.baseRisk2
-                this.addForm.budget = +a + +q + +w + +e + +r
+                this.addForm.budget = total;
+                // var a = '0'
+                // var q = '0'
+                // var w = '0'
+                // var e = '0'
+                // var r = '0'
+                // //  this.addForm.baseMan === undefined || this.addForm.baseMan === NaN ? this.addForm.baseMa = '0' : this.addForm.baseMan
+                // if (this.addForm.baseMan == undefined || this.addForm.baseMan == NaN) {
+                //     a = 0
+                // } else {
+                //     a = this.addForm.baseMan
+                // }
+                // if (this.addForm.baseFee !== undefined) q = this.addForm.baseFee
+                // if (this.addForm.baseOutsourcing !== undefined) w = this.addForm.baseOutsourcing
+                // if (this.addForm.baseRisk1 !== undefined) e = this.addForm.baseRisk1
+                // if (this.addForm.baseRisk2 !== undefined) r = this.addForm.baseRisk2
+                // this.addForm.budget = +a + +q + +w + +e + +r
             },
             submitInsert() {
                 this.$refs.form1.validate(valid => {
@@ -682,32 +882,19 @@
                             formData.append("level", this.addForm.level);
                         }
                         if(this.addForm.contractAmount != null) {
-                            formData.append("contractAmount", this.addForm.contractAmount)
-                        }
-                        if(this.addForm.baseMan != null) { // 人工成本
-                            formData.append("baseMan", this.addForm.baseMan)
+                            formData.append("contractAmount", this.addForm.contractAmount);
                         }
-                        if(this.addForm.baseFee != null) { // 费用
-                            formData.append("baseFee", this.addForm.baseFee)
+                        if (this.projectBaseCostData != null) {
+                            formData.append("projectBaseCostData", JSON.stringify(this.projectBaseCostData));
+                            //计算总预算成本
+                            formData.append("budget", this.addForm.budget);
                         }
-                        if(this.addForm.baseOutsourcing != null) { // 外包费用
-                            formData.append("baseOutsourcing", this.addForm.baseOutsourcing)
-                        }
-                        if(this.addForm.baseRisk1 != null) { // 预留风险金额1
-                            formData.append("baseRisk1", this.addForm.baseRisk1)
-                        }
-                        if(this.addForm.baseRisk2 != null) { //预留风险金额1
-                            formData.append("baseRisk2", this.addForm.baseRisk2)
-                        }
-                         if(this.addForm.budget != null) { //预留风险金额1
-                            formData.append("budget", this.addForm.budget)
+                        if (this.addForm.customerId == null) {
+                            formData.append("customerId", 0);
+                        } else {
+                            formData.append("customerId", this.addForm.customerId);
                         }
-                        // 合计
-                        // if(this.addUp != null) {
-                        //     this.addForm.budget = this.addUp
-                        //     formData.append("budget", this.addForm.budget);
-                        // }
-                        console.log(this.addForm.budget, 123, this.addUp);
+                        
                         this.http.uploadFile(this.port.project.add,formData,
                         res => {
                             this.addLoading = false;
@@ -790,6 +977,8 @@
         mounted() {
             this.getList();
             this.getUsers();
+            this.getCustomerList();
+            this.getProjectBaseConfigList();
         }
     };
 </script>

Diferenças do arquivo suprimidas por serem muito extensas
+ 1070 - 102
fhKeeper/formulahousekeeper/timesheet/src/views/project/projectInside.vue


+ 168 - 7
fhKeeper/formulahousekeeper/timesheet/src/views/workReport/daily.vue

@@ -70,8 +70,12 @@
                 <div class="allDaily" style="float:left;flex-grow:1">
                     <!--系统管理员和部门负责人 -->
                     <div class="report_title" v-if="user.role == 1 || user.role == 2 || user.manageDeptId > 0">
-                        <span>工作日报 | {{depData.label}}</span> - 已填写<span style="margin-left:5px;margin-right:5px;color:green;">{{reportList.length}}</span>人,
-                    未填写<span style="margin-left:5px;margin-right:5px;color:red;">{{(depData == null?data[0].membCount:(depData.isUser == 1?1:depData.membCount))-reportList.length}}</span>人
+                        <span>工作日报 | {{depData != null ?depData.label:""}}</span>
+                        <span v-if="targetUid == null">
+                         - 已填写
+                        <el-link :underline="false" @click="showMembList(1)"><span style="margin-left:5px;margin-right:5px;color:green;">{{reportList.length}}</span></el-link>人,
+                    未填写<el-link :underline="false" @click="showMembList(0)"><span style="margin-left:5px;margin-right:5px;color:red;">{{(depData == null?data[0].membCount:(depData.isUser == 1?1:depData.membCount))-reportList.length}}</span></el-link>人
+                        </span>
                         <span style="float:right;">
                             <el-link type="primary" style="margin-right:10px;" :underline="false" @click="fillInReport(-1,0)">填写日报</el-link>
                             <el-link type="primary" style="margin-right:10px;" :underline="false" @click="fillInReport(-1,1)">批量填报</el-link>
@@ -293,6 +297,24 @@
                 <el-button type="primary" @click="exportReport" style="width:100%;" >导出</el-button>
             </div>
         </el-dialog>
+        <!--人员列表 -->
+        <el-dialog  :title="(isFill?'已填':'未填')+'人员列表'" v-if="membListVisible" :visible.sync="membListVisible"  width="500px">
+            <el-table :show-header="false" :data="fillMembList" highlight-current-row :height="400" style="width: 100%;">
+            <el-table-column type="index" width="60">
+                <template slot-scope="scope" >
+                        {{scope.$index+1}}
+                    </template>
+            </el-table-column>
+            <el-table-column prop="label" label="姓名" ></el-table-column>
+            <el-table-column prop="deptName" label="部门" >
+            </el-table-column>
+
+            </el-table>
+            <div slot="footer" class="dialog-footer">
+                <el-button type="primary" @click="weixinNotify"  v-if="!isFill" :disabled="fillMembList == 0">微信催填</el-button>
+                <el-button type="default" @click="exportMemb"  :disabled="fillMembList == 0">导出</el-button>
+            </div>
+        </el-dialog>
     </section>
 </template>
 
@@ -302,6 +324,11 @@
     export default {
         data() {
             return {
+                isFill:false,
+                unFillList:[],
+                fillList:[],
+                fillMembList:[],
+                membListVisible: false,
                 isBatch:0,//是否是批量填报
                 weekDay : ["周日", "周一", "周二", "周三", "周四", "周五", "周六"],
                 statusStyle:["waiting", "filledReportStyle", "RejectStyle", ""],
@@ -385,6 +412,68 @@
             };
         },
         methods: {
+            //微信通知人员填写
+            weixinNotify() {
+                if (this.fillMembList.length == 0) return;
+                var ids = '';
+                this.fillMembList.forEach(f=>{
+                    ids += f.id+',';
+                })
+                this.http.post('/user/pushFillReport',{ 
+                        ids: ids, date: this.curDate
+                    },
+                    res => {
+                        if (res.code == "ok") {
+                            this.$message({
+                                message: '已发送成功',
+                                type: "success"
+                            });
+                        } 
+                    },
+                    error => {
+                        this.$message({
+                            message: error,
+                            type: "error"
+                        });
+                        }
+                    );
+            },
+            //导出人员列表
+            exportMemb() {
+                if (this.fillMembList.length == 0) return;
+                var ids = '';
+                this.fillMembList.forEach(f=>{
+                    ids += f.id+',';
+                })
+                this.http.post('/user/exportMembList',{ 
+                        ids: ids,isFill: this.isFill, date: this.curDate
+                    },
+                    res => {
+                        if (res.code == "ok") {
+                            var aTag = document.createElement('a');
+                            aTag.download = this.curDate+(this.isFill?"已填":"未填")+"人员列表.xls";
+                            aTag.href = res.data;
+                            aTag.click();
+                        } 
+                    },
+                    error => {
+                        this.$message({
+                            message: error,
+                            type: "error"
+                        });
+                        }
+                    );
+            },
+            showMembList(fill) {
+                this.membListVisible = true;
+                if (fill == 0) {
+                    this.fillMembList = this.unFillList;
+                    this.isFill = false;
+                } else {
+                    this.fillMembList = this.fillList;
+                    this.isFill = true;
+                }
+            },
             //获取自己填写的日报状态
             getReportFillStatus() {
                 this.http.post('/report/getReportFillStatus',{ 
@@ -693,23 +782,26 @@
             },
             // 部门列表点击
             handleNodeClick(data) {
-                // if(this.depData == null || data.id != this.depData.id) {
-                //     this.depData = data;
-                //     //this.getUser();
-                    
-                // }
                 this.depData = data;
+                var list = [];
                 if (data.id == -1) {
                     this.deptId = null;
                     this.targetUid = null;
+                    list = this.data;
                 } else if (data.isUser == 1) {
                     this.deptId = null;
                     this.targetUid = data.id;
                 } else {
                     this.deptId = data.id;
                     this.targetUid = null;
+                    list.push(data);
                 }
                 this.getReportList();
+                if (list.length > 0) {
+                    this.unFillList = this.getUserMembListFromDeptList(list, 0);
+                    this.fillList = this.getUserMembListFromDeptList(list, 1);
+                } 
+                
             },
             
             // 获取部门列表
@@ -739,7 +831,25 @@
                         list[0].membCount = this.membCount;
                         if (this.depData.id == -1) {
                             this.depData.membCount = this.membCount;
+                            this.unFillList = this.getUserMembListFromDeptList(this.data, 0);
+                            this.fillList = this.getUserMembListFromDeptList(this.data, 1);
+                        } else {
+                            if (this.depData.isUser == null) {
+                                var dep = this.findTargetDept(this.data, this.depData.id);
+                                var membDeptList = [];
+                                membDeptList.push(dep);
+                                this.unFillList = this.getUserMembListFromDeptList(membDeptList, 0);
+                                this.fillList = this.getUserMembListFromDeptList(membDeptList, 1);
+                            }
+                        }
+                        if (this.depData.isUser == null) {
+                            if (this.isFill) {
+                                this.fillMembList = this.fillList;
+                            } else {
+                                this.fillMembList = this.unFillList;
+                            }
                         }
+                        
                     } else {
                         this.$message({
                             message: res.msg,
@@ -757,6 +867,57 @@
                 this.getReportFillStatus();
             },
 
+            findTargetDept(list, deptId) {
+                var t = null;
+                for (var i=0;i<list.length; i++) {
+                    if (list[i].isUser == null && list[i].id == deptId) {
+                        t = list[i];
+                        break;
+                    }
+                }
+                if (t == null) {
+                    for (var i=0;i<list.length; i++) {
+                        if (list[i].children != null && list[i].children.length > 0) {
+                            t = this.findTargetDept(list[i].children, deptId);
+                            if (t != null) {
+                                break;
+                            }
+                        }
+                    }
+                }
+                return t;
+            },
+
+            getUserMembListFromDeptList(list, isFill) {
+                var membList = [];
+                for (var i in list) {
+                    var deptName = list[i].label;
+                    if (list[i].userList != null) {
+                        list[i].userList.forEach(element => {
+                            if (isFill == 0) {
+                                //获取未填的
+                                if (element.state == null) {
+                                    var obj = {id: element.id, label:element.name, deptId:element.departmentId, deptName: deptName};
+                                    membList.push(obj);
+                                }
+                            } else {
+                                if (element.state != null) {
+                                    var obj = {id: element.id, label:element.name, deptId:element.departmentId, deptName: deptName};
+                                    membList.push(obj);
+                                }
+                            }
+                            
+                        });
+                    }
+
+                    if (list[i].children != null) {
+                        membList = membList.concat(this.getUserMembListFromDeptList(list[i].children, isFill));
+                    }
+                }
+
+                return membList;
+            },
+
             setUserToDept(list) {
                 for (var i in list) {
                     var cnt = 0;

+ 234 - 0
fhKeeper/formulahousekeeper/timesheet/src/views/workflow/report.vue

@@ -0,0 +1,234 @@
+<template>
+    <section >
+        <el-col :span="24" class="toolbar" style="padding-bottom: 0px;">
+            <el-form :inline="true">
+                <el-form-item label="审批流程设置">
+                </el-form-item>
+                <el-form-item  style="float:right">
+                    <el-button  type="primary" @click="submitInsert" :loading="addLoading">保存</el-button>
+                </el-form-item>
+            </el-form>
+        </el-col>
+        <p style="padding-top:80px;margin: 0 0 10px 10px;color:#666;">工时审批流程</p>
+        <div class="panel" style="margin-left:20px;margin-right:20px;">
+          <el-button type="primary">员工填报</el-button>
+          <icon class="iconfont firerock-iconright" ></icon>
+          <el-button type="primary">项目负责人</el-button>
+          <icon class="iconfont firerock-iconright"></icon>
+          <icon class="iconfont firerock-iconInsertLine addNode" @click="showNodeDialog(0)"></icon>
+          <icon class="iconfont firerock-iconright"></icon>
+          <span v-for="(item, index) in dataArray" :key="item.roleId" >
+            <el-button type="primary" @click="editNodeDialog(index, item)">{{item.roleName}}<span v-if="item.userId != null">({{item.userName}})</span></el-button>
+            <icon class="iconfont firerock-iconright"></icon>
+            <icon class="iconfont firerock-iconInsertLine addNode" @click="showNodeDialog(index+1)"></icon>
+            <icon class="iconfont firerock-iconright"></icon>
+          </span>
+
+          <!--结束点 -->
+          <icon class="iconfont firerock-iconApp_New_Line" style="color:#20A0FF;"></icon>
+        </div>
+        <div style="width:80px;margin:0 auto;padding:20px;">
+            <el-button type="primary" @click="submitInsert" :loading="addLoading">保存</el-button>
+        </div>
+        <!--人员列表 -->
+        <el-dialog  title="请选择审批角色" v-if="dialogVisible" :visible.sync="dialogVisible"  width="400px">
+              <el-form label-width="80px">
+              <el-form-item label="角色" >
+                  <el-select style="width:100%;" v-model="curRoleId" >
+                    <el-option v-for="item in roleArray"  :label="item.label"  :value="item.value" :key="item.name">
+                        {{item.label}}
+                    </el-option>
+                  </el-select>
+              </el-form-item>
+              <el-form-item label="指定人员" v-if="curRoleId==4">
+                  <el-select style="width:100%;" v-model="curUserId" >
+                    <el-option v-for="item in userList"  :label="item.name"  :value="item.id" :key="item.id">
+                        {{item.name}}
+                    </el-option>
+                  </el-select>
+              </el-form-item>
+              </el-form>
+
+            <div slot="footer" class="dialog-footer">
+              <el-button type="default" @click="deleteNode" v-if="!isAdd" style="float:left;">删除</el-button>
+                <el-button type="primary" @click="addNode" >确定</el-button>
+            </div>
+        </el-dialog>
+    </section>
+</template>
+<script>
+    import util from "../../common/js/util";
+
+    export default {
+        data() {
+            return {
+                isAdd: false,
+                dataArray:[],
+                curRoleId:null,
+                curUserId: null,
+                index:0,
+                roleArray:[
+                {label:"项目管理员",value:5},
+                {label:"部门主管",value:6},
+                {label:"人事管理员",value:4},
+                ],
+                dialogVisible:false,
+                editNode:{},
+                user: JSON.parse(sessionStorage.getItem("user")),
+                userList:[],
+            };
+        },
+        methods: {
+            deleteNode() {
+              this.dialogVisible = false;
+              this.dataArray.splice(this.index, 1);
+            },
+            addNode() {
+              this.dialogVisible = false;
+              if (this.curRoleId == null) return;
+              var label = this.roleArray.filter(r=>r.value == this.curRoleId)[0].label;
+              if (this.isAdd) {
+                var node = {roleId: this.curRoleId, roleName: label};
+                if (this.curUserId != null) {
+                  node.userId = this.curUserId;
+                  node.userName = this.userList.filter(u=>u.id == node.userId)[0].name;
+                }
+                this.dataArray.splice(this.index, 0, node);
+              } else {
+                //编辑
+                this.dataArray[this.index].roleId = this.curRoleId;
+                this.dataArray[this.index].roleName = label;
+                this.dataArray[this.index].userId = this.curUserId;
+                let uid = this.curUserId;
+                console.log(uid);
+                if (uid != null) {
+                  this.dataArray[this.index].userName = this.userList.filter(u=>u.id == uid)[0].name;
+                } else {
+                  this.dataArray[this.index].userName = null;
+                }
+              }
+            },
+            editNodeDialog(index, item) {
+                this.isAdd = false;
+                this.index = index;
+                this.curUserId = item.userId;
+                this.dialogVisible = true;
+                this.curRoleId = item.roleId;
+            },
+            showNodeDialog(index) {
+              this.isAdd = true;
+              this.index = index;
+              this.curRoleId = null;
+              this.curUserId = null;
+              this.dialogVisible = true;
+            },
+            
+            getHRList() {
+              this.http.post('/user/getHRList',{},
+                            res => {
+                                this.listLoading = false;
+                                if (res.code == "ok") {
+                                    this.userList = res.data;
+                                } else {
+                                    this.$message({
+                                        message: res.msg,
+                                        type: "error"
+                                    });
+                                }
+                            },
+                            error => {
+                                this.listLoading = false;
+                                this.$message({
+                                    message: error,
+                                    type: "error"
+                                });
+                                }
+                            );
+            },
+            submitInsert() {
+                this.http.post('/audit-workflow-time-setting/add',{json:JSON.stringify(this.dataArray)},
+                            res => {
+                                this.listLoading = false;
+                                if (res.code == "ok") {
+                                    this.$message({
+                                        message: '保存成功',
+                                        type: "success"
+                                    });
+                                } else {
+                                    this.$message({
+                                        message: res.msg,
+                                        type: "error"
+                                    });
+                                }
+                            },
+                            error => {
+                                this.listLoading = false;
+                                this.$message({
+                                    message: error,
+                                    type: "error"
+                                });
+                                }
+                            );
+            },
+
+            // 获取本公司的工时日报审批流程设置
+            getSettings() {
+                this.http.post('/audit-workflow-time-setting/get',{},
+                    res => {
+                        this.listLoading = false;
+                        if (res.code == "ok") {
+                            this.dataArray = res.data;
+                        } else {
+                            this.$message({
+                                message: res.msg,
+                                type: "error"
+                            });
+                        }
+                    },
+                    error => {
+                        this.listLoading = false;
+                        this.$message({
+                            message: error,
+                            type: "error"
+                        });
+                        }
+                    );
+            },
+
+        },
+        created() {
+            let height = window.innerHeight;
+            this.tableHeight = height - 195;
+            const that = this;
+            window.onresize = function temp() {
+                that.tableHeight = window.innerHeight - 195;
+            };
+        },
+        mounted() {
+            this.getHRList();
+            this.getSettings();
+        }
+    };
+</script>
+
+<style lang="scss" scoped>
+.addNode {
+  cursor:pointer;
+}
+.addNode:hover {
+  color:#20a0ff;
+}
+
+.panel {
+    padding:50px 15px ;box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04);
+    
+}
+.sample {
+    margin-top:30px;
+    color: #999;
+}
+.tip {
+    margin-left:10px; color:gray;
+    
+}
+</style>

+ 22 - 0
fhKeeper/formulahousekeeper/timesheet_h5/public/index.html

@@ -12,6 +12,27 @@
 
     <meta name="wpk-bid" content="dta_2_71020"> <script>    !(function(c,i,e,b){var h=i.createElement("script");var f=i.getElementsByTagName("script")[0];h.type="text/javascript";h.crossorigin=true;h.onload=function(){c[b]||(c[b]=new c.wpkReporter({bid:"dta_2_71020"}));c[b].installAll()};f.parentNode.insertBefore(h,f);h.src=e})(window,document,"https://g.alicdn.com/woodpeckerx/jssdk??wpkReporter.js","__wpk");</script>
     <meta name="wpk-bid" content="dta_2_71020"> <script>    !(function(c,i,e,b){var h=i.createElement("script");var f=i.getElementsByTagName("script")[0];h.type="text/javascript";h.crossorigin=true;h.onload=function(){c[b]||(c[b]=new c.wpkReporter({bid:"dta_2_71020"}));c[b].installAll()};f.parentNode.insertBefore(h,f);h.src=e})(window,document,"https://g.alicdn.com/woodpeckerx/jssdk??wpkReporter.js","__wpk");</script>
+    <script>
+        function IsPC() {
+            var userAgentInfo = navigator.userAgent;
+            var Agents = ["Android", "iPhone",
+                        "SymbianOS", "Windows Phone",
+                        "iPad", "iPod"];
+            var flag = true;
+            for (var v = 0; v < Agents.length; v++) {
+                if (userAgentInfo.indexOf(Agents[v]) > 0) {
+                    flag = false;
+                    break;
+                }
+            }
+            return flag;
+        }
+        var flag = IsPC(); //true为PC端,false为手机端
+        if (flag) {
+            //跳转到PC登录页面
+            location.href = 'https://worktime.ttkuaiban.com';
+        }
+    </script>
 </head>
 
 <body>
@@ -19,6 +40,7 @@
         <strong>非常抱歉,网页丢了</strong>
     </noscript>
     <div id="app"></div>
+    
 </body>
 
 </html>