ソースを参照

任务导出,任务统计工时对比导出

seyason 4 年 前
コミット
0c60dff742
18 ファイル変更851 行追加18 行削除
  1. 15 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/TaskController.java
  2. 10 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/TimeTask.java
  3. 6 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/TaskMapper.java
  4. 5 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/TaskService.java
  5. 1 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ReportServiceImpl.java
  6. 214 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/TaskServiceImpl.java
  7. 44 0
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/TaskMapper.xml
  8. 26 3
      fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/demo_index.html
  9. 7 3
      fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.css
  10. 1 1
      fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.js
  11. 7 0
      fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.json
  12. BIN
      fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.ttf
  13. BIN
      fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.woff
  14. BIN
      fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.woff2
  15. 2 2
      fhKeeper/formulahousekeeper/timesheet/src/views/project/cost.vue
  16. 362 0
      fhKeeper/formulahousekeeper/timesheet/src/views/project/earning.vue
  17. 5 2
      fhKeeper/formulahousekeeper/timesheet/src/views/project/projectInside.vue
  18. 146 6
      fhKeeper/formulahousekeeper/timesheet/src/views/project/summary.vue

+ 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);
+    }
 }
 

+ 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;
+}

+ 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);
 }

+ 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);
 }

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

@@ -744,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;
+    }
 }

+ 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";
 }

ファイルの差分が大きいため隠しています
+ 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
fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.ttf


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


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


+ 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>

+ 5 - 2
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>

+ 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>