Explorar o código

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

Lljy-ai %!s(int64=4) %!d(string=hai) anos
pai
achega
9fb16a7c30
Modificáronse 36 ficheiros con 1598 adicións e 131 borrados
  1. 56 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/EarningSnapshotController.java
  2. 20 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ProjectController.java
  3. 17 5
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ReportController.java
  4. 15 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/TaskController.java
  5. 120 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/EarningSnapshot.java
  6. 44 7
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/Project.java
  7. 10 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/TimeTask.java
  8. 16 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/EarningSnapshotMapper.java
  9. 6 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/TaskMapper.java
  10. 16 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/EarningSnapshotService.java
  11. 8 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/ProjectService.java
  12. 5 2
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/ReportService.java
  13. 5 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/TaskService.java
  14. 20 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/EarningSnapshotServiceImpl.java
  15. 57 2
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ProjectServiceImpl.java
  16. 55 16
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ReportServiceImpl.java
  17. 214 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/TaskServiceImpl.java
  18. 28 0
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/EarningSnapshotMapper.xml
  19. 10 3
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/ProjectMapper.xml
  20. 3 3
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/ReportMapper.xml
  21. 44 0
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/TaskMapper.xml
  22. 26 3
      fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/demo_index.html
  23. 7 3
      fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.css
  24. 1 1
      fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.js
  25. 7 0
      fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.json
  26. BIN=BIN
      fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.ttf
  27. BIN=BIN
      fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.woff
  28. BIN=BIN
      fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.woff2
  29. 1 0
      fhKeeper/formulahousekeeper/timesheet/src/routes.js
  30. 2 2
      fhKeeper/formulahousekeeper/timesheet/src/views/project/cost.vue
  31. 362 0
      fhKeeper/formulahousekeeper/timesheet/src/views/project/earning.vue
  32. 103 19
      fhKeeper/formulahousekeeper/timesheet/src/views/project/info.vue
  33. 8 3
      fhKeeper/formulahousekeeper/timesheet/src/views/project/projectInside.vue
  34. 146 6
      fhKeeper/formulahousekeeper/timesheet/src/views/project/summary.vue
  35. 150 44
      fhKeeper/formulahousekeeper/timesheet/src/views/workReport/list.vue
  36. 16 11
      fhKeeper/formulahousekeeper/timesheet_h5/src/views/msg/index.vue

+ 56 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/EarningSnapshotController.java

@@ -0,0 +1,56 @@
+package com.management.platform.controller;
+
+
+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.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 org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * <p>
+ *  前端控制器
+ * </p>
+ *
+ * @author Seyason
+ * @since 2021-05-15
+ */
+@RestController
+@RequestMapping("/earning-snapshot")
+public class EarningSnapshotController {
+    @Resource
+    private HttpServletRequest request;
+
+    @Resource
+    private EarningSnapshotService earningSnapshotService;
+    @Resource
+    private UserMapper userMapper;
+    @Resource
+    private ProjectMapper projectMapper;
+
+    @RequestMapping("/list")
+    public HttpRespMsg list(Integer projectId) {
+        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())) {
+            msg.data = earningSnapshotService.list(new QueryWrapper<EarningSnapshot>().eq("project_id", projectId).orderByDesc("id"));
+        } else {
+            msg.setError("无权查看");
+        }
+
+        return msg;
+    }
+}
+

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

@@ -61,11 +61,30 @@ public class ProjectController {
                                    String planStartDate,
                                    String planEndDate,
                                    Integer level,
+                                   Integer contractAmount,
+                                   Integer baseMan,
+                                   Integer baseFee,
+                                   Integer baseOutsourcing,
+                                   Integer baseRisk1,
+                                   Integer baseRisk2,
                                    Integer budget
                                    ) {
-        return projectService.editProject(id, name, code, userId, inchargerId, planStartDate, planEndDate, level, budget,request);
+        return projectService.editProject(id, name, code, userId, inchargerId, planStartDate, planEndDate, level, contractAmount,
+                 baseMan,
+                 baseFee,
+                 baseOutsourcing,
+                 baseRisk1,
+                 baseRisk2,
+                 budget,request);
     }
 
+    @RequestMapping("/adjustBase")
+    public HttpRespMsg adjustBase(Project project
+    ) {
+        return projectService.adjustBase(project,request);
+    }
+
+
     /**
      * 更新项目进度
      * @param id

+ 17 - 5
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ReportController.java

@@ -161,18 +161,25 @@ public class ReportController {
      * state 筛选状态 0-未审核 1-已通过 2-未通过
      */
     @RequestMapping("/listByState")
-    public HttpRespMsg getListByState(@RequestParam Integer state, HttpServletRequest request) {
-        return reportService.getListByState(state, request);
+    public HttpRespMsg getListByState(@RequestParam Integer state,
+                                      Integer departmentId,
+                                      Integer projectId,
+                                      String date,
+                                      HttpServletRequest request) {
+        System.out.println("departmentId========="+departmentId);
+        return reportService.getListByState(state, departmentId,
+                projectId,
+                date,request);
     }
 
     /**
      * 按某人某日期审批通过报告
      * id 要通过的报告的用户id
-     * date 日期 格式yyyy-mm-dd
+     * reportIds 报告id
      */
     @RequestMapping("/approve")
-    public HttpRespMsg approveReport(@RequestParam String id, @RequestParam String date, @RequestParam String reportIds,HttpServletRequest request) {
-        return reportService.approveReport(id, date,reportIds, request);
+    public HttpRespMsg approveReport(@RequestParam String id, @RequestParam String reportIds,HttpServletRequest request) {
+        return reportService.approveReport(id, reportIds, request);
     }
 
     /**
@@ -227,5 +234,10 @@ public class ReportController {
     public HttpRespMsg batchApproveReport(@RequestParam String ids, HttpServletRequest request) {
         return reportService.batchApproveReport(ids, request);
     }
+
+    @RequestMapping("/batchDenyReport")
+    public HttpRespMsg batchDenyReport(@RequestParam String ids, HttpServletRequest request) {
+        return reportService.batchDenyReport(ids, request);
+    }
 }
 

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

@@ -480,5 +480,20 @@ public class TaskController {
             });
         }
     }
+
+    @RequestMapping("/getTaskTimeCompare")
+    public HttpRespMsg getTaskTimeCompare(Integer projectId) {
+        return taskService.getTaskTimeCompare(projectId);
+    }
+
+    @RequestMapping("/exportTaskTimeCompare")
+    public HttpRespMsg exportTaskTimeCompare(Integer projectId) {
+        return taskService.exportTaskTimeCompare(projectId);
+    }
+
+    @RequestMapping("exportTask")
+    public HttpRespMsg exportTask(Integer projectId) {
+        return taskService.exportTask(projectId);
+    }
 }
 

+ 120 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/EarningSnapshot.java

@@ -0,0 +1,120 @@
+package com.management.platform.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+import com.baomidou.mybatisplus.annotation.TableField;
+import java.io.Serializable;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.springframework.format.annotation.DateTimeFormat;
+
+/**
+ * <p>
+ * 
+ * </p>
+ *
+ * @author Seyason
+ * @since 2021-05-15
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class EarningSnapshot extends Model<EarningSnapshot> {
+
+    private static final long serialVersionUID=1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 项目id
+     */
+    @TableField("project_id")
+    private Integer projectId;
+
+    /**
+     * 发生时间
+     */
+    @TableField("indate")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private LocalDateTime indate;
+
+    /**
+     * 变更人id
+     */
+    @TableField("creator_id")
+    private String creatorId;
+
+    /**
+     * 变更人姓名
+     */
+    @TableField("creator_name")
+    private String creatorName;
+
+    /**
+     * 项目金额
+     */
+    @TableField("contract_amount")
+    private Integer contractAmount;
+
+    /**
+     * 人员成本
+     */
+    @TableField("base_man")
+    private Integer baseMan;
+
+    /**
+     * 费用
+     */
+    @TableField("base_fee")
+    private Integer baseFee;
+
+    /**
+     * 外包费用
+     */
+    @TableField("base_outsourcing")
+    private Integer baseOutsourcing;
+
+    /**
+     * 风险预留金额1
+     */
+    @TableField("base_risk1")
+    private Integer baseRisk1;
+
+    /**
+     * 风险预留金额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;
+
+
+    @Override
+    protected Serializable pkVal() {
+        return this.id;
+    }
+
+}

+ 44 - 7
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/Project.java

@@ -19,7 +19,7 @@ import lombok.experimental.Accessors;
  * </p>
  *
  * @author Seyason
- * @since 2021-04-30
+ * @since 2021-05-15
  */
 @Data
 @EqualsAndHashCode(callSuper = false)
@@ -94,12 +94,6 @@ public class Project extends Model<Project> {
     @TableField("finish_date")
     private LocalDate finishDate;
 
-    /**
-     * 预算:单位元
-     */
-    @TableField("budget")
-    private Integer budget;
-
     /**
      * 创建人id
      */
@@ -118,12 +112,55 @@ public class Project extends Model<Project> {
     @TableField("create_date")
     private LocalDate createDate;
 
+    /**
+     * 项目金额:单位元
+     */
+    @TableField("contract_amount")
+    private Integer contractAmount;
+
+    /**
+     * 基线总成本:单位元
+     */
+    @TableField("budget")
+    private Integer budget;
+
+    /**
+     * 人员成本:单位元
+     */
+    @TableField("base_man")
+    private Integer baseMan;
+
+    /**
+     * 外包费用
+     */
+    @TableField("base_outsourcing")
+    private Integer baseOutsourcing;
+
+    /**
+     * 风险预留资金1
+     */
+    @TableField("base_risk1")
+    private Integer baseRisk1;
+
+    /**
+     * 风险预留资金1
+     */
+    @TableField("base_risk2")
+    private Integer baseRisk2;
+
+    /**
+     * 基线费用
+     */
+    @TableField("base_fee")
+    private Integer baseFee;
+
 
     @TableField(exist = false)
     private String inchargerName;
 
     @TableField(exist = false)
     private List<Map<String, Object>> participationList;
+
     @Override
     protected Serializable pkVal() {
         return this.id;

+ 10 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/TimeTask.java

@@ -0,0 +1,10 @@
+package com.management.platform.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import lombok.Data;
+
+@Data
+public class TimeTask extends Task {
+    @TableField(exist = false)
+    private double workHours;
+}

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

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

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

@@ -4,10 +4,12 @@ import com.baomidou.mybatisplus.core.conditions.Wrapper;
 import com.baomidou.mybatisplus.core.toolkit.Constants;
 import com.management.platform.entity.Task;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.management.platform.entity.TimeTask;
 import org.apache.ibatis.annotations.Param;
 import org.apache.poi.ss.formula.functions.T;
 
 import java.util.List;
+import java.util.Map;
 
 /**
  * <p>
@@ -23,4 +25,8 @@ public interface TaskMapper extends BaseMapper<Task> {
     List getTopCostTask(Integer projectId);
 
     List<Task> simpleList(@Param(Constants.WRAPPER) Wrapper wrapper);
+
+    List getTaskTimeCompare(Integer projectId);
+
+    List<TimeTask> getTaskWithWorktime(Integer projectId);
 }

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

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

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

@@ -24,6 +24,12 @@ public interface ProjectService extends IService<Project> {
                             String planStartDate,
                             String planEndDate,
                             Integer level,
+                            Integer contractAmount,
+                            Integer baseMan,
+                            Integer baseFee,
+                            Integer baseOutsourcing,
+                            Integer baseRisk1,
+                            Integer baseRisk2,
                             Integer budget,
                             HttpServletRequest request);
 
@@ -46,4 +52,6 @@ public interface ProjectService extends IService<Project> {
     HttpRespMsg restartProject(Integer id);
 
     HttpRespMsg addMemb(Integer id, String[] userId);
+
+    HttpRespMsg adjustBase(Project project, HttpServletRequest request);
 }

+ 5 - 2
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/ReportService.java

@@ -27,9 +27,11 @@ public interface ReportService extends IService<Report> {
 
     HttpRespMsg deleteReport(String userId, String date);
 
-    HttpRespMsg getListByState(Integer state, HttpServletRequest request);
+    HttpRespMsg getListByState(Integer state, Integer departmentId,
+                               Integer projectId,
+                               String date,HttpServletRequest request);
 
-    HttpRespMsg approveReport(String id, String date, String reportIds, HttpServletRequest request);
+    HttpRespMsg approveReport(String id, String reportIds, HttpServletRequest request);
 
     HttpRespMsg denyReport(String id, String date, String reportIds,HttpServletRequest request);
 
@@ -40,6 +42,7 @@ public interface ReportService extends IService<Report> {
     HttpRespMsg getMembList(String date, Integer manageDeptId, HttpServletRequest request);
 
     HttpRespMsg batchApproveReport(String ids, HttpServletRequest request);
+    HttpRespMsg batchDenyReport(String ids, HttpServletRequest request);
 
     HttpRespMsg cancelReport(String userId, String reportIds, HttpServletRequest request);
 }

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

@@ -26,4 +26,9 @@ public interface TaskService extends IService<Task> {
 
     //获取不带任务描述的列表数据
     List<Task> simpleList(Wrapper<Task> queryWrapper);
+
+    HttpRespMsg getTaskTimeCompare(Integer projectId);
+    HttpRespMsg exportTaskTimeCompare(Integer projectId);
+
+    HttpRespMsg exportTask(Integer projectId);
 }

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

@@ -0,0 +1,20 @@
+package com.management.platform.service.impl;
+
+import com.management.platform.entity.EarningSnapshot;
+import com.management.platform.mapper.EarningSnapshotMapper;
+import com.management.platform.service.EarningSnapshotService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ *  服务实现类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2021-05-15
+ */
+@Service
+public class EarningSnapshotServiceImpl extends ServiceImpl<EarningSnapshotMapper, EarningSnapshot> implements EarningSnapshotService {
+
+}

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

@@ -16,6 +16,7 @@ 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 org.springframework.util.StringUtils;
 
 import javax.annotation.Resource;
@@ -40,6 +41,7 @@ import java.util.stream.Collectors;
  * @since 2020-01-03
  */
 @Service
+@Transactional
 public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> implements ProjectService {
     @Resource
     private ProjectMapper projectMapper;
@@ -54,6 +56,8 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
     @Resource
     private TaskMapper taskMapper;
     @Resource
+    private EarningSnapshotMapper earningSnapshotMapper;
+    @Resource
     private TimeTypeMapper timeTypeMapper;
     @Resource
     private HttpServletResponse response;
@@ -149,6 +153,12 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                                    String planStartDate,
                                    String planEndDate,
                                    Integer level,
+                                   Integer contractAmount,
+                                   Integer baseMan,
+                                   Integer baseFee,
+                                   Integer baseOutsourcing,
+                                   Integer baseRisk1,
+                                   Integer baseRisk2,
                                    Integer budget,
                                    HttpServletRequest request) {
         HttpRespMsg httpRespMsg = new HttpRespMsg();
@@ -170,7 +180,13 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                                 .setCreatorId(user.getId())
                                 .setCreatorName(user.getName())
                                 .setCreateDate(LocalDate.now())
-                                .setBudget(budget);
+                                .setContractAmount(contractAmount)
+                                .setBudget(budget)
+                                .setBaseFee(baseFee)
+                                .setBaseMan(baseMan)
+                                .setBaseOutsourcing(baseOutsourcing)
+                                .setBaseRisk1(baseRisk1)
+                                .setBaseRisk2(baseRisk2);
                         if (!StringUtils.isEmpty(planStartDate)) {
                             project.setPlanStartDate(LocalDate.parse(planStartDate));
                         }
@@ -197,7 +213,13 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                     Project p = new Project();
                     p.setProjectName(name).setId(id).setCompanyId(companyId).setProjectCode(code).setInchargerId(inchargerId)
                             .setLevel(level)
-                            .setBudget(budget);
+                            .setContractAmount(contractAmount)
+                            .setBudget(budget)
+                            .setBaseFee(baseFee)
+                            .setBaseMan(baseMan)
+                            .setBaseOutsourcing(baseOutsourcing)
+                            .setBaseRisk1(baseRisk1)
+                            .setBaseRisk2(baseRisk2);;
                     if (!StringUtils.isEmpty(planStartDate)) {
                         p.setPlanStartDate(LocalDate.parse(planStartDate));
                     }
@@ -451,6 +473,39 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
         return new HttpRespMsg();
     }
 
+    @Override
+    public HttpRespMsg adjustBase(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());
+        projectMapper.updateById(project);
+        //增加基线快照
+        User user = userMapper.selectById(request.getHeader("Token"));
+        EarningSnapshot record = new EarningSnapshot();
+        record.setProjectId(project.getId());
+        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());
+        earningSnapshotMapper.insert(record);
+
+        return new HttpRespMsg();
+    }
+
     //获取某个项目每个人分别需要的工时
     @Override
     public HttpRespMsg getProjectCost(String startDate, String endDate, Integer projectId, HttpServletRequest request) {

+ 55 - 16
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ReportServiceImpl.java

@@ -12,6 +12,7 @@ import com.management.platform.util.ListUtil;
 import org.apache.poi.hssf.usermodel.*;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
 
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
@@ -392,9 +393,12 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
 
     //按状态获取报告列表
     @Override
-    public HttpRespMsg getListByState(Integer state, HttpServletRequest request) {
+    public HttpRespMsg getListByState(Integer state, Integer departmentId,
+                                      Integer projectId,
+                                      String date,HttpServletRequest request) {
         HttpRespMsg httpRespMsg = new HttpRespMsg();
         try {
+            SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
             User curUser = userMapper.selectById(request.getHeader("Token"));
             Integer companyId = curUser.getCompanyId();
             String leaderId = null;
@@ -403,9 +407,22 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
             }
             //根据权限,管理员查看全部人员的,各个项目负责人只看自己负责的项目参与人员的日报
             List<Map<String, Object>> nameList = reportMapper.getDetailByState(state, companyId, leaderId);
+            //按部门过滤
+            if (departmentId != null) {
+                nameList = nameList.stream().filter(map->((Long)map.get("departmentId")) == departmentId.longValue()).collect(Collectors.toList());
+            }
+            //按日期过滤
+            if (!StringUtils.isEmpty(date)) {
+                nameList = nameList.stream().filter(map->{
+                    System.out.println("已有数据日期=="+sdf.format((java.sql.Date)map.get("date"))+", 参数date="+date);
+                    return (sdf.format((java.sql.Date)map.get("date"))).equals(date);
+                }).collect(Collectors.toList());
+            }
+
             List<User> userList = userMapper.selectList(new QueryWrapper<User>().eq("company_id", companyId));
 
-            for (Map<String, Object> map2 : nameList) {
+            for (int index=0;index<nameList.size(); index++) {
+                Map<String, Object> map2 = nameList.get(index);
                 java.sql.Date createDate = (java.sql.Date)map2.get("date");
                 List<Map<String, Object>> list2 = null;
                 if (leaderId == null) {
@@ -417,19 +434,28 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                     list2 =
                             inchargeReportList.stream().filter(i->i.get("creatorId").equals(map2.get("id"))).collect(Collectors.toList());
                 }
-
-                map2.put("data", list2);
-                double reportTime = 0;
-                BigDecimal total = new BigDecimal(0);
-                for (Map<String, Object> m : list2) {
-                    double t = (double) m.get("time");
-                    reportTime += t;
-                    total = total.add((BigDecimal)m.get("cost"));
+                //按项目过滤
+                if (projectId != null) {
+                    list2 = list2.stream().filter(report->(((Integer)report.get("projectId")).equals(projectId))).collect(Collectors.toList());
+                }
+                if (list2.size() == 0) {
+                    //被项目过滤掉了,没有数据。
+                    nameList.remove(index);
+                    index--;
+                } else {
+                    map2.put("data", list2);
+                    double reportTime = 0;
+                    BigDecimal total = new BigDecimal(0);
+                    for (Map<String, Object> m : list2) {
+                        double t = (double) m.get("time");
+                        reportTime += t;
+                        total = total.add((BigDecimal)m.get("cost"));
+                    }
+                    DecimalFormat df = new DecimalFormat("0.00");
+                    map2.put("reportTime", df.format(reportTime));
+                    map2.put("cost", total);
+                    map2.put("state", list2.get(0).get("state"));
                 }
-                DecimalFormat df = new DecimalFormat("0.00");
-                map2.put("reportTime", df.format(reportTime));
-                map2.put("cost", total);
-                map2.put("state", list2.get(0).get("state"));
             }
 //            for (Map<String, Object> map : nameList) {
 //                //再根据人分别获取当天的报告
@@ -462,7 +488,7 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
 
     //审核通过某天某人的某报告
     @Override
-    public HttpRespMsg approveReport(String id, String date, String reportIds, HttpServletRequest request) {
+    public HttpRespMsg approveReport(String id, String reportIds, HttpServletRequest request) {
         HttpRespMsg httpRespMsg = new HttpRespMsg();
         try {
             User user = userMapper.selectById(request.getHeader("Token"));
@@ -597,6 +623,19 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
         return msg;
     }
 
+
+    @Override
+    public HttpRespMsg batchDenyReport(String ids, HttpServletRequest request) {
+        Report report = new Report();
+        report.setState(2);
+        int num = reportMapper.update(report, new QueryWrapper<Report>().in("id", ListUtil.convertIdsArrayToList(ids)));
+        HttpRespMsg msg = new HttpRespMsg();
+        if (num <= 0) {
+            msg.setError("无数据更新");
+        }
+        return msg;
+    }
+
     @Override
     public HttpRespMsg cancelReport(String userId, String reportIds, HttpServletRequest request) {
         HttpRespMsg msg = new HttpRespMsg();
@@ -705,7 +744,7 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                 rowNum++;
             }
             //生成Excel文件
-            String fileUrlSuffix = date + "日报" + new SimpleDateFormat("hh-mm-ss").format(new Date()) + ".xls";
+            String fileUrlSuffix = date + "日报" + System.currentTimeMillis() + ".xls";
             FileOutputStream fos = new FileOutputStream(path + fileUrlSuffix);
             workbook.write(fos);
             fos.flush();

+ 214 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/TaskServiceImpl.java

@@ -1,16 +1,31 @@
 package com.management.platform.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.management.platform.entity.Project;
 import com.management.platform.entity.Task;
+import com.management.platform.entity.TimeTask;
+import com.management.platform.entity.User;
+import com.management.platform.mapper.ProjectMapper;
 import com.management.platform.mapper.TaskMapper;
 import com.management.platform.service.TaskService;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.management.platform.util.ExcelUtil;
 import com.management.platform.util.HttpRespMsg;
+import org.apache.poi.hssf.usermodel.*;
 import org.apache.poi.ss.formula.functions.T;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.sql.Timestamp;
+import java.text.SimpleDateFormat;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.Date;
 import java.util.List;
+import java.util.Map;
 
 /**
  * <p>
@@ -22,8 +37,12 @@ import java.util.List;
  */
 @Service
 public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements TaskService {
+    @Value(value = "${upload.path}")
+    private String path;
     @Resource
     private TaskMapper taskMapper;
+    @Resource
+    private ProjectMapper projectMapper;
     @Override
     public HttpRespMsg getExecutorPanel(Integer projectId) {
         HttpRespMsg msg = new HttpRespMsg();
@@ -49,4 +68,199 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
     public List<Task> simpleList(Wrapper<Task> queryWrapper) {
         return taskMapper.simpleList(queryWrapper);
     }
+
+    @Override
+    public HttpRespMsg getTaskTimeCompare(Integer projectId) {
+        HttpRespMsg msg = new HttpRespMsg();
+        msg.data = taskMapper.getTaskTimeCompare(projectId);
+        return msg;
+    }
+
+    @Override
+    public HttpRespMsg exportTaskTimeCompare(Integer projectId) {
+        HttpRespMsg httpRespMsg = new HttpRespMsg();
+        List<Map> list= taskMapper.getTaskTimeCompare(projectId);
+        Project project = projectMapper.selectById(projectId);
+        try {
+            //准备导出
+            HSSFWorkbook workbook = new HSSFWorkbook();
+            HSSFSheet sheet = workbook.createSheet("实际工时VS计划工时");
+            //创建表头
+            HSSFRow headRow = sheet.createRow(0);
+            //设置列宽 setColumnWidth的第二个参数要乘以256 这个参数的单位是1/256个字符宽度
+            sheet.setColumnWidth(0, 5 * 256);
+            sheet.setColumnWidth(1, 50 * 256);
+            sheet.setColumnWidth(2, 20 * 256);
+            sheet.setColumnWidth(3, 20 * 256);
+            sheet.setColumnWidth(4, 10 * 256);
+            //设置为居中加粗
+            HSSFCellStyle headStyle = workbook.createCellStyle();
+            HSSFFont font = workbook.createFont();
+            font.setBold(true);
+            headStyle.setFont(font);
+            HSSFFont redFont = workbook.createFont();
+            redFont.setColor(HSSFFont.COLOR_RED);
+            HSSFCellStyle redStyle = workbook.createCellStyle();
+            redStyle.setFont(redFont);
+            //表头
+            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("实际工时(h)");
+            headCell.setCellStyle(headStyle);
+            headCell = headRow.createCell(3);
+            headCell.setCellValue("计划工时(h)");
+            headCell.setCellStyle(headStyle);
+            headCell = headRow.createCell(4);
+            headCell.setCellValue("偏差");
+            headCell.setCellStyle(headStyle);
+            int rowNum = 1;
+            for (Map<String, Object> map : list) {
+                HSSFRow row = sheet.createRow(rowNum);
+                row.createCell(0).setCellValue(rowNum);
+                row.createCell(1).setCellValue((String) map.get("name"));
+                row.createCell(2).setCellValue((Double) map.get("workHours"));
+                row.createCell(3).setCellValue((Integer) map.get("planHours"));
+                HSSFCell percentCell = row.createCell(4);
+                if ((Integer) map.get("planHours") != null) {
+                    double percent = (Double) map.get("workHours")*100/(Integer) map.get("planHours");
+                    percent = (percent - 100);
+                    String sign = "";
+                    if (percent > 0) {
+                        percentCell.setCellStyle(redStyle);
+                        sign = "+";
+                    } else if (percent < 0) {
+                        sign = "-";
+                    }
+                    percentCell.setCellValue(sign+percent+"%");
+                } else {
+                    percentCell.setCellValue(" ");
+                }
+                rowNum++;
+            }
+            //生成Excel文件
+            String fileUrlSuffix = project.getProjectName()+"工时对比" + 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 exportTask(Integer projectId) {
+        HttpRespMsg httpRespMsg = new HttpRespMsg();
+        List<TimeTask> list= taskMapper.getTaskWithWorktime(projectId);
+        Project project = projectMapper.selectById(projectId);
+        try {
+            DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+            //准备导出
+            HSSFWorkbook workbook = new HSSFWorkbook();
+            HSSFSheet sheet = workbook.createSheet("任务数据");
+            //创建表头
+            HSSFRow headRow = sheet.createRow(0);
+            //设置列宽 setColumnWidth的第二个参数要乘以256 这个参数的单位是1/256个字符宽度
+            sheet.setColumnWidth(0, 50 * 256);
+            sheet.setColumnWidth(1, 20 * 256);
+            sheet.setColumnWidth(2, 20 * 256);
+            sheet.setColumnWidth(3, 20 * 256);
+            sheet.setColumnWidth(4, 20 * 256);
+            sheet.setColumnWidth(5, 20 * 256);
+            sheet.setColumnWidth(6, 20 * 256);
+            sheet.setColumnWidth(7, 20 * 256);
+            sheet.setColumnWidth(8, 20 * 256);
+            sheet.setColumnWidth(9, 20 * 256);
+            sheet.setColumnWidth(10, 20 * 256);
+            //设置为居中加粗
+            HSSFCellStyle headStyle = workbook.createCellStyle();
+            HSSFFont font = workbook.createFont();
+            font.setBold(true);
+            headStyle.setFont(font);
+            HSSFFont redFont = workbook.createFont();
+            redFont.setColor(HSSFFont.COLOR_RED);
+            HSSFCellStyle redStyle = workbook.createCellStyle();
+            redStyle.setFont(redFont);
+            //表头
+            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);
+            headCell = headRow.createCell(3);
+            headCell.setCellValue("创建时间");
+            headCell.setCellStyle(headStyle);
+            headCell = headRow.createCell(4);
+            headCell.setCellValue("截止时间");
+            headCell.setCellStyle(headStyle);
+            headCell = headRow.createCell(5);
+            headCell.setCellValue("完成时间");
+            headCell.setCellStyle(headStyle);
+            headCell = headRow.createCell(6);
+            headCell.setCellValue("是否完成");
+            headCell.setCellStyle(headStyle);
+            headCell = headRow.createCell(7);
+            headCell.setCellValue("是否逾期");
+            headCell.setCellStyle(headStyle);
+            headCell = headRow.createCell(8);
+            headCell.setCellValue("计划工时");
+            headCell.setCellStyle(headStyle);
+            headCell = headRow.createCell(10);
+            headCell.setCellValue("实际工时");
+            headCell.setCellStyle(headStyle);
+            int rowNum = 1;
+            for (TimeTask task : list) {
+                HSSFRow row = sheet.createRow(rowNum);
+                row.createCell(0).setCellValue(task.getName());
+                row.createCell(1).setCellValue(project.getProjectName());
+                row.createCell(2).setCellValue(task.getExecutorName());
+                row.createCell(3).setCellValue(dateTimeFormatter.format(task.getCreateDate()));
+                row.createCell(4).setCellValue(dateTimeFormatter.format(task.getEndDate()));
+                row.createCell(5).setCellValue(dateTimeFormatter.format(task.getFinishDate()));
+                row.createCell(6).setCellValue(task.getTaskStatus() == 1?"Y":"N");
+                boolean isExpired = false;
+                if (task.getTaskStatus() == 0 && !task.getEndDate().isAfter(LocalDate.now())) {
+                    isExpired = true;
+                }
+                row.createCell(7).setCellValue(isExpired?"Y":"N");
+                row.createCell(8).setCellValue(task.getPlanHours());
+                row.createCell(9).setCellValue(task.getWorkHours());
+                rowNum++;
+            }
+            //生成Excel文件
+            String fileUrlSuffix = "【"+project.getProjectName()+"】任务数据" + 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;
+    }
 }

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

@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.management.platform.mapper.EarningSnapshotMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.management.platform.entity.EarningSnapshot">
+        <id column="id" property="id" />
+        <result column="project_id" property="projectId" />
+        <result column="indate" property="indate" />
+        <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" />
+    </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
+    </sql>
+
+</mapper>

+ 10 - 3
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/ProjectMapper.xml

@@ -15,15 +15,21 @@
         <result column="level" property="level" />
         <result column="status" property="status" />
         <result column="finish_date" property="finishDate" />
-        <result column="budget" property="budget" />
         <result column="creator_id" property="creatorId" />
         <result column="creator_name" property="creatorName" />
         <result column="create_date" property="createDate" />
+        <result column="contract_amount" property="contractAmount" />
+        <result column="budget" property="budget" />
+        <result column="base_man" property="baseMan" />
+        <result column="base_outsourcing" property="baseOutsourcing" />
+        <result column="base_risk1" property="baseRisk1" />
+        <result column="base_risk2" property="baseRisk2" />
+        <result column="base_fee" property="baseFee" />
     </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, budget, creator_id, creator_name, create_date
+        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
     </sql>
 
 
@@ -35,7 +41,8 @@
             SELECT project_id
             FROM participation
             WHERE user_id = #{userId}
-        )
+        ) or incharger_id = #{userId}
+        or creator_id = #{userId}
         ORDER BY id DESC
     </select>
 

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

@@ -51,7 +51,7 @@
 
     <!--根据员工id,日期获取当天全部报告信息-->
     <select id="getReportByDate" resultType="java.util.Map">
-        SELECT a.id, b.project_name AS project, a.working_time AS time, a.content, a.state, a.time_type as timeType, a.cost, a.report_time_type as reportTimeType, a.start_time as startTime,
+        SELECT a.id, a.project_id as projectId,b.project_name AS project, a.working_time AS time, a.content, a.state, a.time_type as timeType, a.cost, a.report_time_type as reportTimeType, a.start_time as startTime,
         a.end_time as endTime, b.incharger_id as inchargerId,
         a.creator_id as creatorId, d.name as subProjectName,a.task_id as taskId, task.name as taskName, a.is_overtime as isOvertime
         FROM report AS a
@@ -68,7 +68,7 @@
 
     <!--根据项目经理id,日期获取相关项目的全部报告信息-->
     <select id="getInchargeReportByDate" resultType="java.util.Map">
-        SELECT a.id, b.project_name AS project, a.working_time AS time, a.content, a.state, a.time_type as timeType,
+        SELECT a.id, a.project_id as projectId, b.project_name AS project, a.working_time AS time, a.content, a.state, a.time_type as timeType,
         a.cost, a.report_time_type as reportTimeType, a.start_time as startTime,
         a.end_time as endTime, b.incharger_id as inchargerId,
         a.creator_id as creatorId, d.name as subProjectName,a.task_id as taskId, task.name as taskName, a.is_overtime as isOvertime
@@ -148,7 +148,7 @@
 
     <!--报告列表-->
     <select id="getDetailByState" resultType="java.util.Map">
-        SELECT DISTINCT b.id, b.name, a.create_date AS date
+        SELECT DISTINCT b.id, b.name, cast(b.department_id as SIGNED) as departmentId,a.create_date AS date
         FROM report AS a
         JOIN user AS b ON a.creator_id=b.id
         WHERE a.state = #{state} AND b.company_id=#{companyId}

+ 44 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/TaskMapper.xml

@@ -30,6 +30,34 @@
         <result column="finish_date" property="finishDate" />
     </resultMap>
 
+    <resultMap id="timeResultMap" type="com.management.platform.entity.TimeTask" >
+        <id column="id" property="id" />
+        <result column="name" property="name" />
+        <result column="task_desc" property="taskDesc" />
+        <result column="creater_id" property="createrId" />
+        <result column="creater_name" property="createrName" />
+        <result column="creator_color" property="creatorColor" />
+        <result column="executor_id" property="executorId" />
+        <result column="executor_name" property="executorName" />
+        <result column="executor_color" property="executorColor" />
+        <result column="task_level" property="taskLevel" />
+        <result column="task_status" property="taskStatus" />
+        <result column="create_date" property="createDate" />
+        <result column="end_date" property="endDate" />
+        <result column="project_id" property="projectId" />
+        <result column="stages_id" property="stagesId" />
+        <result column="company_id" property="companyId" />
+        <result column="indate" property="indate" />
+        <result column="parent_tid" property="parentTid" />
+        <result column="group_id" property="groupId" />
+        <result column="seq" property="seq" />
+        <result column="plan_hours" property="planHours" />
+        <result column="task_type" property="taskType" />
+        <result column="parent_tname" property="parentTname" />
+        <result column="finish_date" property="finishDate" />
+        <result column="work_hours" property="workHours" />
+    </resultMap>
+
     <!-- 通用查询结果列 -->
     <sql id="Base_Column_List">
         id, name, task_desc, creater_id, creater_name, creator_color, executor_id, executor_name, executor_color, task_level, task_status, create_date, end_date, project_id, stages_id, company_id, indate, parent_tid, group_id, seq, plan_hours, task_type, parent_tname, finish_date
@@ -64,4 +92,20 @@
         WHERE task.project_id = #{projectId} and report.state = 1
         GROUP BY task.id ORDER BY SUM(report.`working_time`) DESC LIMIT 10
     </select>
+
+    <!-- 查询任务实际工时和计划工时对比,仅查询有实际工时的数据 -->
+    <select id="getTaskTimeCompare" resultType="java.util.Map">
+        SELECT task.id , task.name AS name, task.plan_hours as planHours, IFNULL(SUM(report.`working_time`),0) AS workHours FROM report
+        LEFT JOIN task ON report.`task_id` = task.id
+        WHERE task.project_id = #{projectId} AND report.state = 1
+        GROUP BY task.id ORDER BY SUM(report.`working_time`) DESC
+    </select>
+
+    <!--查询任务,带实际工时-->
+    <select id="getTaskWithWorktime" resultMap="timeResultMap">
+        SELECT task.* , IFNULL(SUM(report.`working_time`),0) AS work_hours FROM task
+        LEFT JOIN report ON report.`task_id` = task.id
+        WHERE task.project_id = #{projectId} and report.state = 1
+        GROUP BY task.id ORDER BY SUM(report.`working_time`) DESC LIMIT 10
+    </select>
 </mapper>

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

@@ -54,6 +54,12 @@
       <div class="content unicode" style="display: block;">
           <ul class="icon_lists dib-box">
           
+            <li class="dib">
+              <span class="icon iconfont">&#xe72d;</span>
+                <div class="name">export</div>
+                <div class="code-name">&amp;#xe72d;</div>
+              </li>
+          
             <li class="dib">
               <span class="icon iconfont">&#xe63c;</span>
                 <div class="name">启动</div>
@@ -234,9 +240,9 @@
 <pre><code class="language-css"
 >@font-face {
   font-family: 'iconfont';
-  src: url('iconfont.woff2?t=1620099021268') format('woff2'),
-       url('iconfont.woff?t=1620099021268') format('woff'),
-       url('iconfont.ttf?t=1620099021268') format('truetype');
+  src: url('iconfont.woff2?t=1621152979500') format('woff2'),
+       url('iconfont.woff?t=1621152979500') format('woff'),
+       url('iconfont.ttf?t=1621152979500') format('truetype');
 }
 </code></pre>
           <h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
@@ -262,6 +268,15 @@
       <div class="content font-class">
         <ul class="icon_lists dib-box">
           
+          <li class="dib">
+            <span class="icon iconfont firerock-iconexport"></span>
+            <div class="name">
+              export
+            </div>
+            <div class="code-name">.firerock-iconexport
+            </div>
+          </li>
+          
           <li class="dib">
             <span class="icon iconfont firerock-iconqidong"></span>
             <div class="name">
@@ -532,6 +547,14 @@
       <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-iconexport"></use>
+                </svg>
+                <div class="name">export</div>
+                <div class="code-name">#firerock-iconexport</div>
+            </li>
+          
             <li class="dib">
                 <svg class="icon svg-icon" aria-hidden="true">
                   <use xlink:href="#firerock-iconqidong"></use>

+ 7 - 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=1620099021268') format('woff2'),
-       url('iconfont.woff?t=1620099021268') format('woff'),
-       url('iconfont.ttf?t=1620099021268') format('truetype');
+  src: url('iconfont.woff2?t=1621152979500') format('woff2'),
+       url('iconfont.woff?t=1621152979500') format('woff'),
+       url('iconfont.ttf?t=1621152979500') format('truetype');
 }
 
 .iconfont {
@@ -13,6 +13,10 @@
   -moz-osx-font-smoothing: grayscale;
 }
 
+.firerock-iconexport:before {
+  content: "\e72d";
+}
+
 .firerock-iconqidong:before {
   content: "\e63c";
 }

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 1
fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.js


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

@@ -5,6 +5,13 @@
   "css_prefix_text": "firerock-icon",
   "description": "",
   "glyphs": [
+    {
+      "icon_id": "19441448",
+      "name": "export",
+      "font_class": "export",
+      "unicode": "e72d",
+      "unicode_decimal": 59181
+    },
     {
       "icon_id": "8796451",
       "name": "启动",

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


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


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


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

@@ -69,6 +69,7 @@ export const fixedRouter = [
             { path: '/files/:id', component: projectInside, name: '任务看板' },
             { path: '/info/:id', component: projectInside, name: '项目概览' },
             { path: '/summary/:id', component: projectInside, name: '数据统计' },
+            { path: '/earning/:id', component: projectInside, name: '挣值分析' },
         ]
     },
     {

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

@@ -59,7 +59,7 @@
                         this.listLoading = false;
                         if (res.code == "ok") {
                             var aTag = document.createElement('a');
-                            aTag.download = "项目成本统计.xls";
+                            aTag.download = "项目工时成本统计.xls";
                             aTag.href = res.data;
                             aTag.click();
                         } else {
@@ -112,7 +112,7 @@
                         _this.myChart = myChart;
                         var option = {
                             title: {
-                                text: '成本总计' + totalMoneyCost.toFixed(2) + '元',
+                                text: '工时成本总计' + totalMoneyCost.toFixed(2) + '元',
                                 left:'left',
                             },
                             // 工具箱

+ 362 - 0
fhKeeper/formulahousekeeper/timesheet/src/views/project/earning.vue

@@ -0,0 +1,362 @@
+<template>
+        <div :style="'padding:10px;background:#f7f7f7;min-height:'+tableHeight+'px;'">
+        <div style="margin: 0 auto;width:1120px;">
+            <el-row :gutter="10">
+            <el-col :span="24">    
+            <div class="box" style="height:350px;">
+                <div >
+                    <div class="lableTxt">项目利润快照</div>
+                    <el-divider></el-divider>
+                    <!--利润率列表-->
+                    <el-table :data="list" highlight-current-row v-loading="listLoading" max-height="300" style="width: 100%;">
+                        <el-table-column prop="indate" label="校准日期"  ></el-table-column>
+                        <el-table-column prop="profitA"  >
+                            <template slot="header">
+                               <span>利润率A</span>
+                               <el-popover placement="top" width="250" trigger="hover" content="利润率A = (项目金额 - 总成本)/项目金额">
+                                   <i class="el-icon-question" slot="reference" />
+                               </el-popover>
+                            </template>
+                            <template slot-scope="scope">
+                                {{scope.row.profitA}}%
+                            </template>
+                        </el-table-column>
+                        <el-table-column prop="profitB" label="利润率B"  >
+                            <template slot="header">
+                               <span>利润率B</span>
+                               <el-popover placement="top" width="350" trigger="hover" content="利润率B = (项目金额 - 总成本 - 预留金额1)/项目金额">
+                                   <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}}%
+                            </template>
+                        </el-table-column>
+                        <el-table-column prop="contractAmount" label="项目金额" ></el-table-column>
+                        <el-table-column  label="基线成本" >
+                            <el-table-column prop="baseMan" label="人员成本">
+                                <template slot-scope="scope">
+                                ¥{{scope.row.baseMan}}
+                                </template>
+                            </el-table-column>
+                            <el-table-column prop="baseFee" label="费用">
+                                <template slot-scope="scope">
+                                ¥{{scope.row.baseFee}}
+                                </template>
+                            </el-table-column>
+                            <el-table-column prop="baseOutsourcing" label="外包费用">
+                                <template slot-scope="scope">
+                                ¥{{scope.row.baseOutsourcing}}
+                                </template>
+                            </el-table-column>
+                            <el-table-column prop="baseRisk1" label="风险预留金额1" width="150">
+                                <template slot-scope="scope">
+                                ¥{{scope.row.baseRisk1}}
+                                </template>
+                            </el-table-column>
+                            <el-table-column prop="baseRisk2" label="风险预留金额2" width="150">
+                                <template slot-scope="scope">
+                                ¥{{scope.row.baseRisk2}}
+                                </template>
+                            </el-table-column>
+                        </el-table-column>
+                        
+                    </el-table>
+                </div>
+            </div>
+            </el-col>
+            </el-row>
+            <el-row :gutter="10">
+                <el-col :span="12">    
+                    <div class="box">   
+                        <div class="lableTxt">耗时最多任务</div>
+                        <el-divider></el-divider>
+                        <div id="costPanel" style="height:300px;"></div>
+                    </div>
+                </el-col>
+                <el-col :span="12">    
+                    <div class="box">   
+                        <div class="lableTxt">按任务列表统计</div>
+                        <el-divider></el-divider>
+                        <div id="stagesPanel" style="height:300px;"></div>
+                    </div>
+                </el-col>
+            </el-row>
+        </div>
+        
+    </div>
+</template>
+<style scoped>
+#executorPanel {
+        display: inline-block;
+        width: 100%; 
+    }  
+.el-divider--horizontal {
+    margin: 10px 0;
+    height: 0.5px;
+}
+.box {
+    background:#fff;border: 1px solid #eeeeee;border-radius:5px;padding:10px;
+    height:303.7px;margin-top:10px;
+}
+.info span {
+    color:#303133;
+}
+.gray_label {
+    color:#999 !important;
+}
+
+.el-row {
+    margin-top:10px;
+}
+.lableTxt {
+    color:#666;
+}
+
+</style>
+<script>
+    import util from "../../common/js/util";
+    export default {
+        data() {
+            return {
+                list:[],
+                costChart:null,
+                stagesChart: null,
+                executorChart: null,
+                pVisible:false,
+                taskSum:{},
+                users:[],
+                importanceList:[{id:1,label:'一般'},{id:2,label:'紧急'},{id:3,label:'重要'},{id:4,label:'重要且紧急'}],
+                //1-一般,2-紧急,3-重要,4-重要且紧急
+                levelTxt:["全部","一般","紧急","重要","重要且紧急"],
+                //1-进行中,2-已完成,3-已撤销
+                statusTxt: ["全部","进行中","已完成","已撤销"],
+                addFolderDialog: false,
+                upLoading:false,
+                user: JSON.parse(sessionStorage.getItem("user")),
+                addLoading: false,
+                curProjectId:null,
+                title: "",
+                
+            };
+        },
+        methods: {
+            getProfitSnapshot() {
+                let _this = this;
+                this.http.post('/earning-snapshot/list', {projectId: this.curProjectId},
+                res => {
+                    if (res.code == "ok") {
+                        _this.list = res.data;
+                    } 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 {
+                        this.$message({
+                            message: res.msg,
+                            type: "error"
+                        });
+                    }
+                },
+                error => {
+                    this.$message({
+                        message: error,
+                        type: "error"
+                    });
+                });
+            },
+            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;
+            window.onresize = function temp() {
+                that.tableHeight = window.innerHeight - 160;
+            };
+        },
+        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.getProfitSnapshot();
+        }
+    };
+</script>

+ 103 - 19
fhKeeper/formulahousekeeper/timesheet/src/views/project/info.vue

@@ -15,8 +15,8 @@
                     </el-row>
                     <el-row :gutter="10">
                         <el-col :span="5" ><span class="gray_label">项目编码: </span></el-col><el-col :span="7" ><span >{{project.projectCode}}</span></el-col>
-                        <el-col :span="5" ><span class="gray_label">项目预算:</span></el-col><el-col :span="7" >
-                        <span >{{project.budget == null?'-':project.budget}} 元</span></el-col>
+                        <el-col :span="5" ><span class="gray_label">项目金额:</span></el-col><el-col :span="7" >
+                        <span >{{project.contractAmount == null?'-':project.contractAmount}} 元</span></el-col>
                     </el-row>
                     <el-row :gutter="10">
                         <el-col :span="5" ><span class="gray_label">项目级别: </span></el-col><el-col :span="7" ><span >{{levelTxt[project.level]}}</span></el-col>
@@ -33,17 +33,23 @@
                             {{project.finishDate==null?'-':project.finishDate}}</span></el-col>
                     </el-row>
                 </div>
-
-                <div class="box" style="margin-top:10px;">
-                    <div><label>相关人员</label>
-                    <el-link v-if="user.id == project.creatorId || user.id == project.inchargerId" @click="showEditPar" style="float:right;"><i class="el-icon-edit"  ></i></el-link>
-                    </div>
-                    <div style="margin-top:10px;color:#999;">负责人</div>
-                    <div><el-link style="margin:10px" @click="showUser(project.inchargerId)">{{project.inchargerName}}</el-link></div>
-                    <div style="color:#999;">参与人</div>
-                    <div>
-                        <el-link v-for="item in project.participationList" :key="item.id" style="margin:10px;" @click="showUser(item.id)">{{item.name}}</el-link>
-                        <el-button class="el-icon-plus" @click="addMembVisible=true" size="mini"></el-button>
+                
+                <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>
+                            ¥{{project.baseMan==null?'-':project.baseMan}}</span></el-col>
+                        <el-col :span="5" ><span class="gray_label">费用:</span></el-col><el-col :span="7" ><span>
+                        ¥{{project.baseFee==null?'-':project.baseFee}}</span></el-col></el-row>
+                        <el-row :gutter="10"><el-col :span="5" ><span class="gray_label">外包费用:</span></el-col><el-col :span="7" ><span>
+                        ¥{{project.baseOutsourcing==null?'-':project.baseOutsourcing}}</span></el-col>
+                        <el-col :span="5" ><span class="gray_label">风险预留金额1:</span></el-col><el-col :span="7" ><span>
+                        ¥{{project.baseRisk1==null?'-':project.baseRisk1}}</span></el-col></el-row>
+                        <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}}</span></el-col>
+                        <el-col :span="5" ><span class="gray_label">总成本:</span></el-col><el-col :span="7" ><span>
+                        ¥{{project.budget==null?'-':project.budget}}</span></el-col>
+                    </el-row>
                     </div>
                 </div>
                 <div class="box" style="margin-top:10px;">
@@ -122,8 +128,8 @@
                     <el-select v-model="addForm.level"  placeholder="请选择级别" style="width:32%;" >
                         <el-option v-for="item in importanceList" :key="item.id" :label="item.label" :value="item.id"></el-option>
                     </el-select>
-                    <span style="margin-left:50px;margin-right:10px;">项目预算</span>
-                    <el-input v-model="addForm.budget"    style="width:32%;"
+                    <span style="margin-left:50px;margin-right:10px;">项目金额</span>
+                    <el-input v-model="addForm.contractAmount"    style="width:32%;"
                     placeholder="整数" clearable @keyup.native="number"></el-input><span style="margin-left:10px;">元</span>
                 </el-form-item>
                 <el-form-item label="开始日期" prop="planStartDate">
@@ -150,6 +156,30 @@
             </div>
         </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-input v-model="addForm.baseMan"  placeholder="请输入" clearable></el-input>
+                </el-form-item>
+                <el-form-item label="费用" prop="baseFee">
+                    <el-input v-model="addForm.baseFee"  placeholder="请输入" clearable></el-input>
+                </el-form-item>
+                <el-form-item label="外包费用" prop="baseOutsourcing">
+                    <el-input v-model="addForm.baseOutsourcing"  placeholder="请输入" clearable></el-input>
+                </el-form-item>
+                <el-form-item label="风险预留金额1" prop="baseRisk1">
+                    <el-input v-model="addForm.baseRisk1"  placeholder="请输入" clearable></el-input>
+                </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>
+            <div slot="footer" class="dialog-footer">
+                <el-button @click.native="addBaseFormVisible = false">取消</el-button>
+                <el-button type="primary" @click="adjustBase" :loading="addLoading">提交</el-button>
+            </div>
+        </el-dialog>
+
         <!--编辑参与人界面-->
         <el-dialog :title="title" v-if="pVisible" :visible.sync="pVisible" :close-on-click-modal="false" customClass="customWidth" width="600px">
             <el-form ref="participForm" :model="addForm" :rules="rules" label-width="120px">
@@ -219,6 +249,7 @@
     export default {
         data() {
             return {
+                addBaseFormVisible:false,
                 addMembVisible:false,
                 addMembForm:{},
                 pVisible:false,
@@ -251,6 +282,47 @@
             };
         },
         methods: {
+            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) {
+                    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
+                },
+                res => {
+                    if (res.code == "ok") {
+                        this.getProjectInfo();
+                        this.addBaseFormVisible = false;
+                        this.$message({
+                            message: '校准成功',
+                            type: "success"
+                        });
+                    } else {
+                        this.$message({
+                        message: res.msg,
+                        type: "error"
+                        });
+                    }
+                },
+                error => {
+                    this.$message({
+                        message: error,
+                        type: "error"
+                    });
+                });
+            },
             //提交添加参与人的请求
             submitAddMemb() {
                 this.addLoading = true;
@@ -315,8 +387,8 @@
                 });
             },
             number(){  
-             this.addForm.budget = this.addForm.budget.replace(/[^\.\d]/g,'');
-                this.addForm.budget = this.addForm.budget.replace('.','');
+             this.addForm.contractAmount = this.addForm.contractAmount.replace(/[^\.\d]/g,'');
+                this.addForm.contractAmount = this.addForm.contractAmount.replace('.','');
           },
             //选择参与人
             changeParticipator() {
@@ -423,8 +495,8 @@
                         if(this.addForm.level != null) {
                             formData.append("level", this.addForm.level);
                         }
-                        if(this.addForm.budget != null) {
-                            formData.append("budget", this.addForm.budget);
+                        if(this.addForm.contractAmount != null) {
+                            formData.append("contractAmount", this.addForm.contractAmount);
                         }
                         
                         this.http.uploadFile(this.port.project.add,formData,
@@ -454,6 +526,18 @@
                         }
                 });
             },
+            showEditBase() {
+                this.addForm = JSON.parse(JSON.stringify(this.project));
+                var list = this.project.participationList , arr = [];
+                for(var j in list) {
+                    arr.push(list[j].id)
+                }
+                this.addForm.userId = arr;
+                this.addForm.code = this.addForm.projectCode;
+                this.addForm.name = this.addForm.projectName;
+                this.addBaseFormVisible = true;
+
+            },
             showEdit() {
                 this.addForm = JSON.parse(JSON.stringify(this.project));
                 console.log('---'+this.addForm);

+ 8 - 3
fhKeeper/formulahousekeeper/timesheet/src/views/project/projectInside.vue

@@ -75,8 +75,8 @@
                     <!-- 增加侧边栏的点击效果 -->
                     
                     <el-main style="background:#f7f7f7;padding:0px;">
-                        <el-row style="color:#999;margin-top:10px;padding: 0px 10px;">
-                        <el-col :span="20">
+                        <el-row style="color:#999;margin-top:10px;padding: 0px 10px;" :gutter="10">
+                        <el-col :span="18">
                             <el-link @click="toggleGroup"><i v-if="selectedGroup != null" :class="groupWidth==0?'el-icon-d-arrow-right':'el-icon-d-arrow-left'" style="margin-top:10px;">{{selectedGroup.name}}</i></el-link>
                         </el-col>
                         <el-col :span="4">
@@ -86,6 +86,9 @@
                                 </el-option>
                             </el-select>
                         </el-col>
+                        <el-col :span="2">
+                            <el-button icon="iconfont firerock-iconexport" size="mini" @click="exportTask">导出</el-button>
+                        </el-col>
                         </el-row>
                         <!-- <div style="color:#999;margin-top:10px;">
                             <i v-if="selectedGroup != null" class="el-icon-arrow-left" style="margin-top:10px;">{{selectedGroup.name}}</i>
@@ -220,7 +223,7 @@
             <el-tab-pane label="文件中心" name="files"><FileCenter ref="fileCenter"></FileCenter></el-tab-pane>
             <el-tab-pane label="项目概览" name="info"><ProjectInfo ref="projectInfo"></ProjectInfo></el-tab-pane>
             <el-tab-pane label="数据统计" name="summary"><Summary ref="summary"></Summary></el-tab-pane>
-            
+            <el-tab-pane label="挣值分析" name="earning"><Earning ref="earning"></Earning></el-tab-pane>
         </el-tabs>
         
         <!--新增任务界面-->
@@ -552,6 +555,7 @@
     import FileCenter from './fileCenter.vue';
     import ProjectInfo from './info.vue';
     import Summary from './summary.vue';
+    import Earning from './earning.vue';
     // import editor from '@tinymce/tinymce-vue'
     // 富文本样式
     import 'quill/dist/quill.core.css'
@@ -570,6 +574,7 @@
             FileCenter,
             ProjectInfo,
             Summary,
+            Earning,
             quillEditor // 富文本
         },
         

+ 146 - 6
fhKeeper/formulahousekeeper/timesheet/src/views/project/summary.vue

@@ -72,6 +72,16 @@
                     </div>
                 </el-col>
             </el-row>
+
+            <el-row :gutter="10">
+                <el-col :span="24">    
+                    <div class="box" style="height:550px;">   
+                        <div class="lableTxt">任务 计划工时 VS 实际工时 <el-link @click="exportTaskCompare" style="float:right;"><i class="iconfont firerock-iconexport"></i>导出</el-link></div>
+                        <el-divider></el-divider>
+                        <div id="taskTimeComparePanel" style="height:500px;"></div>
+                    </div>
+                </el-col>
+            </el-row>
         </div>
         
     </div>
@@ -109,6 +119,7 @@
     export default {
         data() {
             return {
+                compareChart:null,
                 costChart:null,
                 stagesChart: null,
                 executorChart: null,
@@ -130,6 +141,123 @@
             };
         },
         methods: {
+            exportTaskCompare() {
+                let _this = this;
+                this.http.post('/task/exportTaskTimeCompare', {projectId: this.curProjectId},
+                res => {
+                    if (res.code == "ok") {
+                        location.href = res.data;
+                    } else {
+                        this.$message({
+                            message: res.msg,
+                            type: "error"
+                        });
+                    }
+                }
+                );
+            },
+            getTaskTimeCompare() {
+                let _this = this;
+                this.http.post('/task/getTaskTimeCompare', {projectId: this.curProjectId},
+                res => {
+                    if (res.code == "ok") {
+                        var xList1 = [], xList2 = [], list = res.data.reverse();
+                        var taskNames = [];
+                        for(var i in list) {
+                            xList1.push({
+                                "value": list[i].workHours,
+                                "id": list[i].id,
+                                "fullName":list[i].name,
+                            });
+                            xList2.push({
+                                "value": list[i].planHours,
+                                "id": list[i].id,
+                                "fullName":list[i].name,
+                            });
+                            taskNames.push(list[i].name.length>12?list[i].name.substring(0,12)+'..':list[i].name);
+                        }
+                        var myChart = echarts.init(document.getElementById("taskTimeComparePanel"));
+                        _this.compareChart = myChart;
+                        var option = {
+                            // 全局调色盘。
+                            color: ["#409EFF","#71C671"],
+                            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']
+                                    },
+                                }
+                            },
+                            legend: {
+                                data: ['实际工时', '计划工时']
+                            },
+                            grid: {
+                                left: '3%',
+                                right: '4%',
+                                bottom: '3%',
+                                containLabel: true
+                            },
+                            tooltip: {
+                                trigger: 'axis',
+                                axisPointer: {
+                                    type: 'shadow'
+                                },
+                            },
+                            xAxis: {
+                                type: 'value',
+                                boundaryGap: [0, 1],
+                                axisLabel: {
+                                    formatter:'{value} 小时'
+                                }
+                            },
+                            yAxis: [{
+                                type: 'category',
+                                data: taskNames
+                            }],
+                            series: [{
+                                    name: '实际工时',
+                                    type: 'bar',
+                                    data: xList1
+                                },
+                                {
+                                    name: '计划工时',
+                                    type: 'bar',
+                                    data: xList2
+                                }]
+                        };
+                        myChart.setOption(option);
+                    } else {
+                        this.$message({
+                            message: res.msg,
+                            type: "error"
+                        });
+                    }
+                },
+                error => {
+                    this.$message({
+                        message: error,
+                        type: "error"
+                    });
+                });
+            },
             getTopCostTask() {
                 let _this = this;
                 this.http.post('/task/getTopCostTask', {projectId: this.curProjectId},
@@ -286,6 +414,7 @@
                         var myChart = echarts.init(document.getElementById("executorPanel"));
                         _this.executorChart = myChart;
                         var option = {
+                            color: ["#409EFF","#71C671"],
                             title: {
                                 show:list.length == 0,
                                 textStyle: {
@@ -382,6 +511,7 @@
                 this.getExecutorPanel();
                 this.getTopCostTask();
                 this.getStagesPanel();
+                this.getTaskTimeCompare();
             }
         },
         created() {
@@ -398,14 +528,24 @@
             this.curProjectId = parseInt(this.$route.params.id);
             var _this = this;
             window.addEventListener("resize", function() {
-                _this.executorChart.resize();
-                _this.stagesChart.resize();
-                _this.costChart.resize();
+                if (_this.executorChart != null) {
+                    _this.executorChart.resize();
+                }
+                if (_this.stagesChart != null) {
+                    _this.stagesChart.resize();
+                }
+                if (_this.costChart != null) {
+                    _this.costChart.resize();
+                }
+                if (_this.compareChart != null) {
+                    _this.compareChart.resize();
+                }
             });
             this.getProjectTaskSum();
-                this.getExecutorPanel();
-                this.getStagesPanel();
-                this.getTopCostTask();
+            this.getExecutorPanel();
+            this.getStagesPanel();
+            this.getTopCostTask();
+            this.getTaskTimeCompare();
         }
     };
 </script>

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

@@ -1,25 +1,34 @@
 <template>
     <section>
         <!--工具条-->
-        <!-- <el-col :span="24" class="toolbar" style="padding-bottom: 0px;">
+        <el-col :span="24" class="toolbar" style="padding-bottom: 0px;">
             <el-form :inline="true">
-                <el-form-item label="类型:">
-                    <el-select v-model="search.value" placeholder="请选择类型" @change="getList()">
-                        <el-option label="全部" value="-1"></el-option>
-                        <el-option label="待审核" value="0"></el-option>
-                        <el-option label="已通过" value="1"></el-option>
-                        <el-option label="已驳回" value="2"></el-option>
+                <el-form-item label="项目:">
+                    <el-select v-model="search.projectId" placeholder="请选择" clearable @change="getList()">
+                        <el-option v-for="item in projectList" :key="item.id" :label="item.projectName" :value="item.id"></el-option>
                     </el-select>
                 </el-form-item>
-                <el-form-item v-if="search.value == -1" label="日期:" style="margin-left:20px;">
+                <el-form-item label="部门:">
+                    <el-cascader v-model="search.departmentIdArray" placeholder="请选择部门" style="width: 100%"
+                    :options="option" :props="{ checkStrictly: false,expandTrigger: 'hover' }" :show-all-levels="false" clearable
+                    @change="getList()"
+                    ></el-cascader>
+                </el-form-item>
+                <el-form-item label="日期:" style="margin-left:20px;">
                     <el-date-picker v-model="search.date" :editable="false" format="yyyy-MM-dd" value-format="yyyy-MM-dd" 
                     @change="getList()" :clearable="true" type="date" placeholder="选择工作日期"></el-date-picker>
                 </el-form-item>
+                <el-form-item   style="margin-left:20px;">
+                    <el-button @click="batchApprove(true)" style="margin-left:10px;" :disabled="multipleSelection.length==0">批量通过</el-button>
+                <el-button @click="batchApprove(false)"  :disabled="multipleSelection.length==0">批量驳回</el-button>
+                </el-form-item>
+                
             </el-form>
-        </el-col> -->
-
+        </el-col>
         <!--列表-->
-        <el-table :data="list" highlight-current-row v-loading="listLoading" :height="tableHeight" style="width: 100%;">
+        <el-table :data="list" ref="multipleTable" highlight-current-row v-loading="listLoading" :height="tableHeight" style="width: 100%;"
+            @selection-change="handleSelectionChange">
+            <el-table-column type="selection" width="55"></el-table-column>
             <el-table-column type="expand">
                 <template slot-scope="props">
                     <el-timeline>
@@ -34,16 +43,11 @@
                     </el-timeline>
                 </template>
             </el-table-column>
-            <el-table-column type="index" width="60"></el-table-column>
+            
             <el-table-column prop="name" label="姓名" sortable></el-table-column>
             <el-table-column prop="date" label="日期" sortable>
-                <template slot-scope="scope">
-                    <span v-if="search.value == -1">{{search.date}}</span>
-                    <span v-else>{{scope.row.date}}</span>
-                </template>
             </el-table-column>
             <el-table-column prop="reportTime" label="工作时长(h)" >
-
             </el-table-column>
             <el-table-column prop="state" label="状态" sortable>
                 <template slot-scope="scope">
@@ -60,7 +64,7 @@
                 </template>
             </el-table-column>
         </el-table>
-
+        
         <!--工具条-->
         <!-- <el-col v-if="search.value != -1" :span="24" class="toolbar">
             <el-pagination
@@ -82,15 +86,19 @@
     export default {
         data() {
             return {
+                isAllSelect:false,
                 user: JSON.parse(sessionStorage.getItem("user")),
 
                 search: {
-                    value: 0,
-                    date: util.formatDate.format(new Date(new Date()), "yyyy-MM-dd"),
+                    projectId:null,
+                    departmentIdArray: null,
+                    departmentId:null,
+                    date: null,
+                    state:0,
                 },
 
                 users: [],
-
+                option:[],
                 tableHeight: 0,
                 listLoading: false,
                 total: 0,
@@ -98,10 +106,69 @@
                 size: 20,
                 list: [],
                 logining: false,
-
+                multipleSelection: [],
             };
         },
         methods: {
+            // 获取部门列表
+            getDepartment() {
+                this.http.post( this.port.manage.depList, {},
+                res => {
+                    if (res.code == "ok") {
+                        var list1 = JSON.parse(JSON.stringify(res.data));
+                        
+                        this.option = this.changeArr(list1);
+                    } else {
+                        this.$message({
+                            message: res.msg,
+                            type: "error"
+                        });
+                    }
+                },
+                error => {
+                    this.$message({
+                        message: error,
+                        type: "error"
+                    });
+                });
+            },
+
+            handleSelectionChange(val) {
+                this.multipleSelection = val;
+            },
+            batchApprove(isPass) {
+                console.log(this.multipleSelection);
+                var ids = '';
+                for (var i=0;i<this.multipleSelection.length; i++) {
+                    var line = this.multipleSelection[i];
+                    var array = line.data;
+                    for (var m=0;m<array.length; m++) {
+                        ids += array[m].id+',';
+                    }
+                }
+                if (ids.length > 0) {
+                    ids = ids.substring(0, ids.length-1);
+                }
+                this.http.post(isPass?'/report/batchApproveReport':'/report/batchDenyReport', {ids: ids},
+                res => {
+                    this.listLoading = false;
+                    if (res.code == "ok") {
+                        this.getList();
+                    } else {
+                        this.$message({
+                        message: res.msg,
+                        type: "error"
+                        });
+                    }
+                },
+                error => {
+                    this.listLoading = false;
+                    this.$message({
+                        message: error,
+                        type: "error"
+                    });
+                });
+            },
             //分页
             handleCurrentChange(val) {
                 this.page = val;
@@ -113,16 +180,22 @@
                 this.getList();
             },
 
-            //获取项目列表
+            //获取待审核的数据列表
             getList() {
                 this.listLoading = true;
-                let form = {}
-                if(this.search.value==-1) {
-                    form.date = this.search.date
+                // let form = {}
+                // if(this.search.value==-1) {
+                //     form.date = this.search.date
+                // } else {
+                //     form.state = this.search.value;
+                // }
+                if (this.search.departmentIdArray == null) {
+                    this.search.departmentId = null;
                 } else {
-                    form.state = this.search.value;
+                    var length = this.search.departmentIdArray.length;
+                    this.search.departmentId = this.search.departmentIdArray[length-1];
                 }
-                this.http.post(this.search.value==-1?this.port.report.list:this.port.report.portList, form,
+                this.http.post(this.port.report.portList, this.search,
                 res => {
                     this.listLoading = false;
                     if (res.code == "ok") {
@@ -147,19 +220,14 @@
             approve(id,date, item) {
                 console.log(item);
                 this.logining = true;
-                var time = "";
-                if(this.search.value == -1) {
-                    time = this.search.date;
-                } else {
-                    time = date;
-                }
+                
                 var ids = '';
                 var data = item.data;
                 data.forEach(element => {
                     ids +=(element.id+',');
                 });
 
-                this.http.post( this.port.report.approve, {id: id , date: time, reportIds: ids},
+                this.http.post(this.port.report.approve, {id: id ,reportIds: ids},
                 res => {
                     this.logining = false;
                     if (res.code == "ok") {
@@ -183,16 +251,52 @@
                     });
                 });
             },
-
+// 修改数组
+            changeArr(arr) {
+                for (var i = 0; i < arr.length; i++) {
+                    if(arr[i].id != -1 && arr[i].id != 0) {
+                        if (arr[i].children != null && arr[i].children.length>0) {
+                            arr[i].children = this.changeArr(arr[i].children);
+                        }
+                        arr[i].id && (arr[i].value = arr[i].id);
+                        delete arr[i].id;
+                    }
+                }
+                for(var i in arr) {
+                    if(arr[i].id == -1 || arr[i].id == 0) {
+                        arr.splice(i,1)
+                    }    
+                }
+                return arr;
+            },
+            
+            //获取项目列表
+            getProjectList() {
+                this.listLoading = true;
+                this.http.post( this.port.project.list, {},
+                res => {
+                    this.listLoading = false;
+                    if (res.code == "ok") {
+                        this.projectList = res.data;
+                    } else {
+                        this.$message({
+                            message: res.msg,
+                            type: "error"
+                        });
+                    }
+                },
+                error => {
+                    this.listLoading = false;
+                    this.$message({
+                        message: error,
+                        type: "error"
+                    });
+                });
+            },
             // 未通过日报
             deny(id,i,date, item) {
                 this.logining = true;
-                var time = "";
-                if(this.search.value == -1) {
-                    time = this.search.date;
-                } else {
-                    time = date;
-                }
+                var time = date;
                 var ids = '';
                 var data = item.data;
                 data.forEach(element => {
@@ -225,14 +329,16 @@
         },
         created() {
             let height = window.innerHeight;
-            this.tableHeight = height - 85;
+            this.tableHeight = height - 125;
             const that = this;
             window.onresize = function temp() {
-                that.tableHeight = window.innerHeight - 85;
+                that.tableHeight = window.innerHeight - 125;
             };
         },
         mounted() {
             this.getList();
+            this.getDepartment();
+            this.getProjectList();
         }
     };
 </script>

+ 16 - 11
fhKeeper/formulahousekeeper/timesheet_h5/src/views/msg/index.vue

@@ -4,7 +4,7 @@
         
         <div class="login_form">
             <van-list v-model="loading" :finished="finished" finished-text="没有更多了" :error.sync="error" error-text="请求失败,点击重新加载" @load="getMessage">
-                <van-cell @click="readMsg(index)" v-for="(item,index) in list" :key="index" :title="item.type==0?'审批未通过':''" :label="item.time.replace('T', ' ')" >
+                <van-cell @click="readMsg(index)" v-for="(item,index) in list" :key="index" :title="msgType[item.type]" :label="item.time.replace('T', ' ')" >
                     <span v-if="item.checked == 1" style="color:green">已读</span>
                     <span v-if="item.checked == 0" style="color:red">未读</span>
                 </van-cell>
@@ -17,6 +17,7 @@
     export default {
         data() {
             return {
+                msgType:["日报审核未通过","有新任务"],
                 user: JSON.parse(localStorage.userInfo),
                 
                 total: 0,
@@ -44,16 +45,20 @@
 
             readMsg(index) {
                 var item = this.list[index];
-                var date = item.content;
-                this.$axios.post("/information/check", {id:item.id
-                })
-                .then(res => {
-                    if(res.code == "ok") {
-                        //跳转到对应的日报上进行修改
-                        this.getMessage();
-                        this.$router.push('/edit?date='+date);
-                    } 
-                }).catch(err=> {toast.clear();});
+                if (item.type == 0) {
+                    //日报
+                    var date = item.content;
+                    this.$axios.post("/information/check", {id:item.id
+                    })
+                    .then(res => {
+                        if(res.code == "ok") {
+                            //跳转到对应的日报上进行修改
+                            this.getMessage();
+                            this.$router.push('/edit?date='+date);
+                        } 
+                    }).catch(err=> {toast.clear();});
+                }
+                
             },
             
             //获取消息