Bladeren bron

子项目和统计

seyason 4 jaren geleden
bovenliggende
commit
425a3e0857
96 gewijzigde bestanden met toevoegingen van 4404 en 623 verwijderingen
  1. 12 11
      fhKeeper/formulahousekeeper/inva_4_tivo/about.html
  2. 4 4
      fhKeeper/formulahousekeeper/inva_4_tivo/download.html
  3. BIN
      fhKeeper/formulahousekeeper/inva_4_tivo/images/s1.png
  4. BIN
      fhKeeper/formulahousekeeper/inva_4_tivo/images/s10.png
  5. BIN
      fhKeeper/formulahousekeeper/inva_4_tivo/images/s11.png
  6. BIN
      fhKeeper/formulahousekeeper/inva_4_tivo/images/s12.png
  7. BIN
      fhKeeper/formulahousekeeper/inva_4_tivo/images/s2.png
  8. BIN
      fhKeeper/formulahousekeeper/inva_4_tivo/images/s3.png
  9. BIN
      fhKeeper/formulahousekeeper/inva_4_tivo/images/s4.png
  10. BIN
      fhKeeper/formulahousekeeper/inva_4_tivo/images/s5.png
  11. BIN
      fhKeeper/formulahousekeeper/inva_4_tivo/images/s6.png
  12. BIN
      fhKeeper/formulahousekeeper/inva_4_tivo/images/s7.png
  13. BIN
      fhKeeper/formulahousekeeper/inva_4_tivo/images/s8.png
  14. BIN
      fhKeeper/formulahousekeeper/inva_4_tivo/images/s9.png
  15. 69 57
      fhKeeper/formulahousekeeper/inva_4_tivo/index.html
  16. 7 7
      fhKeeper/formulahousekeeper/inva_4_tivo/mobile.html
  17. 4 4
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/DepartmentController.java
  18. 7 6
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ProjectController.java
  19. 148 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ProjectTimerController.java
  20. 55 15
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ReportController.java
  21. 85 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/SubProjectController.java
  22. 2 2
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/UserController.java
  23. 83 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/ProjectTimer.java
  24. 25 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/Report.java
  25. 48 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/SubProject.java
  26. 13 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/TimeType.java
  27. 8 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/User.java
  28. 3 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/vo/DepartmentMasterVO.java
  29. 2 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/vo/UserVO.java
  30. 2 2
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/DepartmentMapper.java
  31. 2 2
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/ProjectMapper.java
  32. 16 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/ProjectTimerMapper.java
  33. 10 3
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/ReportMapper.java
  34. 20 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/SubProjectMapper.java
  35. 2 2
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/DepartmentService.java
  36. 3 3
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/ProjectService.java
  37. 16 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/ProjectTimerService.java
  38. 6 4
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/ReportService.java
  39. 21 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/SubProjectService.java
  40. 1 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/UserService.java
  41. 8 7
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/DepartmentServiceImpl.java
  42. 11 3
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/FinanceServiceImpl.java
  43. 41 26
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ProjectServiceImpl.java
  44. 20 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ProjectTimerServiceImpl.java
  45. 154 60
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ReportServiceImpl.java
  46. 58 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/SubProjectServiceImpl.java
  47. 44 15
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/UserServiceImpl.java
  48. 1 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/util/CodeGenerator.java
  49. 18 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/util/MathUtil.java
  50. 7 1
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/DepartmentMapper.xml
  51. 6 0
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/ProjectMapper.xml
  52. 24 0
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/ProjectTimerMapper.xml
  53. 48 9
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/ReportMapper.xml
  54. 30 0
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/SubProjectMapper.xml
  55. 3 1
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/TimeTypeMapper.xml
  56. 4 4
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/UserMapper.xml
  57. BIN
      fhKeeper/formulahousekeeper/management-platform/人员导入模板 (4).xlsx
  58. BIN
      fhKeeper/formulahousekeeper/management-platform/人员导入模板.xlsx
  59. BIN
      fhKeeper/formulahousekeeper/management-platform/财务人员成本模板2.xlsx
  60. 4 1
      fhKeeper/formulahousekeeper/timesheet/src/App.vue
  61. 539 0
      fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/demo.css
  62. 262 0
      fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/demo_index.html
  63. 33 0
      fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.css
  64. BIN
      fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.eot
  65. 1 0
      fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.js
  66. 37 0
      fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.json
  67. 38 0
      fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.svg
  68. BIN
      fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.ttf
  69. BIN
      fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.woff
  70. BIN
      fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.woff2
  71. 7 2
      fhKeeper/formulahousekeeper/timesheet/src/main.js
  72. 1 0
      fhKeeper/formulahousekeeper/timesheet/src/port.js
  73. 81 15
      fhKeeper/formulahousekeeper/timesheet/src/routes.js
  74. 0 1
      fhKeeper/formulahousekeeper/timesheet/src/views/Home.vue
  75. 13 1
      fhKeeper/formulahousekeeper/timesheet/src/views/Login.vue
  76. 49 15
      fhKeeper/formulahousekeeper/timesheet/src/views/project/cost.vue
  77. 27 10
      fhKeeper/formulahousekeeper/timesheet/src/views/project/detail.vue
  78. 120 101
      fhKeeper/formulahousekeeper/timesheet/src/views/project/detailDep.vue
  79. 366 0
      fhKeeper/formulahousekeeper/timesheet/src/views/project/finance.vue
  80. 160 16
      fhKeeper/formulahousekeeper/timesheet/src/views/project/list.vue
  81. 121 11
      fhKeeper/formulahousekeeper/timesheet/src/views/settings/timetype.vue
  82. 59 18
      fhKeeper/formulahousekeeper/timesheet/src/views/team/index.vue
  83. 331 105
      fhKeeper/formulahousekeeper/timesheet/src/views/workReport/daily.vue
  84. 19 7
      fhKeeper/formulahousekeeper/timesheet/src/views/workReport/list.vue
  85. 370 0
      fhKeeper/formulahousekeeper/timesheet/src/views/workReport/timer.vue
  86. 3 2
      fhKeeper/formulahousekeeper/timesheet_h5/src/main.js
  87. 7 0
      fhKeeper/formulahousekeeper/timesheet_h5/src/router/index.js
  88. 4 4
      fhKeeper/formulahousekeeper/timesheet_h5/src/utils/request.js
  89. 232 14
      fhKeeper/formulahousekeeper/timesheet_h5/src/views/edit/index.vue
  90. 59 19
      fhKeeper/formulahousekeeper/timesheet_h5/src/views/index/index.vue
  91. 7 1
      fhKeeper/formulahousekeeper/timesheet_h5/src/views/login/index.vue
  92. 134 0
      fhKeeper/formulahousekeeper/timesheet_h5/src/views/msg/index.vue
  93. 2 2
      fhKeeper/formulahousekeeper/timesheet_h5/src/views/my/children/center.vue
  94. 119 7
      fhKeeper/formulahousekeeper/timesheet_h5/src/views/project/index.vue
  95. 23 9
      fhKeeper/formulahousekeeper/timesheet_h5/src/views/review/index.vue
  96. 25 9
      fhKeeper/formulahousekeeper/timesheet_h5/src/views/view/index.vue

+ 12 - 11
fhKeeper/formulahousekeeper/inva_4_tivo/about.html

@@ -4,9 +4,9 @@
     <meta charset="utf-8">
     <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-    <meta name="keywords" content="工时管理,工时统计,工时填报,项目成本统计,远程监控,生产工时管理系统,工时成本管理,工时管理软件,研发工时管理系统,企业工时管理系统,项目工时统计,项目工时统计软件,项目工时统计系统,工时统计系统,工时统计表" />
-    <meta name="description" content="工时管家利用智能图像识别技术实现工时管理和工时统计。支持PC和手机端。可按项目,部门,岗位等多维度统计成本。软件可实现远程监管,有效反馈工作实际情况,对非工作情况主动检测上报。"/>
-    <title>工时管家-专注工时管理,手机移动填报,降低企业成本!</title>
+    <meta name="keywords" content="工时管理,工时统计,工时填报,项目成本统计,生产工时管理系统,工时成本管理,工时管理软件,研发工时管理系统,企业工时管理系统,项目工时统计,项目工时统计软件,项目工时统计系统,工时统计系统,工时统计表" />
+    <meta name="description" content="工时管家提供专业的工时填报和统计报表。支持PC和手机端。可按项目,部门,岗位等多维度统计成本。"/>
+    <title>工时管家-专注工时管理,手机移动填报,核算项目投入人力成本,企业IPO利器!</title>
     <link href="https://fonts.googleapis.com/css?family=Open+Sans:400,400i,700&display=swap&subset=latin-ext" rel="stylesheet">
     <link href="css/bootstrap.css" rel="stylesheet">
     <!-- <link href="css/fontawesome-all.css" rel="stylesheet"> -->
@@ -58,11 +58,11 @@
                         <a class="nav-link page-scroll" href=".">网站首页 <span class="sr-only">(current)</span></a>
                     </li>
                     <li class="nav-item">
-                        <a class="nav-link page-scroll" href="#pricing">产品定价</a>
+                        <a class="nav-link page-scroll" href="./index#pricing">产品定价</a>
                     </li>
-                    <li class="nav-item">
+                    <!-- <li class="nav-item">
                         <a class="nav-link page-scroll" href="./download.html">软件下载</a>
-                    </li>
+                    </li> -->
                     <li class="nav-item">
                         <a class="nav-link page-scroll" href="./mobile.html">手机版</a>
                     </li>
@@ -96,7 +96,7 @@
                     <div class="text-container">
                         <h2>公司介绍</h2>
                         <p>
-                            南京火石闪信网络科技有限公司成立于2016年,坐落于六朝古都南京,是一家专注于企业办公和管理领域的科技型中小企业。我们致力于通过互联网思维帮助企业完成数字化转型,为企业提高了工作效率,降低运营成本。
+                            南京火石闪信网络科技有限公司成立于2016年,坐落于六朝古都南京,是一家专注于企业办公和管理领域的国家高新技术企业。我们致力于通过互联网思维帮助企业完成数字化转型,为企业提高了工作效率,降低运营成本。
                             <br>
                             我们自主研发了云团队研发管理平台,快办团队协作管理软件和工时管家系统。使用客户遍布全国,软件获得了广泛好评。公司一直在技术方向不断积累和创新,获得了16项软著,3项专利。
                             <br>
@@ -116,8 +116,9 @@
                         <h2>联系我们</h2>
                         <p>
                             邮编:211001<br>
-                            地址:南京市江宁区秣周东路12号未来网络小镇4号楼P318室<br>
-                            邮箱:3052894409@qq.com<br>
+                            地址:南京市江宁区秣周东路12号未来网络小镇2号楼P346室<br>
+                            邮箱:quyueting@huoshishanxin.com<br>
+                            QQ: 3052894409<br>
                         </p>
                     </div>
                 </div>
@@ -173,12 +174,12 @@
                     <div class="footer-col last">
                         <h4>&nbsp;&nbsp;类别</h4>
                         <ul class="list-unstyled li-space-lg p-small">
-                            <li class="media">
+                            <!-- <li class="media">
                                 <div class="media-body"><a href="./download.html" style="color: #f3f7fd;text-decoration:none;"><i class="fa fa-windows"></i>&nbsp;&nbsp;&nbsp;Windows版本</a></div>
                             </li>
                             <li class="media">
                                 <div class="media-body"><a href="./download.html" style="color: #f3f7fd;text-decoration:none;"><i class="fa fa-apple"></i>&nbsp;&nbsp;&nbsp;Mac版本</a></div>
-                            </li>
+                            </li> -->
                             <li class="media">
                                 <div class="media-body"><a href="http://worktime.ttkuaiban.com/#/login" target="_blank" style="color: #f3f7fd;text-decoration:none;"><i class="fa fa-edge"></i>&nbsp;&nbsp;&nbsp;管理后台</a></div>
                             </li>

+ 4 - 4
fhKeeper/formulahousekeeper/inva_4_tivo/download.html

@@ -3,8 +3,8 @@
 <head>
     <meta charset="utf-8">
     <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-    <meta name="keywords" content="工时管理,工时统计,项目成本统计,远程监控" />
-    <meta name="description" content="工时管家利用智能图像识别技术实现工时管理和工时统计。可按项目,部门,岗位等多维度统计成本。软件可实现远程监管,有效反馈工作实际情况,对非工作情况主动检测上报。"/>
+    <meta name="keywords" content="工时管理,工时统计,项目成本统计" />
+    <meta name="description" content="工时管家提供专业的工时填报和统计报表。可按项目,部门,岗位等多维度统计成本。"/>
     <title>工时管家-工时管理和统计的好助手,反馈真实工作情况,降低企业成本!</title>
     <link href="https://fonts.googleapis.com/css?family=Open+Sans:400,400i,700&display=swap&subset=latin-ext" rel="stylesheet">
     <link href="css/bootstrap.css" rel="stylesheet">
@@ -45,9 +45,9 @@
                     <li class="nav-item">
                         <a class="nav-link page-scroll" href="./index.html#pricing">产品定价</a>
                     </li>
-                    <li class="nav-item">
+                    <!-- <li class="nav-item">
                         <a class="nav-link page-scroll active" href="./download.html">软件下载</a>
-                    </li>
+                    </li> -->
                     <li class="nav-item">
                         <a class="nav-link page-scroll" href="./mobile.html">手机版</a>
                     </li>

BIN
fhKeeper/formulahousekeeper/inva_4_tivo/images/s1.png


BIN
fhKeeper/formulahousekeeper/inva_4_tivo/images/s10.png


BIN
fhKeeper/formulahousekeeper/inva_4_tivo/images/s11.png


BIN
fhKeeper/formulahousekeeper/inva_4_tivo/images/s12.png


BIN
fhKeeper/formulahousekeeper/inva_4_tivo/images/s2.png


BIN
fhKeeper/formulahousekeeper/inva_4_tivo/images/s3.png


BIN
fhKeeper/formulahousekeeper/inva_4_tivo/images/s4.png


BIN
fhKeeper/formulahousekeeper/inva_4_tivo/images/s5.png


BIN
fhKeeper/formulahousekeeper/inva_4_tivo/images/s6.png


BIN
fhKeeper/formulahousekeeper/inva_4_tivo/images/s7.png


BIN
fhKeeper/formulahousekeeper/inva_4_tivo/images/s8.png


BIN
fhKeeper/formulahousekeeper/inva_4_tivo/images/s9.png


+ 69 - 57
fhKeeper/formulahousekeeper/inva_4_tivo/index.html

@@ -3,9 +3,9 @@
 <head>
     <meta charset="utf-8">
     <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-    <meta name="keywords" content="工时管理,工时统计,工时填报,项目成本统计,远程监控,生产工时管理系统,工时成本管理,工时管理软件,研发工时管理系统,企业工时管理系统,项目工时统计,项目工时统计软件,项目工时统计系统,工时统计系统,工时统计表" />
-    <meta name="description" content="工时管家利用智能图像识别技术实现工时管理和工时统计。支持PC和手机端。可按项目,部门,岗位等多维度统计成本。软件可实现远程监管,有效反馈工作实际情况,对非工作情况主动检测上报。"/>
-    <title>工时管家-专注工时管理,手机移动填报,降低企业成本!</title>
+    <meta name="keywords" content="工时管理,工时统计,工时填报,项目成本统计,人员成本统计,生产工时管理系统,工时成本管理,工时管理软件,研发工时管理系统,企业工时管理系统,项目工时统计,项目工时统计软件,项目工时统计系统,工时统计系统,工时统计表" />
+    <meta name="description" content="工时管家提供专业的工时填报和统计报表。支持PC和手机端。可按项目,部门,岗位等多维度统计成本。"/>
+    <title>工时管家-专注工时管理,手机移动填报,核算项目投入人力成本,企业IPO利器!</title>
     <link href="https://fonts.googleapis.com/css?family=Open+Sans:400,400i,700&display=swap&subset=latin-ext" rel="stylesheet">
     <link href="css/bootstrap.css" rel="stylesheet">
     <!-- <link href="css/fontawesome-all.css" rel="stylesheet"> -->
@@ -59,7 +59,7 @@
                         <a class="nav-link page-scroll" href="#pricing">产品定价</a>
                     </li>
                     <li class="nav-item">
-                        <a class="nav-link page-scroll" href="./download.html">软件下载</a>
+                        <!-- <a class="nav-link page-scroll" href="./download.html">软件下载</a> -->
                     </li>
                     <li class="nav-item">
                         <a class="nav-link page-scroll" href="./mobile.html">手机版</a>
@@ -88,15 +88,22 @@
                 <div class="row">
                     <div class="col-lg-12 col-xl-12">
                         <div class="text-container">
-                            <h2 style="color: #fff;">专注工时管理,AI智能升级</h2>
+                            <h2 style="color: #fff;">专注工时管理,数据客观真实,企业IPO利器</h2>
                             <div class="image-z">
                                 <img src="images/z2.png">
                                 <span>专业&nbsp;&nbsp;&nbsp;&nbsp;·&nbsp;&nbsp;&nbsp;&nbsp;安全&nbsp;&nbsp;&nbsp;&nbsp;·&nbsp;&nbsp;&nbsp;&nbsp;移动&nbsp;&nbsp;&nbsp;&nbsp;·&nbsp;&nbsp;&nbsp;&nbsp;便捷</span>
                                 <img src="images/z1.png">
                             </div>
-                            <p class="p-large">为工时填报/审核/统计提供专业解决方案,支持PC端和<b>手机端</b>。独创<b>智能图像识别</b>技术,能有效提高团队<b>工作饱和度</b>。基于项目/部门/岗位<b>多维度统计</b>工时,核算企业人力成本。</p>
+                            <p class="p-large">为工时填报/审核/统计提供专业解决方案,支持PC端和<b>手机端</b>。基于项目/部门/岗位<b>多维度统计</b>工时,实现可视化工时数据展示。</p>
                             <div class="col-lg-9 col-md-9 col-xl-9" style="margin: 0 auto;">
-                                <a class="btn-solid-lg btn-solid-lg-white page-scroll" style="margin-right: 5rem;" data-toggle="modal" data-target=".bs-example-modal-lg">视频演示</a>
+                                <a class="btn-solid-lg btn-solid-lg-white page-scroll overload" style="margin-right: 5rem;">软件演示
+                                    <div class="service">
+                                        <p style="color: #333">扫码获取演示账号</p>
+                                        <img src="./images/code.jpg">
+                                        <p><span style="color: #333">QQ:</span>3052894409</p>
+                                    </div>
+                                </a>
+                            
                                 <a class="btn-solid-lg page-scroll" style="margin-right: 5rem;" href="http://worktime.ttkuaiban.com/#/login" target="_blank">免费使用</a>
                                 <a class="btn-solid-lg page-scroll" href="./mobile.html" target="_blank">手机版</a>
                             </div>
@@ -124,26 +131,28 @@
             </div>
             <div class="row">
                 <div class="col-lg-12">
-                    <div class="scenes card">
-                        <div class="scenes-head">
-                            <img class="img-fluid" src="images/pic_0.png" alt="alternative">
-                            员工在家办公
-                        </div>
-                        <div class="scenes-body">
-                            <img class="img-fluid" src="images/pic_1.png" alt="alternative">
-                            <p>构建可视化办公,工作情况领导可及时了解,灵活安排工作。</p>
-                        </div>
-                    </div>
-                    <div class="scenes card">
-                        <div class="scenes-head">
-                            <img class="img-fluid" src="images/pic_0.png" alt="alternative">
-                            企业成本统计
+                        <div class="scenes card">
+                            <div class="scenes-head">
+                                <img class="img-fluid" src="images/pic_0.png" alt="alternative">
+                                企业IPO审计,老板
+                            </div>
+                            <div class="scenes-body">
+                                <img class="img-fluid" src="images/pic_2.png" alt="alternative">
+                                <p>核算各个项目人力成本,提供审计认可的真实数据。</p>
+                            </div>
                         </div>
-                        <div class="scenes-body">
-                            <img class="img-fluid" src="images/pic_2.png" alt="alternative">
-                            <p>核算各个部门,不同岗位的成本,建立预算基线。</p>
+
+                        <div class="scenes card">
+                            <div class="scenes-head">
+                                <img class="img-fluid" src="images/pic_0.png" alt="alternative">
+                                生产车间工时核算
+                            </div>
+                            <div class="scenes-body">
+                                <img class="img-fluid" src="images/pic_1.png" alt="alternative">
+                                <p>构建可视化车间,工作情况领导可及时了解,准确核发薪资。</p>
+                            </div>
                         </div>
-                    </div>
+                        
                 </div>
             </div>
             <div class="row">
@@ -184,11 +193,11 @@
                 <div class="col-lg-12">
                     <div class="card">
                         <div class="card-image">
-                            <img class="img-fluid" src="images/1.png" alt="alternative">
+                            <img class="img-fluid" src="images/3.png" alt="alternative">
                         </div>
                         <div class="card-body">
-                            <h4 class="card-title">智能监控</h4>
-                            <p>远程查看员工桌面<br>自动分析工作内容<br>研发/设计/聊天/非工作情况等智能识别</p>
+                            <h4 class="card-title">工时日报</h4>
+                            <p>员工填写工时日报<br>领导在线查看审批<br>支持微信端方便快捷</p>
                         </div>
                     </div>
                     <div class="card">
@@ -197,16 +206,16 @@
                         </div>
                         <div class="card-body">
                             <h4 class="card-title">成本统计</h4>
-                            <p>从项目、部门和岗位多个维度<br>统计工作时长和成本<br>数据可视化</p>
+                            <p>从项目、部门和岗位多个维度<br>统计工作时长和成本<br>可视化显示,可导出报表</p>
                         </div>
                     </div>
                     <div class="card">
                         <div class="card-image">
-                            <img class="img-fluid" src="images/3.png" alt="alternative">
+                            <img class="img-fluid" src="images/1.png" alt="alternative">
                         </div>
                         <div class="card-body">
-                            <h4 class="card-title">工时日报</h4>
-                            <p>员工填写工时日报<br>领导在线查看审批<br>随时了解工作进度</p>
+                            <h4 class="card-title">财务核算</h4>
+                            <p>每月导入财务实际成本<br>包含五险一金,奖金等<br>按工时自动分摊到项目上</p>
                         </div>
                     </div>
                 </div>
@@ -227,8 +236,8 @@
                             <img class="img-fluid" src="images/5.png" alt="alternative">
                         </div>
                         <div class="card-body">
-                            <h4 class="card-title">员工绩效</h4>
-                            <p>深入分析员工工作状态<br>比对标准工作时间<br>智能计算员工绩效</p>
+                            <h4 class="card-title">组织结构</h4>
+                            <p>多级部门层级<br>支持批量导入员工<br>员工和领导权限分离</p>
                         </div>
                     </div>
                     <div class="card">
@@ -236,8 +245,8 @@
                             <img class="img-fluid" src="images/6.png" alt="alternative">
                         </div>
                         <div class="card-body">
-                            <h4 class="card-title">自觉养成</h4>
-                            <p>工时管家这个隐形之眼<br>对员工进行警示与督促作用<br>使其无形中养成自省的习惯</p>
+                            <h4 class="card-title">填报时间按需设定</h4>
+                            <p>支持全天/上午/下午便捷模式<br>支持填报小时数自由选择<br>支持时间段范围自由选择</p>
                         </div>
                     </div>
                 </div>
@@ -253,28 +262,31 @@
                         <div class="swiper-container text-slider">
                             <div class="swiper-wrapper">
                                 <div class="swiper-slide">
-                                    <img class="img-fluid" src="images/banner_1.png" alt="">
+                                    <img class="img-fluid" src="images/s1.png" alt="">
                                 </div>
                                 <div class="swiper-slide">
-                                    <img class="img-fluid" src="images/banner_2.png" alt="">
+                                    <img class="img-fluid" src="images/s12.png" alt="">
                                 </div>
                                 <div class="swiper-slide">
-                                    <img class="img-fluid" src="images/banner_3.png" alt="">
+                                    <img class="img-fluid" src="images/s2.png" alt="">
                                 </div>
                                 <div class="swiper-slide">
-                                    <img class="img-fluid" src="images/banner_4.png" alt="">
+                                    <img class="img-fluid" src="images/s10.png" alt="">
                                 </div>
                                 <div class="swiper-slide">
-                                    <img class="img-fluid" src="images/banner_5.png" alt="">
+                                    <img class="img-fluid" src="images/s8.png" alt="">
                                 </div>
                                 <div class="swiper-slide">
-                                    <img class="img-fluid" src="images/banner_6.png" alt="">
+                                    <img class="img-fluid" src="images/s11.png" alt="">
                                 </div>
                                 <div class="swiper-slide">
-                                    <img class="img-fluid" src="images/banner_7.png" alt="">
+                                    <img class="img-fluid" src="images/s6.png" alt="">
                                 </div>
                                 <div class="swiper-slide">
-                                    <img class="img-fluid" src="images/banner_8.png" alt="">
+                                    <img class="img-fluid" src="images/s7.png" alt="">
+                                </div>
+                                <div class="swiper-slide">
+                                    <img class="img-fluid" src="images/s5.png" alt="">
                                 </div>
                             </div>
                             <div class="swiper-button-next"></div>
@@ -303,10 +315,10 @@
                             <div class="divider"></div>
                             <ul class="list-unstyled li-space-lg">
                                 <li class="media">
-                                    <div class="media-body"><i class="fa fa-check"></i>&nbsp;&nbsp;&nbsp;免费支持</div>
+                                    <div class="media-body"><i class="fa fa-check"></i>&nbsp;&nbsp;&nbsp;技术支持</div>
                                 </li>
                                 <li class="media">
-                                    <div class="media-body"><i class="fa fa-check"></i>&nbsp;&nbsp;&nbsp;5G带宽</div>
+                                    <div class="media-body"><i class="fa fa-check"></i>&nbsp;&nbsp;&nbsp;5G空间</div>
                                 </li>
                             </ul>
                             <div class="button-wrapper">
@@ -317,15 +329,15 @@
                     <div class="card">
                         <div class="card-body">
                             <div class="card-title">10人以内</div>
-                            <div class="price"><span class="currency">¥</span><span class="value">1800</span></div>
+                            <div class="price"><span class="currency">¥</span><span class="value">2500</span></div>
                             <div class="frequency">一年</div>
                             <div class="divider"></div>
                             <ul class="list-unstyled li-space-lg">
                                 <li class="media">
-                                    <div class="media-body"><i class="fa fa-check"></i>&nbsp;&nbsp;&nbsp;免费支持</div>
+                                    <div class="media-body"><i class="fa fa-check"></i>&nbsp;&nbsp;&nbsp;技术支持</div>
                                 </li>
                                 <li class="media">
-                                    <div class="media-body"><i class="fa fa-check"></i>&nbsp;&nbsp;&nbsp;5G带宽</div>
+                                    <div class="media-body"><i class="fa fa-check"></i>&nbsp;&nbsp;&nbsp;20G空间</div>
                                 </li>
                             </ul>
                             <div class="button-wrapper">
@@ -337,15 +349,15 @@
                     <div class="card">
                         <div class="card-body">
                             <div class="card-title">30人以内</div>
-                            <div class="price"><span class="currency">¥</span><span class="value">5000</span></div>
+                            <div class="price"><span class="currency">¥</span><span class="value">7000</span></div>
                             <div class="frequency">一年</div>
                             <div class="divider"></div>
                             <ul class="list-unstyled li-space-lg">
                                 <li class="media">
-                                    <div class="media-body"><i class="fa fa-check"></i>&nbsp;&nbsp;&nbsp;免费支持</div>
+                                    <div class="media-body"><i class="fa fa-check"></i>&nbsp;&nbsp;&nbsp;技术支持</div>
                                 </li>
                                 <li class="media">
-                                    <div class="media-body"><i class="fa fa-check"></i>&nbsp;&nbsp;&nbsp;10G带宽</div>
+                                    <div class="media-body"><i class="fa fa-check"></i>&nbsp;&nbsp;&nbsp;50G空间</div>
                                 </li>
                             </ul>
                             <div class="button-wrapper">
@@ -357,15 +369,15 @@
                     <div class="card">
                         <div class="card-body">
                             <div class="card-title">50人以内</div>
-                            <div class="price"><span class="currency">¥</span><span class="value">8000</span></div>
+                            <div class="price"><span class="currency">¥</span><span class="value">10000</span></div>
                             <div class="frequency">一年</div>
                             <div class="divider"></div>
                             <ul class="list-unstyled li-space-lg">
                                 <li class="media">
-                                    <div class="media-body"><i class="fa fa-check"></i>&nbsp;&nbsp;&nbsp;免费支持</div>
+                                    <div class="media-body"><i class="fa fa-check"></i>&nbsp;&nbsp;&nbsp;技术支持</div>
                                 </li>
                                 <li class="media">
-                                    <div class="media-body"><i class="fa fa-check"></i>&nbsp;&nbsp;&nbsp;50G带宽</div>
+                                    <div class="media-body"><i class="fa fa-check"></i>&nbsp;&nbsp;&nbsp;100G空间</div>
                                 </li>
                             </ul>
                             <div class="button-wrapper">
@@ -461,12 +473,12 @@
                     <div class="footer-col last">
                         <h4>&nbsp;&nbsp;类别</h4>
                         <ul class="list-unstyled li-space-lg p-small">
-                            <li class="media">
+                            <!-- <li class="media">
                                 <div class="media-body"><a href="./download.html" style="color: #f3f7fd;text-decoration:none;"><i class="fa fa-windows"></i>&nbsp;&nbsp;&nbsp;Windows版本</a></div>
                             </li>
                             <li class="media">
                                 <div class="media-body"><a href="./download.html" style="color: #f3f7fd;text-decoration:none;"><i class="fa fa-apple"></i>&nbsp;&nbsp;&nbsp;Mac版本</a></div>
-                            </li>
+                            </li> -->
                             <li class="media">
                                 <div class="media-body"><a href="http://worktime.ttkuaiban.com/#/login" target="_blank" style="color: #f3f7fd;text-decoration:none;"><i class="fa fa-edge"></i>&nbsp;&nbsp;&nbsp;管理后台</a></div>
                             </li>

+ 7 - 7
fhKeeper/formulahousekeeper/inva_4_tivo/mobile.html

@@ -3,9 +3,9 @@
 <head>
     <meta charset="utf-8">
     <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-    <meta name="keywords" content="工时管理,工时统计,项目成本统计,远程监控" />
-    <meta name="description" content="工时管家利用智能图像识别技术实现工时管理和工时统计。可按项目,部门,岗位等多维度统计成本。软件可实现远程监管,有效反馈工作实际情况,对非工作情况主动检测上报。"/>
-    <title>工时管家-工时管理和统计的好助手,反馈真实工作情况,降低企业成本!</title>
+    <meta name="keywords" content="工时管理,工时统计,项目成本统计" />
+    <meta name="description" content="工时管家提供专业的工时填报和统计报表。可按项目,部门,岗位等多维度统计成本。"/>
+    <title>工时管家-专注工时管理,手机移动填报,核算项目投入人力成本,企业IPO利器!</title>
     <link href="https://fonts.googleapis.com/css?family=Open+Sans:400,400i,700&display=swap&subset=latin-ext" rel="stylesheet">
     <link href="css/bootstrap.css" rel="stylesheet">
     <!-- <link href="css/fontawesome-all.css" rel="stylesheet"> -->
@@ -45,9 +45,9 @@
                     <li class="nav-item">
                         <a class="nav-link page-scroll" href="./index.html#pricing">产品定价</a>
                     </li>
-                    <li class="nav-item">
+                    <!-- <li class="nav-item">
                         <a class="nav-link page-scroll" href="./download.html">软件下载</a>
-                    </li>
+                    </li> -->
                     <li class="nav-item">
                         <a class="nav-link page-scroll active" href="./mobile.html">手机版</a>
                     </li>
@@ -138,12 +138,12 @@
                     <div class="footer-col last">
                         <h4>&nbsp;&nbsp;类别</h4>
                         <ul class="list-unstyled li-space-lg p-small">
-                            <li class="media">
+                            <!-- <li class="media">
                                 <div class="media-body"><a href="./download.html" style="color: #f3f7fd;text-decoration:none;"><i class="fa fa-windows"></i>&nbsp;&nbsp;&nbsp;Windows版本</a></div>
                             </li>
                             <li class="media">
                                 <div class="media-body"><a href="./download.html" style="color: #f3f7fd;text-decoration:none;"><i class="fa fa-apple"></i>&nbsp;&nbsp;&nbsp;Mac版本</a></div>
-                            </li>
+                            </li> -->
                             <li class="media">
                                 <div class="media-body"><a href="http://worktime.ttkuaiban.com/#/login" target="_blank" style="color: #f3f7fd;text-decoration:none;"><i class="fa fa-edge"></i>&nbsp;&nbsp;&nbsp;管理后台</a></div>
                             </li>

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

@@ -75,8 +75,8 @@ public class DepartmentController {
      * 获取顶级项目及其统计
      */
     @RequestMapping("/departmentStatistic")
-    public HttpRespMsg getDepartmentStatistics(HttpServletRequest request) {
-        return departmentService.getDepartmentStatistics(request);
+    public HttpRespMsg getDepartmentStatistics(String startDate, String endDate, HttpServletRequest request) {
+        return departmentService.getDepartmentStatistics(startDate, endDate, request);
     }
 
     /**
@@ -84,8 +84,8 @@ public class DepartmentController {
      * departmentId 要查询的项目
      */
     @RequestMapping("/userStatistic")
-    public HttpRespMsg getUserStatistics(@RequestParam Integer departmentId, HttpServletRequest request) {
-        return departmentService.getUserStatistics(departmentId, request);
+    public HttpRespMsg getUserStatistics(String startDate, String endDate, @RequestParam Integer departmentId, HttpServletRequest request) {
+        return departmentService.getUserStatistics(startDate, endDate, departmentId, request);
     }
 }
 

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

@@ -53,6 +53,7 @@ public class ProjectController {
      */
     @RequestMapping("/editProject")
     public HttpRespMsg editProject(Integer id, @RequestParam String name, String code,  String[] userId, String inchargerId) {
+
         return projectService.editProject(id, name, code, userId, inchargerId, request);
     }
 
@@ -69,16 +70,16 @@ public class ProjectController {
      * 获取查询者所在公司每个项目的工时成本
      */
     @RequestMapping("/getTimeCost")
-    public HttpRespMsg getTimeCost() {
-        return projectService.getTimeCost(request);
+    public HttpRespMsg getTimeCost(String startDate, String endDate) {
+        return projectService.getTimeCost(startDate, endDate, request);
     }
 
     /**
      * 导出查询者所在公司每个项目的工时成本
      */
     @RequestMapping("/exportTimeCost")
-    public HttpRespMsg exportTimeCost() {
-        return projectService.exportTimeCost(request);
+    public HttpRespMsg exportTimeCost(@RequestParam String startDate, @RequestParam String endDate) {
+        return projectService.exportTimeCost(startDate, endDate, request);
     }
 
     /**
@@ -86,8 +87,8 @@ public class ProjectController {
      * id 项目id
      */
     @RequestMapping("/getProjectCost")
-    public HttpRespMsg getProjectCost(@RequestParam Integer id) {
-        return projectService.getProjectCost(id, request);
+    public HttpRespMsg getProjectCost(String startDate, String endDate, @RequestParam Integer id) {
+        return projectService.getProjectCost(startDate, endDate, id, request);
     }
 }
 

+ 148 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ProjectTimerController.java

@@ -0,0 +1,148 @@
+package com.management.platform.controller;
+
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.management.platform.entity.ProjectTimer;
+import com.management.platform.entity.Report;
+import com.management.platform.entity.User;
+import com.management.platform.mapper.ProjectTimerMapper;
+import com.management.platform.mapper.ReportMapper;
+import com.management.platform.mapper.UserMapper;
+import com.management.platform.service.ProjectService;
+import com.management.platform.util.HttpRespMsg;
+import org.apache.log4j.helpers.DateTimeDateFormat;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
+import java.util.List;
+
+/**
+ * <p>
+ *  前端控制器
+ * </p>
+ *
+ * @author Seyason
+ * @since 2021-03-17
+ */
+@RestController
+@RequestMapping("/project-timer")
+public class ProjectTimerController {
+    @Resource
+    private ProjectTimerMapper projectTimerMapper;
+    @Resource
+    private ReportMapper reportMapper;
+    @Resource
+    private UserMapper userMapper;
+    @Resource
+    private HttpServletRequest request;
+
+    /**
+     * 获取定时器
+     */
+    @RequestMapping("/getMyTimer")
+    public HttpRespMsg getMyTimer() {
+        QueryWrapper<ProjectTimer> query = new QueryWrapper<ProjectTimer>();
+        String userId = request.getHeader("Token");
+
+        query.eq("user_id", userId);
+        query.orderByDesc("id");
+        HttpRespMsg msg = new HttpRespMsg();
+        List<ProjectTimer> list = projectTimerMapper.selectList(query);
+        LocalDateTime now = LocalDateTime.now();
+        list.forEach(t->{
+            if (t.getEndTime() == null) {
+                t.setTimer(now.toEpochSecond(ZoneOffset.ofHours(8)) - t.getStartTime().toEpochSecond(ZoneOffset.ofHours(8)));
+            } else {
+                t.setTimer(t.getEndTime().toEpochSecond(ZoneOffset.ofHours(8)) - t.getStartTime().toEpochSecond(ZoneOffset.ofHours(8)));
+            }
+        });
+        msg.data = list;
+        return msg;
+    }
+
+    @RequestMapping("/addTimer")
+    public HttpRespMsg addTimer(ProjectTimer timer) {
+        String userId = request.getHeader("Token");
+        timer.setUserId(userId);
+        timer.setStartTime(LocalDateTime.now());
+        projectTimerMapper.insert(timer);
+        HttpRespMsg msg = new HttpRespMsg();
+        msg.data = timer;
+        return msg;
+    }
+
+
+    @RequestMapping("/deleteTimer")
+    public HttpRespMsg deleteTimer(Integer id) {
+        String userId = request.getHeader("Token");
+        HttpRespMsg msg = new HttpRespMsg();
+        ProjectTimer timer = projectTimerMapper.selectById(id);
+        if (!timer.getUserId().equals(userId)) {
+            msg.setError("非创建人无权删除");
+        } else {
+            projectTimerMapper.deleteById(id);
+        }
+        return msg;
+    }
+
+
+    @RequestMapping("/endTimer")
+    public HttpRespMsg endTimer(Integer id) {
+        String userId = request.getHeader("Token");
+        HttpRespMsg msg = new HttpRespMsg();
+        ProjectTimer timer = projectTimerMapper.selectById(id);
+        if (!timer.getUserId().equals(userId)) {
+            msg.setError("非创建人无权结束");
+        } else {
+            timer.setEndTime(LocalDateTime.now());
+            projectTimerMapper.updateById(timer);
+            msg.data = timer;
+        }
+        return msg;
+    }
+
+    @RequestMapping("/tranferToReport")
+    public HttpRespMsg tranferToReport(Integer id, String content) {
+        String userId = request.getHeader("Token");
+        User user = userMapper.selectById(userId);
+        HttpRespMsg msg = new HttpRespMsg();
+        ProjectTimer timer = projectTimerMapper.selectById(id);
+        if (!timer.getUserId().equals(userId)) {
+            msg.setError("非创建人无权操作");
+        } else {
+            //创建日报
+            DateTimeFormatter df = DateTimeFormatter.ofPattern("HH:mm");
+            Report report = new Report();
+            report.setSubProjectId(timer.getSubProjectId());
+            report.setProjectId(timer.getProjectId());
+            report.setCreatorId(timer.getUserId());
+            report.setContent(content);
+            report.setCreateDate(timer.getStartTime().toLocalDate());
+            report.setStartTime(df.format(timer.getStartTime()));
+            report.setEndTime(df.format(timer.getEndTime()));
+            report.setReportTimeType(2);//2-按时间段录入
+            //计算时长
+            long time = timer.getEndTime().toEpochSecond(ZoneOffset.ofHours(8)) - timer.getStartTime().toEpochSecond(ZoneOffset.ofHours(8));
+            int minutes = (int)time/60;
+            double hours = minutes*1.0f/60;
+            report.setWorkingTime(hours);
+            report.setCost(user.getCost().multiply(new BigDecimal(hours)));
+
+            reportMapper.insert(report);
+            timer.setReportId(report.getId());
+            projectTimerMapper.updateById(timer);
+            msg.data = timer;
+        }
+        return msg;
+    }
+
+}
+

+ 55 - 15
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ReportController.java

@@ -13,6 +13,7 @@ import org.springframework.web.bind.annotation.RestController;
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
 import java.math.BigDecimal;
+import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.time.LocalDate;
 import java.time.format.DateTimeFormatter;
@@ -75,24 +76,51 @@ public class ReportController {
      * createDate 报告日期 数组
      */
     @RequestMapping("/editReport")
-    public HttpRespMsg editReport(Integer[] id, Integer[] projectId, Double[] workingTime, String[] content,
+    public HttpRespMsg editReport(Integer[] id, Integer[] projectId,
+                                  Integer[] subProjectId,
+                                  Double[] workingTime,
+                                  String[] content,
                                   Integer[] timeType,
+                                  String[] startTime,
+                                  String[] endTime,
+                                  Integer[] reportTimeType,
                                   String[] createDate) {
         List<Report> reportList = new ArrayList<>();
         String token = request.getHeader("Token");
         BigDecimal hourCost = userService.getById(token).getCost();
+        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
         try {
             for (int i = 0; i < id.length; i++) {
-                reportList.add(new Report()
+                Report report = new Report()
                         .setId(id[i] == -1 ? null : id[i])
                         .setProjectId(projectId[i])
-                        .setWorkingTime(workingTime[i])
-                        .setCost(hourCost.multiply(new BigDecimal(workingTime[i])))
-                        .setTimeType(timeType[i])
+                        .setSubProjectId(subProjectId[i] == 0?null:subProjectId[i])
+                        .setReportTimeType(reportTimeType[i])
                         .setContent(content[i])
                         .setState(0)
                         .setCreateDate(LocalDate.parse(createDate[i], DateTimeFormatter.ofPattern("yyyy-MM-dd")))
-                        .setCreatorId(token));
+                        .setCreatorId(token);
+                if (report.getReportTimeType() == 0) {
+                    report.setWorkingTime(workingTime[i])
+                            .setCost(hourCost.multiply(new BigDecimal(workingTime[i])))
+                            .setTimeType(timeType[i]);
+                } else if (report.getReportTimeType() == 1) {
+                    report.setWorkingTime(workingTime[i])
+                            .setCost(hourCost.multiply(new BigDecimal(workingTime[i])));
+                } else if (report.getReportTimeType() == 2) {
+                    //时间范围填报, 计算一下时长
+                    try {
+                        report.setStartTime(startTime[i]).setEndTime(endTime[i]);
+                        long time = sdf.parse(report.getEndTime()).getTime() - sdf.parse(report.getStartTime()).getTime();
+                        int minutes = (int)time/1000/60;
+                        double hours = minutes*1.0f/60;
+                        report.setWorkingTime(hours);
+                        report.setCost(hourCost.multiply(new BigDecimal(hours)));
+                    } catch (ParseException e) {
+                        e.printStackTrace();
+                    }
+                }
+                reportList.add(report);
                 /*后续需要加入状态*/
                 if (createDate[i] == null || projectId[i] == null) {
                     HttpRespMsg httpRespMsg = new HttpRespMsg();
@@ -101,6 +129,7 @@ public class ReportController {
                 }
             }
         } catch (NullPointerException e) {
+            e.printStackTrace();
             HttpRespMsg httpRespMsg = new HttpRespMsg();
             httpRespMsg.setError("验证失败");
             return httpRespMsg;
@@ -112,9 +141,9 @@ public class ReportController {
      * 删除报告
      * id 要删除的报告的id
      */
-    @RequestMapping("/deleteReport")
-    public HttpRespMsg deleteReport(@RequestParam Integer id) {
-        return reportService.deleteReport(id);
+    @RequestMapping("/delete")
+    public HttpRespMsg deleteReport(String userId, String date) {
+        return reportService.deleteReport(userId, date);
     }
 
     /**
@@ -132,8 +161,8 @@ public class ReportController {
      * date 日期 格式yyyy-mm-dd
      */
     @RequestMapping("/approve")
-    public HttpRespMsg approveReport(@RequestParam String id, @RequestParam String date, HttpServletRequest request) {
-        return reportService.approveReport(id, date, request);
+    public HttpRespMsg approveReport(@RequestParam String id, @RequestParam String date, @RequestParam String reportIds,HttpServletRequest request) {
+        return reportService.approveReport(id, date,reportIds, request);
     }
 
     /**
@@ -142,8 +171,19 @@ public class ReportController {
      * date 日期 格式yyyy-mm-dd
      */
     @RequestMapping("/deny")
-    public HttpRespMsg denyReport(@RequestParam String id, @RequestParam String date, HttpServletRequest request) {
-        return reportService.denyReport(id, date, request);
+    public HttpRespMsg denyReport(@RequestParam String id, @RequestParam String date, @RequestParam String reportIds, HttpServletRequest request) {
+        return reportService.denyReport(id, date,reportIds, request);
+    }
+
+    /**
+     * 撤回报告
+     * @param reportIds
+     * @param request
+     * @return
+     */
+    @RequestMapping("/cancel")
+    public HttpRespMsg cancelReport(@RequestParam String userId, @RequestParam String reportIds,HttpServletRequest request) {
+        return reportService.cancelReport(userId, reportIds, request);
     }
 
     /**
@@ -174,8 +214,8 @@ public class ReportController {
     }
 
     @RequestMapping("/batchApproveReport")
-    public HttpRespMsg batchApproveReport(@RequestParam String ids, @RequestParam String date, HttpServletRequest request) {
-        return reportService.batchApproveReport(ids, date, request);
+    public HttpRespMsg batchApproveReport(@RequestParam String ids, HttpServletRequest request) {
+        return reportService.batchApproveReport(ids, request);
     }
 }
 

+ 85 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/SubProjectController.java

@@ -0,0 +1,85 @@
+package com.management.platform.controller;
+
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.management.platform.entity.ProjectTimer;
+import com.management.platform.entity.SubProject;
+import com.management.platform.mapper.ProjectTimerMapper;
+import com.management.platform.service.ProjectService;
+import com.management.platform.service.SubProjectService;
+import com.management.platform.util.HttpRespMsg;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * <p>
+ *  前端控制器
+ * </p>
+ *
+ * @author Seyason
+ * @since 2021-03-17
+ */
+@RestController
+@RequestMapping("/sub-project")
+public class SubProjectController {
+    @Autowired
+    private SubProjectService subProjectService;
+    @Resource
+    private ProjectTimerMapper projectTimerMapper;
+
+    /**
+     * 获取子项目列表
+     */
+    @RequestMapping("/list")
+    public HttpRespMsg list(Integer projectId) {
+        HttpRespMsg msg = new HttpRespMsg();
+        msg.data = subProjectService.list(new QueryWrapper<SubProject>().eq("project_id", projectId));
+        return msg;
+    }
+
+    /**
+     * 添加或编辑项目
+     * id 要编辑项目的id 可填
+     * name 子项目的名称
+     * projectId 父项目id
+     */
+    @RequestMapping("/saveOrUpdate")
+    public HttpRespMsg saveOrUpdate(SubProject item) {
+        subProjectService.saveOrUpdate(item);
+        if (item.getId() != null) {
+            //修改相关表
+            ProjectTimer timer = new ProjectTimer();
+            timer.setSubProjectName(item.getName());
+            projectTimerMapper.update(timer, new QueryWrapper<ProjectTimer>().eq("sub_project_id", item.getId()));
+        }
+        return new HttpRespMsg();
+    }
+
+    /**
+     * 删除项目
+     * id 要删除的项目的id
+     */
+    @RequestMapping("/deleteProject")
+    public HttpRespMsg deleteProject(@RequestParam Integer id) {
+        subProjectService.removeById(id);
+        return new HttpRespMsg();
+    }
+
+    /**
+     * 查询某个项目内子项目的统计成本
+     * @param startDate
+     * @param endDate
+     * @return
+     */
+    @RequestMapping("/getTimeCost")
+    public HttpRespMsg getTimeCost(String startDate, String endDate, Integer id) {
+        return subProjectService.getTimeCost(startDate, endDate,id);
+    }
+}
+

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

@@ -113,8 +113,8 @@ public class UserController {
      */
     @RequestMapping("/insertUser")
     public HttpRespMsg insertUser(String id, @RequestParam String name, @RequestParam String phone,
-                                  @RequestParam Integer role, Double monthCost, Double cost, Integer departmentId) {
-        return userService.insertUser(id, name, phone, role, monthCost, cost, departmentId, request);
+                                  @RequestParam Integer role, Double monthCost, Double cost, Integer departmentId, Integer salaryType) {
+        return userService.insertUser(id, name, phone, role, monthCost, cost, departmentId, salaryType, request);
     }
 
     /**

+ 83 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/ProjectTimer.java

@@ -0,0 +1,83 @@
+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;
+
+/**
+ * <p>
+ * 
+ * </p>
+ *
+ * @author Seyason
+ * @since 2021-03-18
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class ProjectTimer extends Model<ProjectTimer> {
+
+    private static final long serialVersionUID=1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    @TableField("project_id")
+    private Integer projectId;
+
+    @TableField("sub_project_id")
+    private Integer subProjectId;
+
+    @TableField("start_time")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime startTime;
+
+    @TableField("end_time")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime endTime;
+
+    @TableField("user_id")
+    private String userId;
+
+    /**
+     * 耗时(小时)
+     */
+    @TableField("time_cost")
+    private Double timeCost;
+
+    /**
+     * 日报id
+     */
+    @TableField("report_id")
+    private Integer reportId;
+
+    /**
+     * 项目名称
+     */
+    @TableField("project_name")
+    private String projectName;
+
+    /**
+     * 子项目名称
+     */
+    @TableField("sub_project_name")
+    private String subProjectName;
+
+
+    @Override
+    protected Serializable pkVal() {
+        return this.id;
+    }
+
+    @TableField(exist = false)
+    private long timer;
+
+}

+ 25 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/Report.java

@@ -18,7 +18,7 @@ import lombok.experimental.Accessors;
  * </p>
  *
  * @author Seyason
- * @since 2021-02-18
+ * @since 2021-03-17
  */
 @Data
 @EqualsAndHashCode(callSuper = false)
@@ -87,6 +87,30 @@ public class Report extends Model<Report> {
     @TableField("cost")
     private BigDecimal cost;
 
+    /**
+     * 开始时间
+     */
+    @TableField("start_time")
+    private String startTime;
+
+    /**
+     * 结束时间
+     */
+    @TableField("end_time")
+    private String endTime;
+
+    /**
+     * 员工填写时长类型
+     */
+    @TableField("report_time_type")
+    private Integer reportTimeType;
+
+    /**
+     * 子项目id
+     */
+    @TableField("sub_project_id")
+    private Integer subProjectId;
+
 
     @Override
     protected Serializable pkVal() {

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

@@ -0,0 +1,48 @@
+package com.management.platform.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableField;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 
+ * </p>
+ *
+ * @author Seyason
+ * @since 2021-03-17
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class SubProject extends Model<SubProject> {
+
+    private static final long serialVersionUID=1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 子项目名称
+     */
+    @TableField("name")
+    private String name;
+
+    /**
+     * 项目id
+     */
+    @TableField("project_id")
+    private Integer projectId;
+
+
+    @Override
+    protected Serializable pkVal() {
+        return this.id;
+    }
+
+}

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

@@ -15,7 +15,7 @@ import lombok.experimental.Accessors;
  * </p>
  *
  * @author Seyason
- * @since 2021-02-13
+ * @since 2021-02-27
  */
 @Data
 @EqualsAndHashCode(callSuper = false)
@@ -54,6 +54,18 @@ public class TimeType extends Model<TimeType> {
     @TableField("month_days")
     private BigDecimal monthDays;
 
+    /**
+     * 时薪录入方式:0-按月薪计算,1-直接输入时薪
+     */
+    @TableField("hour_cost_input_type")
+    private Integer hourCostInputType;
+
+    /**
+     * 时长上报方式
+     */
+    @TableField("type")
+    private Integer type;
+
 
     @Override
     protected Serializable pkVal() {

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

@@ -16,7 +16,7 @@ import lombok.experimental.Accessors;
  * </p>
  *
  * @author Seyason
- * @since 2021-02-13
+ * @since 2021-02-27
  */
 @Data
 @EqualsAndHashCode(callSuper = false)
@@ -97,6 +97,13 @@ public class User extends Model<User> {
     @TableField("month_cost")
     private BigDecimal monthCost;
 
+    /**
+     * 薪资模式:0-固定月薪,1-计时工资
+     */
+    @TableField("salary_type")
+    private Integer salaryType;
+
+
     @TableField(exist = false)
     private String departmentName;
 

+ 3 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/vo/DepartmentMasterVO.java

@@ -5,10 +5,12 @@ import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.experimental.Accessors;
 
+import java.math.BigDecimal;
+
 @Data
 @EqualsAndHashCode(callSuper = false)
 @Accessors(chain = true)
 public class DepartmentMasterVO extends Department {
     private Double costTime;
-    private Double costMoney;
+    private BigDecimal costMoney;
 }

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

@@ -11,4 +11,6 @@ import lombok.experimental.Accessors;
 public class UserVO extends User {
     private String companyName;
     private Long remainingTime;
+    //是否是项目经理
+    private boolean isLeader;
 }

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

@@ -16,7 +16,7 @@ import java.util.Map;
  * @since 2020-02-11
  */
 public interface DepartmentMapper extends BaseMapper<Department> {
-    Map<String, Object> getCostByDepartment(@Param("departmentIds") List departmentIds);
+    Map<String, Object> getCostByDepartment(@Param("departmentIds") List departmentIds, String startDate, String endDate);
 
-    List<Map<String, Object>> getCostByUser(@Param("departmentIds") List departmentIds);
+    List<Map<String, Object>> getCostByUser(@Param("departmentIds") List departmentIds, String startDate, String endDate);
 }

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

@@ -18,7 +18,7 @@ import java.util.Map;
 public interface ProjectMapper extends BaseMapper<Project> {
     List<Map<String, Object>> getParticipatedProject(@Param("userId") String userId);
 
-    List<Map<String, Object>> getTimeCost(@Param("companyId") Integer companyId);
+    List<Map<String, Object>> getTimeCost(@Param("companyId") Integer companyId, @Param("startDate") String startDate, @Param("endDate") String endDate);
 
-    List<Map<String, Object>> getProjectCost(@Param("projectId") Integer projectId);
+    List<Map<String, Object>> getProjectCost(@Param("startDate") String startDate, @Param("endDate") String endDate, @Param("projectId") Integer projectId);
 }

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

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

+ 10 - 3
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/ReportMapper.java

@@ -20,16 +20,23 @@ import java.util.Map;
 public interface ReportMapper extends BaseMapper<Report> {
     List<Map<String, Object>> getAllReportByDate(@Param("date") String date, @Param("companyId") Integer companyId, @Param("userId") String userId);
 
+    //按当前人员获取本人报告
     List<Map<String, Object>> getReportByDate(@Param("date") String date, @Param("id") String id);
+    //获取项目经理所管理的人员的报告
+    List<Map<String, Object>> getInchargeReportByDate(@Param("date") String date, @Param("id") String id, @Param("state") Integer state);
 
     List<Map<String, Object>> getUserReportByDate(@Param("date") String date, @Param("userIds") List<String> userIds);
 
-    List<Map<String, Object>> getReportNameByDate(@Param("date") String date, @Param("companyId") Integer companyId);
+    List<Map<String, Object>> getReportNameByDate(@Param("date") String date, @Param("companyId") Integer companyId, @Param("leaderId") String leaderId);
 
-    List<Map<String, Object>> getReportNameByDateAndDept(@Param("date") String date, @Param("deptIds") List<Integer> deptIds, @Param("userId") String userId);
+    List<Map<String, Object>> getReportNameByDateAndDept(@Param("date") String date,
+                                                         @Param("deptIds") List<Integer> deptIds,
+                                                         @Param("userId") String userId,
+                                                         @Param("companyId") Integer company);
 
     List<Map<String, Object>> getDetailByState(@Param("state") Integer state,
-                                               @Param("companyId") Integer companyId);
+                                               @Param("companyId") Integer companyId,
+                                                @Param("leaderId") String leaderId);
 
     List<Map<String, Object>> getRealProjectTime(@Param("startDate") LocalDateTime startDate, @Param("endDate") LocalDateTime endDate, Integer companyId);
 }

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

@@ -0,0 +1,20 @@
+package com.management.platform.mapper;
+
+import com.management.platform.entity.SubProject;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <p>
+ *  Mapper 接口
+ * </p>
+ *
+ * @author Seyason
+ * @since 2021-03-17
+ */
+public interface SubProjectMapper extends BaseMapper<SubProject> {
+    List<Map<String, Object>> getTimeCost(@Param("projectId") Integer projectId, @Param("startDate") String startDate, @Param("endDate") String endDate);
+}

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

@@ -25,7 +25,7 @@ public interface DepartmentService extends IService<Department> {
 
     HttpRespMsg getDepartmentList(HttpServletRequest request);
 
-    HttpRespMsg getDepartmentStatistics(HttpServletRequest request);
+    HttpRespMsg getDepartmentStatistics(String startDate, String endDate, HttpServletRequest request);
 
-    HttpRespMsg getUserStatistics(Integer departmentId, HttpServletRequest request);
+    HttpRespMsg getUserStatistics(String startDate, String endDate, Integer departmentId, HttpServletRequest request);
 }

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

@@ -23,9 +23,9 @@ public interface ProjectService extends IService<Project> {
 
     HttpRespMsg deleteProject(Integer id);
 
-    HttpRespMsg getTimeCost(HttpServletRequest request);
+    HttpRespMsg getTimeCost(String startDate, String endDate, HttpServletRequest request);
 
-    HttpRespMsg getProjectCost(Integer projectId, HttpServletRequest request);
+    HttpRespMsg getProjectCost(String startDate, String endDate, Integer projectId, HttpServletRequest request);
 
-    HttpRespMsg exportTimeCost(HttpServletRequest request);
+    HttpRespMsg exportTimeCost(String startDate, String endDate, HttpServletRequest request);
 }

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

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

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

@@ -25,13 +25,13 @@ public interface ReportService extends IService<Report> {
 
     HttpRespMsg editReport(List<Report> reportList, String date);
 
-    HttpRespMsg deleteReport(Integer reportId);
+    HttpRespMsg deleteReport(String userId, String date);
 
     HttpRespMsg getListByState(Integer state, HttpServletRequest request);
 
-    HttpRespMsg approveReport(String id, String date, HttpServletRequest request);
+    HttpRespMsg approveReport(String id, String date, String reportIds, HttpServletRequest request);
 
-    HttpRespMsg denyReport(String id, String date, HttpServletRequest request);
+    HttpRespMsg denyReport(String id, String date, String reportIds,HttpServletRequest request);
 
     HttpRespMsg singleApproveReport(Integer id, HttpServletRequest request);
 
@@ -39,5 +39,7 @@ public interface ReportService extends IService<Report> {
 
     HttpRespMsg getMembList(String date, HttpServletRequest request);
 
-    HttpRespMsg batchApproveReport(String ids, String date, HttpServletRequest request);
+    HttpRespMsg batchApproveReport(String ids, HttpServletRequest request);
+
+    HttpRespMsg cancelReport(String userId, String reportIds, HttpServletRequest request);
 }

+ 21 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/SubProjectService.java

@@ -0,0 +1,21 @@
+package com.management.platform.service;
+
+import com.management.platform.entity.SubProject;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.management.platform.util.HttpRespMsg;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * <p>
+ *  服务类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2021-03-17
+ */
+public interface SubProjectService extends IService<SubProject> {
+
+    HttpRespMsg getTimeCost(String startDate, String endDate, Integer projectId);
+
+}

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

@@ -31,6 +31,7 @@ public interface UserService extends IService<User> {
     HttpRespMsg insertCompany(String companyName, String name, String phone);
 
     HttpRespMsg insertUser(String id, String name, String phone, Integer role, Double monthCost, Double cost, Integer departmentId,
+                           Integer salaryType,
                            HttpServletRequest request);
 
     HttpRespMsg importUser(Integer departmentId, MultipartFile multipartFile, HttpServletRequest request);

+ 8 - 7
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/DepartmentServiceImpl.java

@@ -15,6 +15,7 @@ import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
+import java.math.BigDecimal;
 import java.util.*;
 
 /**
@@ -247,7 +248,7 @@ public class DepartmentServiceImpl extends ServiceImpl<DepartmentMapper, Departm
 
     //获取某个项目下的统计
     @Override
-    public HttpRespMsg getDepartmentStatistics(HttpServletRequest request) {
+    public HttpRespMsg getDepartmentStatistics(String startDate, String endDate, HttpServletRequest request) {
         HttpRespMsg httpRespMsg = new HttpRespMsg();
         try {
             Integer companyId = userMapper.selectById(request.getHeader("Token")).getCompanyId();
@@ -255,15 +256,15 @@ public class DepartmentServiceImpl extends ServiceImpl<DepartmentMapper, Departm
                     .eq("company_id", companyId).isNull("superior_id"));
             Map<String, Object> resultMap = new HashMap<>();
             List<DepartmentMasterVO> list = new ArrayList<>();
-            Double totalCostMoney = (double) 0;
+            BigDecimal totalCostMoney = new BigDecimal(0);
             for (Department department : masterList) {
                 DepartmentMasterVO departmentMasterVO = new DepartmentMasterVO();
                 BeanUtils.copyProperties(department, departmentMasterVO);
                 Map<String, Object> map = departmentMapper.getCostByDepartment(
-                        getBranchDepartment(department.getDepartmentId(), companyId));
+                        getBranchDepartment(department.getDepartmentId(), companyId), startDate, endDate);
                 Double time = map == null ? new Double(0) : (Double) map.get("time");
-                Double money = map == null ? new Double(0) : (Double) map.get("money");
-                totalCostMoney += money;
+                BigDecimal money = map == null ? new BigDecimal(0) : (BigDecimal) map.get("money");
+                totalCostMoney = totalCostMoney.add(money);
                 departmentMasterVO.setCostTime(time);
                 departmentMasterVO.setCostMoney(money);
                 list.add(departmentMasterVO);
@@ -281,7 +282,7 @@ public class DepartmentServiceImpl extends ServiceImpl<DepartmentMapper, Departm
     //获取某个部门下人员的统计
     @SuppressWarnings("SuspiciousMethodCalls")
     @Override
-    public HttpRespMsg getUserStatistics(Integer departmentId, HttpServletRequest request) {
+    public HttpRespMsg getUserStatistics(String startDate, String endDate, Integer departmentId, HttpServletRequest request) {
         HttpRespMsg httpRespMsg = new HttpRespMsg();
         try {
             Integer companyId = userMapper.selectById(request.getHeader("Token")).getCompanyId();
@@ -290,7 +291,7 @@ public class DepartmentServiceImpl extends ServiceImpl<DepartmentMapper, Departm
                     .eq("department_id", departmentId)
                     .eq("company_id", companyId)) == 1) {
                 List<Map<String, Object>> list = departmentMapper
-                        .getCostByUser(getBranchDepartment(departmentId, companyId));
+                        .getCostByUser(getBranchDepartment(departmentId, companyId), startDate, endDate);
                 Map<String, List<Map<String, Object>>> tempMap = new HashMap<>();
                 Double totalCostMoney = (double) 0;
                 for (Map<String, Object> map : list) {

+ 11 - 3
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/FinanceServiceImpl.java

@@ -105,7 +105,9 @@ public class FinanceServiceImpl extends ServiceImpl<FinanceMapper, Finance> impl
 
 
             //由于第一行需要指明列对应的标题
-            for (int rowIndex = 0; rowIndex <= sheet.getLastRowNum(); rowIndex++) {
+            int rowNum = sheet.getLastRowNum();
+            System.out.println("总行数=="+rowNum);
+            for (int rowIndex = 0; rowIndex < sheet.getLastRowNum(); rowIndex++) {
                 XSSFRow row = sheet.getRow(rowIndex);
                 if (row == null) {
                     continue;
@@ -123,6 +125,7 @@ public class FinanceServiceImpl extends ServiceImpl<FinanceMapper, Finance> impl
 
 
                 nameCell.setCellType(CellType.STRING);
+                System.out.println("name=="+nameCell.getStringCellValue());
                 salaryCell.setCellType(CellType.STRING);
                 bonusCell.setCellType(CellType.STRING);
                 allowanceCell.setCellType(CellType.STRING);
@@ -537,8 +540,13 @@ public class FinanceServiceImpl extends ServiceImpl<FinanceMapper, Finance> impl
             finances.forEach(f->{
                 String uid = f.getUserId();
                 BigDecimal b = userTime.get(uid);
-                BigDecimal avgHourCost = f.getTotalCost().divide(b,4, BigDecimal.ROUND_HALF_UP);
-                f.setHourCost(avgHourCost);
+                if (b == null) {
+                    //该员工无工时填报,不计入项目
+                    f.setHourCost(new BigDecimal(0));
+                } else {
+                    BigDecimal avgHourCost = f.getTotalCost().divide(b,4, BigDecimal.ROUND_HALF_UP);
+                    f.setHourCost(avgHourCost);
+                }
             });
 
             for (Map<String, Object> map : projectTimeList) {

+ 41 - 26
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ProjectServiceImpl.java

@@ -4,15 +4,9 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.management.platform.entity.Participation;
-import com.management.platform.entity.Project;
-import com.management.platform.entity.Report;
-import com.management.platform.entity.User;
+import com.management.platform.entity.*;
 import com.management.platform.entity.vo.ProjectVO;
-import com.management.platform.mapper.ParticipationMapper;
-import com.management.platform.mapper.ProjectMapper;
-import com.management.platform.mapper.ReportMapper;
-import com.management.platform.mapper.UserMapper;
+import com.management.platform.mapper.*;
 import com.management.platform.service.ProjectService;
 import com.management.platform.util.HttpRespMsg;
 import com.management.platform.util.ExcelUtil;
@@ -47,6 +41,8 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
     @Resource
     private ParticipationMapper participationMapper;
     @Resource
+    private ProjectTimerMapper projectTimerMapper;
+    @Resource
     private HttpServletResponse response;
 
     @Value(value = "${upload.path}")
@@ -116,23 +112,42 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                 if (name == null) {
                     httpRespMsg.setError("请填写项目名称");
                 } else {
-                    Project project = new Project().setProjectName(name).setCompanyId(companyId).setProjectCode(code).setInchargerId(inchargerId);
-                    if (projectMapper.insert(project) == 0) {
-                        httpRespMsg.setError("操作失败");
+                    //检查项目编号不能重复
+                    Integer count = projectMapper.selectCount(new QueryWrapper<Project>().eq("company_id", companyId).eq("project_code", code));
+                    if (count > 0) {
+                        httpRespMsg.setError("提交失败:项目编号已存在");
+                    } else {
+                        Project project = new Project().setProjectName(name).setCompanyId(companyId).setProjectCode(code).setInchargerId(inchargerId);
+                        if (projectMapper.insert(project) == 0) {
+                            httpRespMsg.setError("操作失败");
+                        }
+                        id = project.getId();
                     }
-                    id = project.getId();
                 }
             } else {
                 //修改项目
-                if (projectMapper.updateById(new Project().setProjectName(name).setId(id).setCompanyId(companyId).setProjectCode(code).setInchargerId(inchargerId)) == 0) {
-                    httpRespMsg.setError("操作失败");
+                //检查项目编号不能重复
+                Integer count = projectMapper.selectCount(new QueryWrapper<Project>().eq("company_id", companyId).eq("project_code", code).ne("id", id));
+                if (count > 0) {
+                    httpRespMsg.setError("提交失败:项目编号已存在");
+                } else {
+                    if (projectMapper.updateById(new Project().setProjectName(name).setId(id).setCompanyId(companyId).setProjectCode(code).setInchargerId(inchargerId)) == 0) {
+                        httpRespMsg.setError("操作失败");
+                    } else {
+                        //修改项目相关表
+                        ProjectTimer timer = new ProjectTimer();
+                        timer.setProjectName(name);
+                        projectTimerMapper.update(timer, new QueryWrapper<ProjectTimer>().eq("project_id", id));
+                    }
                 }
             }
-            //编辑关系
-            participationMapper.delete(new QueryWrapper<Participation>().eq("project_id", id));
-            if (userIds != null) {
-                for (String userId : userIds) {
-                    participationMapper.insert(new Participation().setProjectId(id).setUserId(userId));
+            if (httpRespMsg.code.equals("ok")) {
+                //编辑关系
+                participationMapper.delete(new QueryWrapper<Participation>().eq("project_id", id));
+                if (userIds != null) {
+                    for (String userId : userIds) {
+                        participationMapper.insert(new Participation().setProjectId(id).setUserId(userId));
+                    }
                 }
             }
         } catch (NullPointerException e) {
@@ -156,12 +171,12 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
 
     //获取查询者所在公司每个项目的工时成本
     @Override
-    public HttpRespMsg getTimeCost(HttpServletRequest request) {
+    public HttpRespMsg getTimeCost(String startDate, String endDate, HttpServletRequest request) {
         HttpRespMsg httpRespMsg = new HttpRespMsg();
         try {
             Integer companyId = userMapper.selectById(request.getHeader("Token")).getCompanyId();
             Map<String, Object> resultMap = new HashMap<>();
-            List<Map<String, Object>> list = projectMapper.getTimeCost(companyId);
+            List<Map<String, Object>> list = projectMapper.getTimeCost(companyId, startDate, endDate);
             BigDecimal totalMoneyCost = BigDecimal.valueOf(0);
             for (Map<String, Object> map : list) {
                 if (!map.containsKey("cost")) {
@@ -185,12 +200,12 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
 
     //导出查询者所在公司每个项目的工时成本,包括项目人员明细统计
     @Override
-    public HttpRespMsg exportTimeCost(HttpServletRequest request) {
+    public HttpRespMsg exportTimeCost(String startDate, String endDate, HttpServletRequest request) {
         HttpRespMsg httpRespMsg = new HttpRespMsg();
         try {
             Integer companyId = userMapper.selectById(request.getHeader("Token")).getCompanyId();
             Map<String, Object> resultMap = new HashMap<>();
-            List<Map<String, Object>> list = projectMapper.getTimeCost(companyId);
+            List<Map<String, Object>> list = projectMapper.getTimeCost(companyId, startDate, endDate);
             BigDecimal totalMoneyCost = BigDecimal.valueOf(0);
             List<String> headList = new ArrayList<String>();
             headList.add("项目");
@@ -218,7 +233,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                 allList.add(rowData);
                 //统计每个项目中的人员时间成本投入
                 int projectId = (Integer)map.get("id");
-                List<Map<String, Object>> membList = projectMapper.getProjectCost(projectId);
+                List<Map<String, Object>> membList = projectMapper.getProjectCost(startDate, endDate, projectId);
                 map.put("membList", membList);
                 for (Map<String, Object> membMap : membList) {
                     List<String> membRowData = new ArrayList<String>();
@@ -251,7 +266,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
 
     //获取某个项目每个人分别需要的工时
     @Override
-    public HttpRespMsg getProjectCost(Integer projectId, HttpServletRequest request) {
+    public HttpRespMsg getProjectCost(String startDate, String endDate, Integer projectId, HttpServletRequest request) {
         HttpRespMsg httpRespMsg = new HttpRespMsg();
         try {
             Integer companyId = userMapper.selectById(request.getHeader("Token")).getCompanyId();
@@ -260,7 +275,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                 httpRespMsg.setError("无权查看其他公司的项目详情");
             } else {
                 Map<String, Object> resultMap = new HashMap<>();
-                List<Map<String, Object>> list = projectMapper.getProjectCost(projectId);
+                List<Map<String, Object>> list = projectMapper.getProjectCost(startDate, endDate, projectId);
                 BigDecimal totalMoneyCost = BigDecimal.valueOf(0);
                 for (Map<String, Object> map : list) {
                     if (!map.containsKey("costMoney")) {

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

@@ -0,0 +1,20 @@
+package com.management.platform.service.impl;
+
+import com.management.platform.entity.ProjectTimer;
+import com.management.platform.mapper.ProjectTimerMapper;
+import com.management.platform.service.ProjectTimerService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ *  服务实现类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2021-03-17
+ */
+@Service
+public class ProjectTimerServiceImpl extends ServiceImpl<ProjectTimerMapper, ProjectTimer> implements ProjectTimerService {
+
+}

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

@@ -20,6 +20,7 @@ import java.io.IOException;
 import java.math.BigDecimal;
 import java.sql.Timestamp;
 import java.text.DecimalFormat;
+import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.time.LocalDate;
 import java.time.format.DateTimeFormatter;
@@ -48,7 +49,8 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
     private ProjectMapper projectMapper;
     @Resource
     private InformationMapper informationMapper;
-
+    @Resource
+    private TimeTypeMapper timeTypeMapper;
     @Resource
     private DepartmentService departmentService;
     @Resource
@@ -67,25 +69,70 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
             User user = userMapper.selectById(userId);
             List<Map<String, Object>> nameList = new ArrayList<>();
             if (user.getRole() == 0) {
-                //普通员工只能看自己的
+                String leaderId = user.getId();
+
+                //查看自己的日报
                 Map<String, Object> map = new HashMap<>();
                 map.put("id", user.getId());
                 map.put("name", user.getName());
-                List<Map<String, Object>> list = reportMapper.getReportByDate(date, (String) map.get("id"));
+                //不是项目经理,只看自己的报告
+                List<Map<String, Object>> list = new ArrayList<>();
+                list = reportMapper.getReportByDate(date, (String) map.get("id"));
                 if (list.size() > 0) {
+                    //个人日报
                     nameList.add(map);
                     map.put("data", list);
                     double reportTime = 0;
                     BigDecimal total = new BigDecimal(0);
+                    int state = (int)list.get(0).get("state");
+                    boolean hasDeny = false;
+                    boolean hasWaiting = false;
                     for (Map<String, Object> m : list) {
                         double t = (double) m.get("time");
                         reportTime += t;
                         total = total.add((BigDecimal)m.get("cost"));
+                        int curState = (int)m.get("state");
+                        if (curState == 2) {
+                            hasDeny = true;
+                        }
+                        if (curState == 0) {
+                            hasWaiting = true;
+                        }
+                    }
+                    if(hasDeny) {
+                        state = 2;
+                    } else if (hasWaiting) {
+                        state = 0;
                     }
                     DecimalFormat df = new DecimalFormat("0.00");
                     map.put("reportTime", df.format(reportTime));
                     map.put("cost", total);
-                    map.put("state", list.get(0).get("state"));
+                    map.put("state", state);
+                }
+
+                int cnt = projectMapper.selectCount(new QueryWrapper<Project>().eq("incharger_id", leaderId));
+                if (cnt > 0) {
+                    //担任项目经理,查找相关的人员的日报
+                    List<Map<String, Object>> puserNames = reportMapper.getReportNameByDate(date, user.getCompanyId(), leaderId);
+                    List<Map<String, Object>> inchargeReportList= reportMapper.getInchargeReportByDate(date, leaderId, null);
+                    for (Map<String, Object> map2 : puserNames) {
+                        nameList.add(map2);
+                        //再根据人分别获取当天的报告
+                        List<Map<String, Object>> 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"));
+                        }
+                        DecimalFormat df = new DecimalFormat("0.00");
+                        map2.put("reportTime", df.format(reportTime));
+                        map2.put("cost", total);
+                        map2.put("state", list2.get(0).get("state"));
+                    }
                 }
             } else {
                 Integer companyId = userMapper.selectById(request.getHeader("Token")).getCompanyId();
@@ -103,7 +150,10 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                     }
                 }
                 nameList = reportMapper.getReportNameByDateAndDept(date,
-                        ids, targetUid);
+                        ids, targetUid, companyId);
+                nameList.forEach(n->{
+                    System.out.println("name=="+n.get("name"));
+                });
                 if (nameList.size() > 0) {
                     List<String> userIds = new ArrayList<>();
                     nameList.forEach(n->{
@@ -164,6 +214,7 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
         HttpRespMsg httpRespMsg = new HttpRespMsg();
         try {
             String userId = request.getHeader("Token");
+            Integer companyId = userMapper.selectById(userId).getCompanyId();
             Map<String, Object> resultMap = new HashMap<>();
             //获取某日本人的所有日志
             resultMap.put("report", reportMapper.selectList(new QueryWrapper<Report>()
@@ -188,6 +239,8 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
             //顺便返回该公司全部的计划
             resultMap.put("project", projectMapper.selectList(new QueryWrapper<Project>()
                     .eq("company_id", userMapper.selectById(userId).getCompanyId())));
+            //顺便返回公司的工作时间设置
+            resultMap.put("timeType",timeTypeMapper.selectById(companyId));
             httpRespMsg.data = resultMap;
         } catch (NullPointerException e) {
             httpRespMsg.setError("验证失败");
@@ -215,6 +268,7 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
                     httpRespMsg.setError("操作失败");
                 }
             } else {
+                //只操作没有审核通过的
                 if (reportMapper.selectById(report.getId()).getState() != 1) {
                     if (reportMapper.updateById(report) == 0) {
                         httpRespMsg.setError("操作失败");
@@ -234,9 +288,10 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
 
     //删除报告
     @Override
-    public HttpRespMsg deleteReport(Integer reportId) {
+    public HttpRespMsg deleteReport(String userId, String date) {
         HttpRespMsg httpRespMsg = new HttpRespMsg();
-        if (reportMapper.deleteById(reportId) == 0) {
+        //某人删除自己某天的全部报告
+        if (reportMapper.delete(new QueryWrapper<Report>().eq("creator_id", userId).eq("create_date", date)) == 0) {
             httpRespMsg.setError("操作失败");
         }
         return httpRespMsg;
@@ -247,45 +302,67 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
     public HttpRespMsg getListByState(Integer state, HttpServletRequest request) {
         HttpRespMsg httpRespMsg = new HttpRespMsg();
         try {
-            Integer companyId = userMapper.selectById(request.getHeader("Token")).getCompanyId();
-            List<Map<String, Object>> nameList = reportMapper.getDetailByState(state, companyId);
+            User curUser = userMapper.selectById(request.getHeader("Token"));
+            Integer companyId = curUser.getCompanyId();
+            String leaderId = null;
+            if (curUser.getRole() == 0) {//普通员工
+                leaderId = curUser.getId();
+            }
+            //根据权限,管理员查看全部人员的,各个项目负责人只看自己负责的项目参与人员的日报
+            List<Map<String, Object>> nameList = reportMapper.getDetailByState(state, companyId, leaderId);
             List<User> userList = userMapper.selectList(new QueryWrapper<User>().eq("company_id", companyId));
-            for (Map<String, Object> map : nameList) {
-                //再根据人分别获取当天的报告
-                List<Map<String, Object>> list = reportMapper.getReportByDate(
-                        map.get("date").toString(),
-                        (String) map.get("id"));
-                map.put("data", list);
+
+            System.out.println("人员列表:"+nameList.size());
+            for (Map<String, Object> map2 : nameList) {
+                java.sql.Date createDate = (java.sql.Date)map2.get("date");
+                System.out.println("姓名="+map2.get("name")+", "+createDate.toString());
+                List<Map<String, Object>> list2 = null;
+                if (leaderId == null) {
+                    //管理员,直接获取每个人的报告
+                    list2 = reportMapper.getReportByDate(createDate.toString(), (String)map2.get("id"));
+                } else {
+                    //获取相关项目的报告
+                    List<Map<String, Object>> inchargeReportList= reportMapper.getInchargeReportByDate(createDate.toString(), leaderId, state);
+                    System.out.println("再根据人分别获取当天的报告="+inchargeReportList.size());
+                    list2 =
+                            inchargeReportList.stream().filter(i->i.get("creatorId").equals(map2.get("id"))).collect(Collectors.toList());
+                    System.out.println("再根据人分别获取当天的报告list2="+list2.size());
+                }
+
+                map2.put("data", list2);
                 double reportTime = 0;
-                if (list.size() > 0) {
-                    for (Map<String, Object> m : list) {
-                        double t = (double) m.get("time");
-                        reportTime += t;
-                    }
-                    map.put("state", list.get(0).get("state"));
+                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");
-                map.put("reportTime", df.format(reportTime));
-                //计算成本
-                BigDecimal multiply = userList.stream().filter(u -> u.getId().equals((String) map.get("id"))).findFirst().get().getCost().multiply(new BigDecimal(reportTime));
-                map.put("cost", multiply);
-                //顺便再获取一下可分配时间
-                Integer calculateTime = 0;
-                //以下区间被认为是工作时间
-                Integer[] workType = {-1, 0, 1, 2, 3, 4, 5};
-                //工作时间筛选
-                List<TimeCalculation> timeCalculations = timeCalculationMapper.selectList(new QueryWrapper<TimeCalculation>()
-                        .eq("date", map.get("date").toString())
-                        .eq("user_id", map.get("id"))
-                        .in("action_type", workType));
-                if (timeCalculations != null) {
-                    for (TimeCalculation timeCalculation : timeCalculations) {
-                        calculateTime += timeCalculation.getDuration();
-                    }
-                }
-                //把总秒数转为double后换算为小时并保留两位小数
-                map.put("calculateTime", df.format((double) calculateTime / 3600));
+                map2.put("reportTime", df.format(reportTime));
+                map2.put("cost", total);
+                map2.put("state", list2.get(0).get("state"));
             }
+//            for (Map<String, Object> map : nameList) {
+//                //再根据人分别获取当天的报告
+//                List<Map<String, Object>> list = reportMapper.getReportByDate(
+//                        map.get("date").toString(),
+//                        (String) map.get("id"));
+//                map.put("data", list);
+//                double reportTime = 0;
+//                if (list.size() > 0) {
+//                    for (Map<String, Object> m : list) {
+//                        double t = (double) m.get("time");
+//                        reportTime += t;
+//                    }
+//                    map.put("state", list.get(0).get("state"));
+//                }
+//                DecimalFormat df = new DecimalFormat("0.00");
+//                map.put("reportTime", df.format(reportTime));
+//                //计算成本
+//                BigDecimal multiply = userList.stream().filter(u -> u.getId().equals((String) map.get("id"))).findFirst().get().getCost().multiply(new BigDecimal(reportTime));
+//                map.put("cost", multiply);
+//
+//            }
             httpRespMsg.data = nameList;
         } catch (NullPointerException e) {
             httpRespMsg.setError("验证失败");
@@ -294,18 +371,14 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
         return httpRespMsg;
     }
 
-    //审核通过某天某人
+    //审核通过某天某人的某报告
     @Override
-    public HttpRespMsg approveReport(String id, String date, HttpServletRequest request) {
+    public HttpRespMsg approveReport(String id, String date, String reportIds, HttpServletRequest request) {
         HttpRespMsg httpRespMsg = new HttpRespMsg();
         try {
             User user = userMapper.selectById(request.getHeader("Token"));
-            if (user.getRole() == 0) {
-                httpRespMsg.setError("无修改权限");
-            } else {
-                reportMapper.update(new Report().setState(1),
-                        new QueryWrapper<Report>().eq("creator_id", id).eq("create_date", date));
-            }
+            reportMapper.update(new Report().setState(1),
+                    new QueryWrapper<Report>().in("id", ListUtil.convertIdsArrayToList(reportIds)));
         } catch (NullPointerException e) {
             httpRespMsg.setError("验证失败");
             return httpRespMsg;
@@ -315,17 +388,13 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
 
     //审核未通过 以及 撤销审核某天某人
     @Override
-    public HttpRespMsg denyReport(String id, String date, HttpServletRequest request) {
+    public HttpRespMsg denyReport(String id, String date, String reportIds, HttpServletRequest request) {
         HttpRespMsg httpRespMsg = new HttpRespMsg();
         try {
             User user = userMapper.selectById(request.getHeader("Token"));
-            if (user.getRole() == 0) {
-                httpRespMsg.setError("无修改权限");
-            } else {
-                reportMapper.update(new Report().setState(2),
-                        new QueryWrapper<Report>().eq("creator_id", id).eq("create_date", date));
-                informationMapper.insert(new Information().setType(0).setContent(date).setUserId(id));
-            }
+            reportMapper.update(new Report().setState(2),
+                    new QueryWrapper<Report>().in("id", ListUtil.convertIdsArrayToList(reportIds)));
+            informationMapper.insert(new Information().setType(0).setContent(date).setUserId(id));
         } catch (NullPointerException e) {
             httpRespMsg.setError("验证失败");
             return httpRespMsg;
@@ -373,7 +442,7 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
     public HttpRespMsg getMembList(String date, HttpServletRequest request) {
         Integer companyId = userMapper.selectById(request.getHeader("Token")).getCompanyId();
         //获取当日已填写的人员报告
-        List<Map<String, Object>> reportNameByDate = reportMapper.getReportNameByDate(date, companyId);
+        List<Map<String, Object>> reportNameByDate = reportMapper.getReportNameByDate(date, companyId, null);
 
         HttpRespMsg departmentList = departmentService.getDepartmentList(request);
         List<DepartmentVO> list = (List<DepartmentVO>) departmentList.data;
@@ -399,10 +468,10 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
     }
 
     @Override
-    public HttpRespMsg batchApproveReport(String ids, String date, HttpServletRequest request) {
+    public HttpRespMsg batchApproveReport(String ids, HttpServletRequest request) {
         Report report = new Report();
         report.setState(1);
-        int num = reportMapper.update(report, new QueryWrapper<Report>().in("creator_id", ListUtil.convertIdsArrayToList(ids)).eq("create_date", date));
+        int num = reportMapper.update(report, new QueryWrapper<Report>().in("id", ListUtil.convertIdsArrayToList(ids)));
         HttpRespMsg msg = new HttpRespMsg();
         if (num <= 0) {
             msg.setError("无数据更新");
@@ -410,6 +479,31 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
         return msg;
     }
 
+    @Override
+    public HttpRespMsg cancelReport(String userId, String reportIds, HttpServletRequest request) {
+        HttpRespMsg msg = new HttpRespMsg();
+        User user = userMapper.selectById(userId);
+
+        List<Integer> ids = ListUtil.convertIntegerIdsArrayToList(reportIds);
+        int cnt = 0;
+        for (Integer reportId : ids) {
+            Report report = new Report();
+            report.setState(3);//待提交
+            if (user.getRole() == 0) {
+                //自己只能撤销待审核状态的
+                cnt += reportMapper.update(report, new QueryWrapper<Report>().eq("id", reportId).eq("state", 0));
+            } else {
+                //管理员可以撤销任何状态的
+                cnt += reportMapper.update(report, new QueryWrapper<Report>().eq("id", reportId));
+            }
+
+        }
+        if (cnt == 0) {
+            msg.setError("只有待审核状态的报告才能撤回");
+        }
+        return msg;
+    }
+
     private void fillDeptUser(List<DepartmentVO> list, List<HashMap> userList) {
         list.forEach(l->{
             List<HashMap> collect = userList.stream().filter(u -> u.get("departmentId").equals(l.getId())).collect(Collectors.toList());

+ 58 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/SubProjectServiceImpl.java

@@ -0,0 +1,58 @@
+package com.management.platform.service.impl;
+
+import com.management.platform.entity.SubProject;
+import com.management.platform.mapper.SubProjectMapper;
+import com.management.platform.mapper.UserMapper;
+import com.management.platform.service.SubProjectService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.management.platform.util.HttpRespMsg;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import java.math.BigDecimal;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <p>
+ *  服务实现类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2021-03-17
+ */
+@Service
+public class SubProjectServiceImpl extends ServiceImpl<SubProjectMapper, SubProject> implements SubProjectService {
+    @Resource
+    private UserMapper userMapper;
+    @Resource
+    private SubProjectMapper subProjectMapper;
+    @Override
+    public HttpRespMsg getTimeCost(String startDate, String endDate, Integer projectId) {
+        HttpRespMsg httpRespMsg = new HttpRespMsg();
+        try {
+            Map<String, Object> resultMap = new HashMap<>();
+            List<Map<String, Object>> list = subProjectMapper.getTimeCost(projectId, startDate, endDate);
+            BigDecimal totalMoneyCost = BigDecimal.valueOf(0);
+            for (Map<String, Object> map : list) {
+                if (!map.containsKey("cost")) {
+                    map.put("cost", 0);
+                }
+                if (!map.containsKey("costMoney")) {
+                    map.put("costMoney", 0);
+                } else {
+                    totalMoneyCost = totalMoneyCost.add(BigDecimal.valueOf((Double) map.get("costMoney")));
+                }
+            }
+            resultMap.put("costList", list);
+            resultMap.put("totalMoneyCost", totalMoneyCost);
+            httpRespMsg.data = resultMap;
+        } catch (NullPointerException e) {
+            httpRespMsg.setError("验证失败");
+            return httpRespMsg;
+        }
+        return httpRespMsg;
+    }
+}

+ 44 - 15
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/UserServiceImpl.java

@@ -3,18 +3,13 @@ package com.management.platform.service.impl;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.management.platform.entity.Company;
-import com.management.platform.entity.Department;
-import com.management.platform.entity.TimeType;
-import com.management.platform.entity.User;
+import com.management.platform.entity.*;
 import com.management.platform.entity.vo.UserVO;
-import com.management.platform.mapper.CompanyMapper;
-import com.management.platform.mapper.DepartmentMapper;
-import com.management.platform.mapper.TimeTypeMapper;
-import com.management.platform.mapper.UserMapper;
+import com.management.platform.mapper.*;
 import com.management.platform.service.UserService;
 import com.management.platform.util.HttpRespMsg;
 import com.management.platform.util.MD5Util;
+import com.management.platform.util.MathUtil;
 import com.management.platform.util.SnowFlake;
 import org.apache.poi.ss.usermodel.CellType;
 import org.apache.poi.xssf.usermodel.XSSFCell;
@@ -23,12 +18,14 @@ import org.apache.poi.xssf.usermodel.XSSFSheet;
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
+import org.springframework.util.NumberUtils;
 import org.springframework.web.multipart.MultipartFile;
 
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
 import java.io.*;
 import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
 import java.util.ArrayList;
@@ -54,7 +51,8 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
     private DepartmentMapper departmentMapper;
     @Resource
     private TimeTypeMapper timeTypeMapper;
-
+    @Resource
+    private ProjectMapper projectMapper;
     //登录网页端
     @Override
     public HttpRespMsg loginAdmin(String username, String password) {
@@ -93,6 +91,11 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
             LocalDateTime remainingTime = company.getExpirationDate() == null ? LocalDateTime.now() : company.getExpirationDate();
             userVO.setRemainingTime(remainingTime.toInstant(ZoneOffset.of("+8")).toEpochMilli() -
                     LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli());
+            //检测是否是项目经理,项目经理有审核功能权限
+            int cnt = projectMapper.selectCount(new QueryWrapper<Project>().eq("incharger_id", userVO.getId()));
+            if (cnt > 0) {
+                userVO.setLeader(true);
+            }
             httpRespMsg.data = userVO;
         } else {
             httpRespMsg.setError("密码错误");
@@ -306,13 +309,13 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
     //新增或修改用户
     @Override
     public HttpRespMsg insertUser(String targetId, String name, String phone, Integer role, Double monthCost, Double cost,
-                                  Integer departmentId, HttpServletRequest request) {
+                                  Integer departmentId, Integer salaryType, HttpServletRequest request) {
         HttpRespMsg httpRespMsg = new HttpRespMsg();
         try {
             User creator = userMapper.selectById(request.getHeader("Token"));
             //处理时薪
             BigDecimal costValue = cost == null ? BigDecimal.valueOf(0) : BigDecimal.valueOf(cost);
-            BigDecimal monthCostValue = cost == null ? BigDecimal.valueOf(0) : BigDecimal.valueOf(monthCost);
+            BigDecimal monthCostValue = monthCost == null ? BigDecimal.valueOf(0) : BigDecimal.valueOf(monthCost);
             if (targetId == null) {
                 //新增
                 if (creator.getRole() == 2 && role != 0) {
@@ -339,6 +342,7 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
                                     .setCompanyId(creator.getCompanyId())
                                     .setMonthCost(monthCostValue)
                                     .setCost(costValue)
+                                    .setSalaryType(salaryType)
                                     .setDepartmentId(departmentId == null ? 0 : departmentId)
                                     .setDepartmentCascade(departmentId == null ?
                                             convertDepartmentIdToCascade(0) :
@@ -357,6 +361,7 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
                         .setRole(role)
                         .setMonthCost(monthCostValue)
                         .setCost(costValue)
+                        .setSalaryType(salaryType)
                         .setDepartmentId(departmentId == null ? 0 : departmentId)
                         .setDepartmentCascade(departmentId == null ?
                                 convertDepartmentIdToCascade(0) :
@@ -390,8 +395,13 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
     public HttpRespMsg importUser(Integer departmentId, MultipartFile multipartFile,
                                   HttpServletRequest request) {
         HttpRespMsg httpRespMsg = new HttpRespMsg();
+
         //首先先搞到公司id
         Integer companyId = userMapper.selectById(request.getHeader("Token")).getCompanyId();
+
+        //查询工作时长设置
+        TimeType time = timeTypeMapper.selectById(companyId);
+        BigDecimal monthHours = time.getMonthDays().multiply(new BigDecimal(time.getAllday()));
         //然后处理文件
         String fileName = multipartFile.getOriginalFilename();
         File file = new File(fileName == null ? "file" : fileName);
@@ -421,11 +431,12 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
                 if (row == null) {
                     continue;
                 }
-                //此处新建账号 默认密码为000000 默认 姓名第一列 手机号第二列 薪第三列
+                //此处新建账号 默认密码为000000 默认 姓名第一列 手机号第二列 薪第三列
                 Long id = SnowFlake.nextId();
                 XSSFCell nameCell = row.getCell(0);
                 XSSFCell phoneCell = row.getCell(1);
-                XSSFCell costCell = row.getCell(2);
+                XSSFCell monthCostCell = row.getCell(2);
+                XSSFCell costCell = row.getCell(3);
                 nameCell.setCellType(CellType.STRING);
                 phoneCell.setCellType(CellType.STRING);
 
@@ -434,12 +445,28 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
                 if (name.equals("姓名") && phone.equals("手机号") && rowIndex == 0) {
                     continue;
                 }
-
+                int salaryType = 0;
+                BigDecimal monthCost = new BigDecimal(0);
                 BigDecimal cost = new BigDecimal(0);
+                if (monthCostCell != null) {
+                    monthCostCell.setCellType(CellType.STRING);
+                    String monthCostString = monthCostCell.getStringCellValue();
+
+                    monthCost = MathUtil.isIntegerOrDigital(monthCostString)? new BigDecimal(monthCostString) : BigDecimal.valueOf(0);
+                    //计算时薪
+                    cost = monthCost.divide(monthHours, 2, RoundingMode.HALF_UP);
+                    if (MathUtil.isIntegerOrDigital(monthCostString)) {
+                        salaryType = 0;
+                    } else {
+                        salaryType = 1;
+                    }
+                } else {
+                    salaryType = 1;
+                }
                 if (costCell != null) {
                     costCell.setCellType(CellType.STRING);
                     String costString = costCell.getStringCellValue();
-                    cost = costString != null ? new BigDecimal(costString) : BigDecimal.valueOf(0);
+                    cost = MathUtil.isIntegerOrDigital(costString) ? new BigDecimal(costString) : BigDecimal.valueOf(0);
                 }
 
                 phoneList.add(phone);
@@ -450,7 +477,9 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
                         .setPhone(phone)
                         .setRole(0)
                         .setCompanyId(companyId)
+                        .setMonthCost(monthCost)
                         .setCost(cost)
+                        .setSalaryType(salaryType)
                         .setDepartmentId(departmentId)
                         .setDepartmentCascade(convertDepartmentIdToCascade(departmentId)));
             }

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

@@ -204,7 +204,7 @@ public class CodeGenerator {
         //若想要生成的实体类继承某个Controller,则可打开下面注释。写上需要继承的Controller的位置即可
 //        strategy.setSuperControllerClass("com.baomidou.ant.common.BaseController");
         //此处user是表名,多个英文逗号分割
-        strategy.setInclude("report");
+        strategy.setInclude("project_timer");
 //        strategy.setExclude();//数据库表全生成
 //        strategy.setInclude(scanner("user").split(","));//表名,多个英文逗号分割
         strategy.setControllerMappingHyphenStyle(true);

+ 18 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/util/MathUtil.java

@@ -0,0 +1,18 @@
+package com.management.platform.util;
+
+import java.util.regex.Pattern;
+
+public class MathUtil {
+    public static boolean isIntegerOrDigital(String str) {
+        if (str == null || str.trim().length() == 0) {
+            return false;
+        }
+        Pattern pattern = Pattern.compile("^[-\\+]?[\\d]*[\\.]?[\\d]*$");
+        return pattern.matcher(str).matches();
+    }
+
+    public static void main(String[] args) {
+        String str = "";
+        System.out.println(isIntegerOrDigital(str));
+    }
+}

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

@@ -17,7 +17,7 @@
 
     <!--根据部门获取成本-->
     <select id="getCostByDepartment" resultType="java.util.Map">
-        SELECT SUM(b.working_time) AS time, SUM(b.working_time * a.cost) AS money
+        SELECT SUM(b.working_time) AS time, cast(SUM(b.working_time * a.cost) AS decimal(11,2)) AS money
         FROM user AS a
         LEFT JOIN report AS b ON a.id = b.creator_id
         WHERE b.state = 1
@@ -25,6 +25,9 @@
         <foreach collection="departmentIds" item="departmentId" index="index" open="(" close=")" separator=",">
             #{departmentId}
         </foreach>
+        <if test="startDate != null and endDate != null">
+            AND b.create_date between #{startDate} and #{endDate}
+        </if>
     </select>
 
     <!--根据人员获取成本-->
@@ -39,6 +42,9 @@
         <foreach collection="departmentIds" item="departmentId" index="index" open="(" close=")" separator=",">
             #{departmentId}
         </foreach>
+        <if test="startDate != null and endDate != null">
+            AND b.create_date between #{startDate} and #{endDate}
+        </if>
         GROUP BY b.project_id, a.id
     </select>
 

+ 6 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/ProjectMapper.xml

@@ -34,6 +34,9 @@
         LEFT JOIN report AS b ON b.project_id = a.id
         JOIN user AS c ON b.creator_id = c.id
         WHERE a.company_id = #{companyId}
+        <if test="startDate != null and endDate != null">
+            AND b.create_date between #{startDate} and #{endDate}
+        </if>
         AND b.state = 1
         GROUP BY a.id
         ORDER BY a.id ASC
@@ -46,6 +49,9 @@
         JOIN user AS b ON a.creator_id = b.id
         WHERE a.project_id = #{projectId}
         AND a.state = 1
+        <if test="startDate != null and endDate != null">
+            AND a.create_date between #{startDate} and #{endDate}
+        </if>
         GROUP BY b.id
         ORDER BY b.id ASC
     </select>

+ 24 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/ProjectTimerMapper.xml

@@ -0,0 +1,24 @@
+<?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.ProjectTimerMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.management.platform.entity.ProjectTimer">
+        <id column="id" property="id" />
+        <result column="project_id" property="projectId" />
+        <result column="sub_project_id" property="subProjectId" />
+        <result column="start_time" property="startTime" />
+        <result column="end_time" property="endTime" />
+        <result column="user_id" property="userId" />
+        <result column="time_cost" property="timeCost" />
+        <result column="report_id" property="reportId" />
+        <result column="project_name" property="projectName" />
+        <result column="sub_project_name" property="subProjectName" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, project_id, sub_project_id, start_time, end_time, user_id, time_cost, report_id, project_name, sub_project_name
+    </sql>
+
+</mapper>

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

@@ -14,20 +14,26 @@
         <result column="create_time" property="createTime" />
         <result column="time_type" property="timeType" />
         <result column="cost" property="cost" />
+        <result column="start_time" property="startTime" />
+        <result column="end_time" property="endTime" />
+        <result column="report_time_type" property="reportTimeType" />
+        <result column="sub_project_id" property="subProjectId" />
     </resultMap>
 
     <!-- 通用查询结果列 -->
     <sql id="Base_Column_List">
-        id, creator_id, project_id, create_date, working_time, content, state, create_time, time_type, cost
+        id, creator_id, project_id, create_date, working_time, content, state, create_time, time_type, cost, start_time, end_time, report_time_type, sub_project_id
     </sql>
 
     <!--根据日期获取全部报告信息-->
     <select id="getAllReportByDate" resultType="java.util.Map">
         SELECT c.name, b.project_name AS project, a.working_time AS duration, a.content, a.create_time AS time,
-        a.state, a.time_type as timeType, a.cost
+        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, d.name as subProjectName
         FROM report AS a
         JOIN project AS b ON a.project_id=b.id
         LEFT JOIN user AS c ON a.creator_id=c.id
+        left join sub_project as d on d.id = a.sub_project_id
         WHERE a.state = 1
         <if test="date != null and date != ''">
             AND a.create_date = #{date}
@@ -41,9 +47,11 @@
         ORDER BY a.creator_id ASC
     </select>
 
-    <!--根据日期获取报告信息-->
+
+    <!--根据员工id,日期获取当天全部报告信息-->
     <select id="getReportByDate" resultType="java.util.Map">
-        SELECT b.project_name AS project, a.working_time AS time, a.content, a.state, a.time_type as timeType, a.cost
+        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,
+        a.end_time as endTime, b.incharger_id as inchargerId
         FROM report AS a
         JOIN project AS b ON a.project_id=b.id
         WHERE 1=1
@@ -53,11 +61,34 @@
         AND a.creator_id=#{id}
         ORDER BY a.creator_id ASC
     </select>
+
+    <!--根据项目经理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,
+        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
+        FROM report AS a
+        JOIN project AS b ON a.project_id=b.id
+        left join sub_project as d on d.id = a.sub_project_id
+        WHERE 1=1
+        <if test="date != null and date != ''">
+            AND a.create_date=#{date}
+        </if>
+        <if test="state != null">
+            AND a.state=#{state}
+        </if>
+        AND b.incharger_id = #{id}
+        ORDER BY a.creator_id ASC
+    </select>
+
     <!-- 批量获取员工某天的报告 -->
     <select id="getUserReportByDate" resultType="java.util.Map">
-        SELECT b.project_name AS project, a.working_time AS time, a.content, a.state, a.time_type as timeType, a.creator_id as creatorId, a.cost
+        SELECT a.id, b.project_name AS project, a.working_time AS time, a.content, a.state, a.time_type as timeType, a.creator_id as creatorId, a.cost, a.report_time_type as reportTimeType, a.start_time as startTime,
+        a.end_time as endTime, d.name as subProjectName
         FROM report AS a
         JOIN project AS b ON a.project_id=b.id
+        left join sub_project as d on d.id = a.sub_project_id
         WHERE 1=1
         <if test="date != null and date != ''">
             AND a.create_date=#{date}
@@ -81,11 +112,14 @@
         <if test="companyId != null and companyId != ''">
             AND b.company_id=#{companyId}
         </if>
+        <if test="leaderId != null and leaderId != ''">
+            AND a.project_id in (select id from project where incharger_id = #{leaderId})
+        </if>
     </select>
 
     <!--根据日期,部门,指定人员获取报告上传人-->
     <select id="getReportNameByDateAndDept" resultType="java.util.Map">
-        SELECT DISTINCT b.id, b.name, a.state
+        SELECT DISTINCT b.id, b.name
         FROM report AS a
         JOIN user AS b ON a.creator_id=b.id
         WHERE 1=1
@@ -98,6 +132,9 @@
                 #{item, jdbcType=INTEGER}
             </foreach>
         </if>
+        <if test="deptIds == null and companyId != null">
+            AND b.company_id = #{companyId}
+        </if>
         <if test="userId != null">
             AND b.id=#{userId}
         </if>
@@ -109,11 +146,15 @@
         FROM report AS a
         JOIN user AS b ON a.creator_id=b.id
         WHERE a.state = #{state} AND b.company_id=#{companyId}
+        <if test="leaderId != null">
+            AND a.creator_id in (select user_id from participation where project_id in(select id from project where incharger_id = #{leaderId}))
+            AND a.project_id in (select id from project where incharger_id = #{leaderId})
+        </if>
         ORDER BY a.create_date DESC
     </select>
     <select id="getRealProjectTime" resultType="java.util.Map">
         SELECT project.project_name as project,creator_id AS creatorId,sum(working_time) as workingTime, SUM(cost) as cost
-         FROM report
+        FROM report
         left join project on project.id = report.project_id
         WHERE creator_id IN
         (select id from user where company_id = #{companyId})
@@ -126,6 +167,4 @@
         </if>
         GROUP BY project_id, creator_id;
     </select>
-
-
 </mapper>

+ 30 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/SubProjectMapper.xml

@@ -0,0 +1,30 @@
+<?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.SubProjectMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.management.platform.entity.SubProject">
+        <id column="id" property="id" />
+        <result column="name" property="name" />
+        <result column="project_id" property="projectId" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, name, project_id
+    </sql>
+    <!--获取某个项目内子项目的工时成本统计-->
+    <select id="getTimeCost" resultType="java.util.Map">
+        SELECT a.id, a.name AS name, SUM(b.working_time) AS cost, SUM(b.working_time * c.cost) AS costMoney
+        FROM sub_project AS a
+        LEFT JOIN report AS b ON b.sub_project_id = a.id
+        JOIN user AS c ON b.creator_id = c.id
+        WHERE a.project_id = #{projectId}
+        <if test="startDate != null and endDate != null">
+            AND b.create_date between #{startDate} and #{endDate}
+        </if>
+        AND b.state = 1
+        GROUP BY a.id
+        ORDER BY a.id ASC
+    </select>
+</mapper>

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

@@ -9,11 +9,13 @@
         <result column="am" property="am" />
         <result column="pm" property="pm" />
         <result column="month_days" property="monthDays" />
+        <result column="hour_cost_input_type" property="hourCostInputType" />
+        <result column="type" property="type" />
     </resultMap>
 
     <!-- 通用查询结果列 -->
     <sql id="Base_Column_List">
-        company_id, allday, am, pm, month_days
+        company_id, allday, am, pm, month_days, hour_cost_input_type, type
     </sql>
 
 </mapper>

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

@@ -16,19 +16,19 @@
         <result column="department_cascade" property="departmentCascade" />
         <result column="cost" property="cost" />
         <result column="month_cost" property="monthCost" />
+        <result column="salary_type" property="salaryType" />
     </resultMap>
 
     <!-- 通用查询结果列 -->
     <sql id="Base_Column_List">
-        id, name, phone, password, portrait_url, create_time, role, company_id, department_id, department_cascade, cost, month_cost
+        id, name, phone, password, portrait_url, create_time, role, company_id, department_id, department_cascade, cost, month_cost, salary_type
     </sql>
 
-
     <!--单独分页获取人员-->
     <select id="getUserByDepartment" resultType="java.util.Map">
         SELECT a.id, a.name, a.phone, a.portrait_url AS portraitUrl, a.role, a.company_id AS companyId, a.cost,
         a.department_id AS departmentId, b.department_name AS departmentName, a.department_cascade AS departmentCascade,
-        a.month_cost as monthCost
+        a.month_cost as monthCost, a.salary_type as salaryType
         FROM user AS a
         LEFT JOIN department AS b ON a.department_id = b.department_id
         WHERE a.company_id = #{companyId}
@@ -51,7 +51,7 @@
     <select id="getUserByDepartmentList" resultType="java.util.Map">
         SELECT a.id, a.name, a.phone, a.portrait_url AS portraitUrl, a.role, a.company_id AS companyId, a.cost,
         a.department_id AS departmentId, b.department_name AS departmentName, a.department_cascade AS departmentCascade,
-        a.month_cost as monthCost
+        a.month_cost as monthCost, a.salary_type as salaryType
         FROM user AS a
         LEFT JOIN department AS b ON a.department_id = b.department_id
         WHERE a.company_id = #{companyId} AND a.department_id IN

BIN
fhKeeper/formulahousekeeper/management-platform/人员导入模板 (4).xlsx


BIN
fhKeeper/formulahousekeeper/management-platform/人员导入模板.xlsx


BIN
fhKeeper/formulahousekeeper/management-platform/财务人员成本模板2.xlsx


+ 4 - 1
fhKeeper/formulahousekeeper/timesheet/src/App.vue

@@ -1,7 +1,10 @@
 <template>
 	<div id="app">
 		<transition name="fade" mode="out-in">
-			<router-view></router-view>
+			<!-- <keep-alive>
+                <router-view v-if='$route.meta != null && $route.meta.keepAlive'/>
+            </keep-alive> -->
+            <router-view />
 		</transition>
 	</div>
 </template>

+ 539 - 0
fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/demo.css

@@ -0,0 +1,539 @@
+/* Logo 字体 */
+@font-face {
+  font-family: "iconfont logo";
+  src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
+  src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
+    url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
+    url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
+    url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
+}
+
+.logo {
+  font-family: "iconfont logo";
+  font-size: 160px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+/* tabs */
+.nav-tabs {
+  position: relative;
+}
+
+.nav-tabs .nav-more {
+  position: absolute;
+  right: 0;
+  bottom: 0;
+  height: 42px;
+  line-height: 42px;
+  color: #666;
+}
+
+#tabs {
+  border-bottom: 1px solid #eee;
+}
+
+#tabs li {
+  cursor: pointer;
+  width: 100px;
+  height: 40px;
+  line-height: 40px;
+  text-align: center;
+  font-size: 16px;
+  border-bottom: 2px solid transparent;
+  position: relative;
+  z-index: 1;
+  margin-bottom: -1px;
+  color: #666;
+}
+
+
+#tabs .active {
+  border-bottom-color: #f00;
+  color: #222;
+}
+
+.tab-container .content {
+  display: none;
+}
+
+/* 页面布局 */
+.main {
+  padding: 30px 100px;
+  width: 960px;
+  margin: 0 auto;
+}
+
+.main .logo {
+  color: #333;
+  text-align: left;
+  margin-bottom: 30px;
+  line-height: 1;
+  height: 110px;
+  margin-top: -50px;
+  overflow: hidden;
+  *zoom: 1;
+}
+
+.main .logo a {
+  font-size: 160px;
+  color: #333;
+}
+
+.helps {
+  margin-top: 40px;
+}
+
+.helps pre {
+  padding: 20px;
+  margin: 10px 0;
+  border: solid 1px #e7e1cd;
+  background-color: #fffdef;
+  overflow: auto;
+}
+
+.icon_lists {
+  width: 100% !important;
+  overflow: hidden;
+  *zoom: 1;
+}
+
+.icon_lists li {
+  width: 100px;
+  margin-bottom: 10px;
+  margin-right: 20px;
+  text-align: center;
+  list-style: none !important;
+  cursor: default;
+}
+
+.icon_lists li .code-name {
+  line-height: 1.2;
+}
+
+.icon_lists .icon {
+  display: block;
+  height: 100px;
+  line-height: 100px;
+  font-size: 42px;
+  margin: 10px auto;
+  color: #333;
+  -webkit-transition: font-size 0.25s linear, width 0.25s linear;
+  -moz-transition: font-size 0.25s linear, width 0.25s linear;
+  transition: font-size 0.25s linear, width 0.25s linear;
+}
+
+.icon_lists .icon:hover {
+  font-size: 100px;
+}
+
+.icon_lists .svg-icon {
+  /* 通过设置 font-size 来改变图标大小 */
+  width: 1em;
+  /* 图标和文字相邻时,垂直对齐 */
+  vertical-align: -0.15em;
+  /* 通过设置 color 来改变 SVG 的颜色/fill */
+  fill: currentColor;
+  /* path 和 stroke 溢出 viewBox 部分在 IE 下会显示
+      normalize.css 中也包含这行 */
+  overflow: hidden;
+}
+
+.icon_lists li .name,
+.icon_lists li .code-name {
+  color: #666;
+}
+
+/* markdown 样式 */
+.markdown {
+  color: #666;
+  font-size: 14px;
+  line-height: 1.8;
+}
+
+.highlight {
+  line-height: 1.5;
+}
+
+.markdown img {
+  vertical-align: middle;
+  max-width: 100%;
+}
+
+.markdown h1 {
+  color: #404040;
+  font-weight: 500;
+  line-height: 40px;
+  margin-bottom: 24px;
+}
+
+.markdown h2,
+.markdown h3,
+.markdown h4,
+.markdown h5,
+.markdown h6 {
+  color: #404040;
+  margin: 1.6em 0 0.6em 0;
+  font-weight: 500;
+  clear: both;
+}
+
+.markdown h1 {
+  font-size: 28px;
+}
+
+.markdown h2 {
+  font-size: 22px;
+}
+
+.markdown h3 {
+  font-size: 16px;
+}
+
+.markdown h4 {
+  font-size: 14px;
+}
+
+.markdown h5 {
+  font-size: 12px;
+}
+
+.markdown h6 {
+  font-size: 12px;
+}
+
+.markdown hr {
+  height: 1px;
+  border: 0;
+  background: #e9e9e9;
+  margin: 16px 0;
+  clear: both;
+}
+
+.markdown p {
+  margin: 1em 0;
+}
+
+.markdown>p,
+.markdown>blockquote,
+.markdown>.highlight,
+.markdown>ol,
+.markdown>ul {
+  width: 80%;
+}
+
+.markdown ul>li {
+  list-style: circle;
+}
+
+.markdown>ul li,
+.markdown blockquote ul>li {
+  margin-left: 20px;
+  padding-left: 4px;
+}
+
+.markdown>ul li p,
+.markdown>ol li p {
+  margin: 0.6em 0;
+}
+
+.markdown ol>li {
+  list-style: decimal;
+}
+
+.markdown>ol li,
+.markdown blockquote ol>li {
+  margin-left: 20px;
+  padding-left: 4px;
+}
+
+.markdown code {
+  margin: 0 3px;
+  padding: 0 5px;
+  background: #eee;
+  border-radius: 3px;
+}
+
+.markdown strong,
+.markdown b {
+  font-weight: 600;
+}
+
+.markdown>table {
+  border-collapse: collapse;
+  border-spacing: 0px;
+  empty-cells: show;
+  border: 1px solid #e9e9e9;
+  width: 95%;
+  margin-bottom: 24px;
+}
+
+.markdown>table th {
+  white-space: nowrap;
+  color: #333;
+  font-weight: 600;
+}
+
+.markdown>table th,
+.markdown>table td {
+  border: 1px solid #e9e9e9;
+  padding: 8px 16px;
+  text-align: left;
+}
+
+.markdown>table th {
+  background: #F7F7F7;
+}
+
+.markdown blockquote {
+  font-size: 90%;
+  color: #999;
+  border-left: 4px solid #e9e9e9;
+  padding-left: 0.8em;
+  margin: 1em 0;
+}
+
+.markdown blockquote p {
+  margin: 0;
+}
+
+.markdown .anchor {
+  opacity: 0;
+  transition: opacity 0.3s ease;
+  margin-left: 8px;
+}
+
+.markdown .waiting {
+  color: #ccc;
+}
+
+.markdown h1:hover .anchor,
+.markdown h2:hover .anchor,
+.markdown h3:hover .anchor,
+.markdown h4:hover .anchor,
+.markdown h5:hover .anchor,
+.markdown h6:hover .anchor {
+  opacity: 1;
+  display: inline-block;
+}
+
+.markdown>br,
+.markdown>p>br {
+  clear: both;
+}
+
+
+.hljs {
+  display: block;
+  background: white;
+  padding: 0.5em;
+  color: #333333;
+  overflow-x: auto;
+}
+
+.hljs-comment,
+.hljs-meta {
+  color: #969896;
+}
+
+.hljs-string,
+.hljs-variable,
+.hljs-template-variable,
+.hljs-strong,
+.hljs-emphasis,
+.hljs-quote {
+  color: #df5000;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-type {
+  color: #a71d5d;
+}
+
+.hljs-literal,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-attribute {
+  color: #0086b3;
+}
+
+.hljs-section,
+.hljs-name {
+  color: #63a35c;
+}
+
+.hljs-tag {
+  color: #333333;
+}
+
+.hljs-title,
+.hljs-attr,
+.hljs-selector-id,
+.hljs-selector-class,
+.hljs-selector-attr,
+.hljs-selector-pseudo {
+  color: #795da3;
+}
+
+.hljs-addition {
+  color: #55a532;
+  background-color: #eaffea;
+}
+
+.hljs-deletion {
+  color: #bd2c00;
+  background-color: #ffecec;
+}
+
+.hljs-link {
+  text-decoration: underline;
+}
+
+/* 代码高亮 */
+/* PrismJS 1.15.0
+https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
+/**
+ * prism.js default theme for JavaScript, CSS and HTML
+ * Based on dabblet (http://dabblet.com)
+ * @author Lea Verou
+ */
+code[class*="language-"],
+pre[class*="language-"] {
+  color: black;
+  background: none;
+  text-shadow: 0 1px white;
+  font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
+  text-align: left;
+  white-space: pre;
+  word-spacing: normal;
+  word-break: normal;
+  word-wrap: normal;
+  line-height: 1.5;
+
+  -moz-tab-size: 4;
+  -o-tab-size: 4;
+  tab-size: 4;
+
+  -webkit-hyphens: none;
+  -moz-hyphens: none;
+  -ms-hyphens: none;
+  hyphens: none;
+}
+
+pre[class*="language-"]::-moz-selection,
+pre[class*="language-"] ::-moz-selection,
+code[class*="language-"]::-moz-selection,
+code[class*="language-"] ::-moz-selection {
+  text-shadow: none;
+  background: #b3d4fc;
+}
+
+pre[class*="language-"]::selection,
+pre[class*="language-"] ::selection,
+code[class*="language-"]::selection,
+code[class*="language-"] ::selection {
+  text-shadow: none;
+  background: #b3d4fc;
+}
+
+@media print {
+
+  code[class*="language-"],
+  pre[class*="language-"] {
+    text-shadow: none;
+  }
+}
+
+/* Code blocks */
+pre[class*="language-"] {
+  padding: 1em;
+  margin: .5em 0;
+  overflow: auto;
+}
+
+:not(pre)>code[class*="language-"],
+pre[class*="language-"] {
+  background: #f5f2f0;
+}
+
+/* Inline code */
+:not(pre)>code[class*="language-"] {
+  padding: .1em;
+  border-radius: .3em;
+  white-space: normal;
+}
+
+.token.comment,
+.token.prolog,
+.token.doctype,
+.token.cdata {
+  color: slategray;
+}
+
+.token.punctuation {
+  color: #999;
+}
+
+.namespace {
+  opacity: .7;
+}
+
+.token.property,
+.token.tag,
+.token.boolean,
+.token.number,
+.token.constant,
+.token.symbol,
+.token.deleted {
+  color: #905;
+}
+
+.token.selector,
+.token.attr-name,
+.token.string,
+.token.char,
+.token.builtin,
+.token.inserted {
+  color: #690;
+}
+
+.token.operator,
+.token.entity,
+.token.url,
+.language-css .token.string,
+.style .token.string {
+  color: #9a6e3a;
+  background: hsla(0, 0%, 100%, .5);
+}
+
+.token.atrule,
+.token.attr-value,
+.token.keyword {
+  color: #07a;
+}
+
+.token.function,
+.token.class-name {
+  color: #DD4A68;
+}
+
+.token.regex,
+.token.important,
+.token.variable {
+  color: #e90;
+}
+
+.token.important,
+.token.bold {
+  font-weight: bold;
+}
+
+.token.italic {
+  font-style: italic;
+}
+
+.token.entity {
+  cursor: help;
+}

+ 262 - 0
fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/demo_index.html

@@ -0,0 +1,262 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8"/>
+  <title>IconFont Demo</title>
+  <link rel="shortcut icon" href="https://img.alicdn.com/tps/i4/TB1_oz6GVXXXXaFXpXXJDFnIXXX-64-64.ico" type="image/x-icon"/>
+  <link rel="stylesheet" href="https://g.alicdn.com/thx/cube/1.3.2/cube.min.css">
+  <link rel="stylesheet" href="demo.css">
+  <link rel="stylesheet" href="iconfont.css">
+  <script src="iconfont.js"></script>
+  <!-- jQuery -->
+  <script src="https://a1.alicdn.com/oss/uploads/2018/12/26/7bfddb60-08e8-11e9-9b04-53e73bb6408b.js"></script>
+  <!-- 代码高亮 -->
+  <script src="https://a1.alicdn.com/oss/uploads/2018/12/26/a3f714d0-08e6-11e9-8a15-ebf944d7534c.js"></script>
+</head>
+<body>
+  <div class="main">
+    <h1 class="logo"><a href="https://www.iconfont.cn/" title="iconfont 首页" target="_blank">&#xe86b;</a></h1>
+    <div class="nav-tabs">
+      <ul id="tabs" class="dib-box">
+        <li class="dib active"><span>Unicode</span></li>
+        <li class="dib"><span>Font class</span></li>
+        <li class="dib"><span>Symbol</span></li>
+      </ul>
+      
+      <a href="https://www.iconfont.cn/manage/index?manage_type=myprojects&projectId=2390497" target="_blank" class="nav-more">查看项目</a>
+      
+    </div>
+    <div class="tab-container">
+      <div class="content unicode" style="display: block;">
+          <ul class="icon_lists dib-box">
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe631;</span>
+                <div class="name">统计</div>
+                <div class="code-name">&amp;#xe631;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe617;</span>
+                <div class="name">项目</div>
+                <div class="code-name">&amp;#xe617;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe89c;</span>
+                <div class="name">财务</div>
+                <div class="code-name">&amp;#xe89c;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe672;</span>
+                <div class="name">setting</div>
+                <div class="code-name">&amp;#xe672;</div>
+              </li>
+          
+          </ul>
+          <div class="article markdown">
+          <h2 id="unicode-">Unicode 引用</h2>
+          <hr>
+
+          <p>Unicode 是字体在网页端最原始的应用方式,特点是:</p>
+          <ul>
+            <li>兼容性最好,支持 IE6+,及所有现代浏览器。</li>
+            <li>支持按字体的方式去动态调整图标大小,颜色等等。</li>
+            <li>但是因为是字体,所以不支持多色。只能使用平台里单色的图标,就算项目里有多色图标也会自动去色。</li>
+          </ul>
+          <blockquote>
+            <p>注意:新版 iconfont 支持多色图标,这些多色图标在 Unicode 模式下将不能使用,如果有需求建议使用symbol 的引用方式</p>
+          </blockquote>
+          <p>Unicode 使用步骤如下:</p>
+          <h3 id="-font-face">第一步:拷贝项目下面生成的 <code>@font-face</code></h3>
+<pre><code class="language-css"
+>@font-face {
+  font-family: 'iconfont';
+  src: url('iconfont.eot');
+  src: url('iconfont.eot?#iefix') format('embedded-opentype'),
+      url('iconfont.woff2') format('woff2'),
+      url('iconfont.woff') format('woff'),
+      url('iconfont.ttf') format('truetype'),
+      url('iconfont.svg#iconfont') format('svg');
+}
+</code></pre>
+          <h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
+<pre><code class="language-css"
+>.iconfont {
+  font-family: "iconfont" !important;
+  font-size: 16px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+</code></pre>
+          <h3 id="-">第三步:挑选相应图标并获取字体编码,应用于页面</h3>
+<pre>
+<code class="language-html"
+>&lt;span class="iconfont"&gt;&amp;#x33;&lt;/span&gt;
+</code></pre>
+          <blockquote>
+            <p>"iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。</p>
+          </blockquote>
+          </div>
+      </div>
+      <div class="content font-class">
+        <ul class="icon_lists dib-box">
+          
+          <li class="dib">
+            <span class="icon iconfont firerock-icontongji"></span>
+            <div class="name">
+              统计
+            </div>
+            <div class="code-name">.firerock-icontongji
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont firerock-iconxiangmu"></span>
+            <div class="name">
+              项目
+            </div>
+            <div class="code-name">.firerock-iconxiangmu
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont firerock-iconcaiwu"></span>
+            <div class="name">
+              财务
+            </div>
+            <div class="code-name">.firerock-iconcaiwu
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont firerock-iconsetting"></span>
+            <div class="name">
+              setting
+            </div>
+            <div class="code-name">.firerock-iconsetting
+            </div>
+          </li>
+          
+        </ul>
+        <div class="article markdown">
+        <h2 id="font-class-">font-class 引用</h2>
+        <hr>
+
+        <p>font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。</p>
+        <p>与 Unicode 使用方式相比,具有如下特点:</p>
+        <ul>
+          <li>兼容性良好,支持 IE8+,及所有现代浏览器。</li>
+          <li>相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。</li>
+          <li>因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。</li>
+          <li>不过因为本质上还是使用的字体,所以多色图标还是不支持的。</li>
+        </ul>
+        <p>使用步骤如下:</p>
+        <h3 id="-fontclass-">第一步:引入项目下面生成的 fontclass 代码:</h3>
+<pre><code class="language-html">&lt;link rel="stylesheet" href="./iconfont.css"&gt;
+</code></pre>
+        <h3 id="-">第二步:挑选相应图标并获取类名,应用于页面:</h3>
+<pre><code class="language-html">&lt;span class="iconfont firerock-iconxxx"&gt;&lt;/span&gt;
+</code></pre>
+        <blockquote>
+          <p>"
+            iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。</p>
+        </blockquote>
+      </div>
+      </div>
+      <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-icontongji"></use>
+                </svg>
+                <div class="name">统计</div>
+                <div class="code-name">#firerock-icontongji</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#firerock-iconxiangmu"></use>
+                </svg>
+                <div class="name">项目</div>
+                <div class="code-name">#firerock-iconxiangmu</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#firerock-iconcaiwu"></use>
+                </svg>
+                <div class="name">财务</div>
+                <div class="code-name">#firerock-iconcaiwu</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#firerock-iconsetting"></use>
+                </svg>
+                <div class="name">setting</div>
+                <div class="code-name">#firerock-iconsetting</div>
+            </li>
+          
+          </ul>
+          <div class="article markdown">
+          <h2 id="symbol-">Symbol 引用</h2>
+          <hr>
+
+          <p>这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇<a href="">文章</a>
+            这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:</p>
+          <ul>
+            <li>支持多色图标了,不再受单色限制。</li>
+            <li>通过一些技巧,支持像字体那样,通过 <code>font-size</code>, <code>color</code> 来调整样式。</li>
+            <li>兼容性较差,支持 IE9+,及现代浏览器。</li>
+            <li>浏览器渲染 SVG 的性能一般,还不如 png。</li>
+          </ul>
+          <p>使用步骤如下:</p>
+          <h3 id="-symbol-">第一步:引入项目下面生成的 symbol 代码:</h3>
+<pre><code class="language-html">&lt;script src="./iconfont.js"&gt;&lt;/script&gt;
+</code></pre>
+          <h3 id="-css-">第二步:加入通用 CSS 代码(引入一次就行):</h3>
+<pre><code class="language-html">&lt;style&gt;
+.icon {
+  width: 1em;
+  height: 1em;
+  vertical-align: -0.15em;
+  fill: currentColor;
+  overflow: hidden;
+}
+&lt;/style&gt;
+</code></pre>
+          <h3 id="-">第三步:挑选相应图标并获取类名,应用于页面:</h3>
+<pre><code class="language-html">&lt;svg class="icon" aria-hidden="true"&gt;
+  &lt;use xlink:href="#icon-xxx"&gt;&lt;/use&gt;
+&lt;/svg&gt;
+</code></pre>
+          </div>
+      </div>
+
+    </div>
+  </div>
+  <script>
+  $(document).ready(function () {
+      $('.tab-container .content:first').show()
+
+      $('#tabs li').click(function (e) {
+        var tabContent = $('.tab-container .content')
+        var index = $(this).index()
+
+        if ($(this).hasClass('active')) {
+          return
+        } else {
+          $('#tabs li').removeClass('active')
+          $(this).addClass('active')
+
+          tabContent.hide().eq(index).fadeIn()
+        }
+      })
+    })
+  </script>
+</body>
+</html>

File diff suppressed because it is too large
+ 33 - 0
fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.css


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


File diff suppressed because it is too large
+ 1 - 0
fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.js


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

@@ -0,0 +1,37 @@
+{
+  "id": "2390497",
+  "name": "seyaproject",
+  "font_family": "iconfont",
+  "css_prefix_text": "firerock-icon",
+  "description": "",
+  "glyphs": [
+    {
+      "icon_id": "807967",
+      "name": "统计",
+      "font_class": "tongji",
+      "unicode": "e631",
+      "unicode_decimal": 58929
+    },
+    {
+      "icon_id": "1778691",
+      "name": "项目",
+      "font_class": "xiangmu",
+      "unicode": "e617",
+      "unicode_decimal": 58903
+    },
+    {
+      "icon_id": "14417643",
+      "name": "财务",
+      "font_class": "caiwu",
+      "unicode": "e89c",
+      "unicode_decimal": 59548
+    },
+    {
+      "icon_id": "11673579",
+      "name": "setting",
+      "font_class": "setting",
+      "unicode": "e672",
+      "unicode_decimal": 58994
+    }
+  ]
+}

File diff suppressed because it is too large
+ 38 - 0
fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.svg


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


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

@@ -2,6 +2,8 @@
 // import VueRouter from 'vue-router'
 // Vue.use(VueRouter)
 // import ElementUI from 'element-ui'
+//全局修改默认配置,点击空白处不能关闭弹窗
+// Dialog.props.closeOnClickModal.default = false
 // Vue.use(ElementUI)
 // import Vuex from 'vuex'
 // Vue.use(Vuex)
@@ -23,13 +25,16 @@ Vue.prototype.echarts = echarts
 import VueClipboard from 'vue-clipboard2'
 Vue.use(VueClipboard)
 
+
+
 import 'font-awesome/css/font-awesome.min.css'
 import './assets/iconfont/iconfont.css'
+import './assets/myfont/iconfont.css'
 
 // const router = new VueRouter({
 //     routes
 // })
-import { staffRouter, manageRouter, fixedRouter } from './routes'
+import { staffRouter, manageRouter, fixedRouter,leaderRouter } from './routes'
 import router from './routes'
 
 import NProgress from 'nprogress'
@@ -60,7 +65,7 @@ router.beforeEach((to, from, next) => {
             if(user != null) {
                 addRouFlag = true
                 if(user.role == 0) {
-                    var getRoutes = baseRoleGetRouters(staffRouter, 1);
+                    var getRoutes = baseRoleGetRouters(user.leader?leaderRouter:staffRouter, 1);
                     global.antRouter = fixedRouter.concat(getRoutes);
                     router.addRoutes(fixedRouter.concat(getRoutes));
                     router.options.routes = fixedRouter.concat(getRoutes);

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

@@ -56,5 +56,6 @@ export default {
         portList: '/report/listByState',                         // 审核列表
         approve: '/report/approve',                             // 通过报告
         deny: '/report/deny',                                   // 未通过
+        cancelReport: '/report/cancel', //用户自己撤回日报
     }
 }

+ 81 - 15
fhKeeper/formulahousekeeper/timesheet/src/routes.js

@@ -16,7 +16,7 @@ import unusual from './views/desktop/unusual.vue'
 import statistics from './views/workReport/statistics.vue'
 import daily from './views/workReport/daily.vue'
 import review from './views/workReport/list.vue'
-
+import timer from './views/workReport/timer.vue'
 // 项目管理
 import list from './views/project/list.vue'
 import cost from './views/project/cost.vue'
@@ -61,7 +61,17 @@ export const manageRouter = [
             { path: '/daily', component: daily, name: '工时报告' },
         ]
     },
-    //工时报告
+    {
+        path: '/',
+        component: Home,
+        name: '自动计时',
+        iconCls: 'fa fa-sticky-note',
+        leaf: true,
+        children: [
+            { path: '/timer', component: timer, name: '自动计时' },
+        ]
+    },
+    //工时审核
     {
         path: '/',
         component: Home,
@@ -77,7 +87,7 @@ export const manageRouter = [
         path: '/',
         component: Home,
         name: '成本统计',
-        iconCls: 'fa fa-clock-o',
+        iconCls: 'iconfont firerock-icontongji',
         leaf: true,
         children: [
             { path: '/cost', component: cost, name: '成本统计' },
@@ -90,7 +100,7 @@ export const manageRouter = [
         path: '/',
         component: Home,
         name: '财务核算成本',
-        iconCls: 'fa fa-sticky-note',
+        iconCls: 'iconfont firerock-iconcaiwu',
         leaf: true,
         children: [
             { path: '/finance', component: finance, name: '财务核算成本' },
@@ -101,7 +111,7 @@ export const manageRouter = [
         path: '/',
         component: Home,
         name: '项目管理',
-        iconCls: 'fa fa-briefcase',
+        iconCls: 'iconfont firerock-iconxiangmu',
         leaf: true,
         children: [
             { path: '/list', component: list, name: '项目管理' },
@@ -124,23 +134,58 @@ export const manageRouter = [
         path: '/',
         component: Home,
         name: '',
-        iconCls: 'fa fa-clock-o',
+        iconCls: 'iconfont firerock-iconsetting',
         leaf: true,//只有一个节点
         children: [
-            { path: '/timetype', component: timetype, name: '工作时长设置' },
+            { path: '/timetype', component: timetype, name: '系统基础设置' },
         ]
     },
     //智能监控
+    // {
+    //     path: '/',
+    //     component: Home,
+    //     name: '智能监控',
+    //     iconCls: 'fa fa-desktop',
+    //     children: [
+    //         { path: '/desktop', component: desktop, name: '员工桌面' },
+    //         { path: '/desktop/:id/:date', component: desktopDetail, name: '员工桌面详情', hidden: true },
+    //         { path: '/unusual', component: unusual, name: '异常统计' },
+    //         { path: '/statistics', component: statistics, name: '智能分析' },
+    //     ]
+    // },
+    {
+        path: '/404',
+        component: NotFound,
+        name: '',
+        hidden: true
+    },
+    {
+        path: '*',
+        hidden: true,
+        redirect: { path: '/404' }
+    }
+];
+
+export const staffRouter = [
+    //工时报告
+    {
+        path: '/',
+        component: Home,
+        name: '工时报告',
+        iconCls: 'fa fa-sticky-note',
+        leaf: true,
+        children: [
+            { path: '/daily', component: daily, name: '工时报告' },
+        ]
+    },
     {
         path: '/',
         component: Home,
-        name: '智能监控',
-        iconCls: 'fa fa-desktop',
+        name: '自动计时',
+        iconCls: 'fa fa-sticky-note',
+        leaf: true,
         children: [
-            { path: '/desktop', component: desktop, name: '员工桌面' },
-            { path: '/desktop/:id/:date', component: desktopDetail, name: '员工桌面详情', hidden: true },
-            { path: '/unusual', component: unusual, name: '异常统计' },
-            { path: '/statistics', component: statistics, name: '智能分析' },
+            { path: '/timer', component: timer, name: '自动计时' },
         ]
     },
     {
@@ -155,8 +200,8 @@ export const manageRouter = [
         redirect: { path: '/404' }
     }
 ];
-
-export const staffRouter = [
+//项目经理的权限,填报和审核
+export const leaderRouter = [
     //工时报告
     {
         path: '/',
@@ -168,6 +213,27 @@ export const staffRouter = [
             { path: '/daily', component: daily, name: '工时报告' },
         ]
     },
+    {
+        path: '/',
+        component: Home,
+        name: '自动计时',
+        iconCls: 'fa fa-sticky-note',
+        leaf: true,
+        children: [
+            { path: '/timer', component: timer, name: '自动计时' },
+        ]
+    },
+    //工时审核
+    {
+        path: '/',
+        component: Home,
+        name: '报告审核',
+        iconCls: 'fa fa-check-square-o',
+        leaf: true,
+        children: [
+            { path: '/review', component: review, name: '报告审核' },
+        ]
+    },
     {
         path: '/404',
         component: NotFound,

+ 0 - 1
fhKeeper/formulahousekeeper/timesheet/src/views/Home.vue

@@ -371,7 +371,6 @@
                     });
                 });
             },
-
         },
         mounted() {
             let height = window.innerHeight;

+ 13 - 1
fhKeeper/formulahousekeeper/timesheet/src/views/Login.vue

@@ -23,11 +23,22 @@
                             <p><span style="color: #333">QQ:</span><span id="QQ">3052894409</span></p>
                         </div>
                     </el-link>
-                    <el-link type="primary" style="margin-right:5px;" :underline="false"><a style="color:#409EFF;text-decoration:none" href="http://gsgj.ttkuaiban.com/download.html" target="_blank">客户端下载</a></el-link>
+                    <el-link type="primary" style="margin-right:5px;" @click="dialogVisible=true" :underline="false">
+                        使用说明
+                    </el-link>
                     <el-link type="primary" @click="jumpTo" :underline="false">企业注册</el-link>
                 </div>
             </el-form>
         </div>
+        <el-dialog title="使用说明" :visible.sync="dialogVisible" width="500px">
+            <p><a style="color:#409EFF;text-decoration:none" href="upload/工时管家使用说明_管理员.docx" download="工时管家使用说明_管理员.docx" 
+                        target="_blank">工时管家使用说明_管理员.docx</a></p>
+            <p><a style="color:#409EFF;text-decoration:none" href="upload/工时管家使用说明_项目经理.docx" download="工时管家使用说明_项目经理.docx" 
+                        target="_blank">工时管家使用说明_项目经理.docx</a></p>
+            <p><a style="color:#409EFF;text-decoration:none" href="upload/工时管家使用说明_普通员工.docx" download="工时管家使用说明_普通员工.docx" 
+                        target="_blank">工时管家使用说明_普通员工.docx</a></p>
+            
+        </el-dialog>
     </div>
 </template>
 
@@ -35,6 +46,7 @@
     export default {
         data() {
             return {
+                dialogVisible: false,
                 logining: false,
                 // 登录信息
                 ruleForm: {

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

@@ -1,7 +1,17 @@
 <template>
     <section>
         <el-col :span="24" style="padding-bottom: 0px;text-align:center;">
-
+            <el-date-picker
+            v-model="dateRange"
+            type="daterange"
+            value-format="yyyy-MM-dd"
+            align="right"
+            unlink-panels
+            range-separator="至"
+            start-placeholder="开始日期"
+            end-placeholder="结束日期"
+            @change="getEchart">
+            </el-date-picker>
             <el-radio-group v-model="radio" @change="getEchart">
                 <el-radio-button label="项目"></el-radio-button>
                 <el-radio-button label="部门"></el-radio-button>
@@ -17,6 +27,7 @@
     export default {
         data() {
             return {
+                dateRange:null,
                 user: JSON.parse(sessionStorage.getItem("user")),
                 radio: sessionStorage.radio!=null?sessionStorage.radio:'项目',
                 containerHeight: 0,    
@@ -26,7 +37,11 @@
         },
         methods: {
             exportProjectData() {
-                this.http.post("/project/exportTimeCost", {},
+                 var param = {};
+                if (this.dateRange != null) {
+                    param = {startDate:this.dateRange[0], endDate: this.dateRange[1]};
+                }
+                this.http.post("/project/exportTimeCost", param,
                     res => {
                         this.listLoading = false;
                         if (res.code == "ok") {
@@ -52,7 +67,12 @@
             getEchart(){
                 sessionStorage.radio = this.radio;
                 var _this = this;
-                this.http.post(this.radio=='项目'?this.port.project.listCost:this.port.project.depCost, {},
+                console.log(this.dateRange);
+                var param = {};
+                if (this.dateRange != null) {
+                    param = {startDate:this.dateRange[0], endDate: this.dateRange[1]};
+                }
+                this.http.post(this.radio=='项目'?this.port.project.listCost:this.port.project.depCost, param,
                 res => {
                     if (res.code == "ok") {
                         var xList = [], yList = [], list = res.data.costList, 
@@ -61,25 +81,25 @@
                             if(this.radio=='项目') {
                                 xList.push(list[i].project);
                                 yList.push({
-                                    "value": list[i].cost,
+                                    "value": list[i].costMoney,
                                     "id": list[i].id,
-                                    "cost": list[i].costMoney
+                                    "cost": list[i].cost
                                 });
                             } else {
                                 xList.push(list[i].departmentName);
                                 yList.push({
-                                    "value": list[i].costTime,
+                                    "value": list[i].costMoney,
                                     "id": list[i].departmentId,
-                                    "cost": list[i].costMoney
+                                    "cost": list[i].costTime
                                 });
                             }
                         }
-
+                        
                         var myChart = echarts.init(document.getElementById("container"));
                         _this.myChart = myChart;
                         var option = {
                             title: {
-                                text: '项目成本统计 总计' + totalMoneyCost + '元',
+                                text: '成本总计' + totalMoneyCost.toFixed(2) + '元',
                                 left:'left',
                             },
                             // 工具箱
@@ -108,8 +128,8 @@
                             tooltip:{
                                 trigger:'axis',
                                 formatter: function (params,ticket,callback) {
-                                    var res = params[0].name + "<br/>工作时长(h)"+" : " + params[0].data.value 
-                                    + "h <br/>工作成本(元)"+" : " + params[0].data.cost + "元";
+                                    var res = params[0].name + "<br/>工作成本"+" : " + params[0].data.value 
+                                    + "元 <br/>工作时长"+" : " + params[0].data.cost + "小时";
                                     _this.params = params;
                                     return res;
                                 }
@@ -123,11 +143,11 @@
                             yAxis: [{
                                 type : 'value',
                                 axisLabel: {
-                                    formatter:'{value} (h)'
+                                    formatter:'{value} ()'
                                 }
                             }],
                             series: [{
-                                name: '工作时长(h)',
+                                name: '工作成本(元)',
                                 type: 'bar',
                                 barMaxWidth: 30,
                                 data: yList,
@@ -146,9 +166,20 @@
                             if (myChart.containPixel('grid', pointInPixel)) {
                                 console.log(_this.params)
                                 if(_this.radio=='项目') {
-                                    _this.$router.push("/cost/" + _this.params[0].data.id + "/" + _this.params[0].name);
+                                    if (_this.dateRange != null) {
+                                        _this.$router.push("/cost/" + _this.params[0].data.id + "/" + _this.params[0].name
+                                            +"?startDate="+_this.dateRange[0]+"&endDate="+_this.dateRange[1]);
+                                    } else {
+                                        _this.$router.push("/cost/" + _this.params[0].data.id + "/" + _this.params[0].name);
+                                    }
                                 } else {
-                                    _this.$router.push("/costDep/" + _this.params[0].data.id + "/" + _this.params[0].name);
+                                    if (_this.dateRange != null) {
+                                        _this.$router.push("/costDep/" + _this.params[0].data.id + "/" + _this.params[0].name
+                                            +"?startDate="+_this.dateRange[0]+"&endDate="+_this.dateRange[1]);
+                                    } else {
+                                        _this.$router.push("/costDep/" + _this.params[0].data.id + "/" + _this.params[0].name);
+                                    }
+                                    
                                 }
                             }
                         });
@@ -175,6 +206,9 @@
             window.onresize = function temp() {
                 this.containerHeight = window.innerHeight - 100
             };
+            if (this.$route.query.startDate != null) {
+                this.dateRange = [this.$route.query.startDate, this.$route.query.endDate];
+            }
             this.getEchart();
             var _this = this;
             window.addEventListener("resize", function() {

+ 27 - 10
fhKeeper/formulahousekeeper/timesheet/src/views/project/detail.vue

@@ -15,7 +15,13 @@
                 </el-form-item>
             </el-form>
         </el-col>
-
+        <el-col :span="24"  style="margin-top:10px;padding-bottom: 0px;text-align:center;">
+            <el-radio-group v-model="radio" @change="getList">
+                <el-radio-button label="人员"></el-radio-button>
+                <el-radio-button label="子项目"></el-radio-button>
+            </el-radio-group>
+        </el-col>
+        
         <div id="container" :style="'height:' + tableHeight + 'px'"></div> 
     </section>
 </template>
@@ -26,9 +32,11 @@
     export default {
         data() {
             return {
+                startDate:null,
+                endDate: null,
                 detailId: this.$route.params.id,
                 detailName: this.$route.params.name,
-
+                radio:"人员",
                 user: JSON.parse(sessionStorage.getItem("user")),
 
                 cost: 0,
@@ -41,14 +49,21 @@
         methods: {
             //返回
             backToList() {
-                this.$router.go(-1);
+                if (this.startDate != null) {
+                    this.$router.push("/cost?startDate="+this.startDate+"&endDate="+this.endDate);
+                } else {
+                    this.$router.push("/cost");
+                }
             },
 
             //获取项目列表
             getList() {
                 this.listLoading = true;
-                this.http.post(this.port.project.projectCost, {
+                this.http.post(this.radio=='人员'?this.port.project.projectCost:'/sub-project/getTimeCost'
+                , {
                     id: this.detailId,
+                    startDate: this.startDate,
+                    endDate: this.endDate,
                 },
                 res => {
                     this.listLoading = false;
@@ -59,8 +74,8 @@
                         for(var i in list) {
                             xList.push(list[i].name);
                             yList.push({
-                                "value": list[i].cost,
-                                "cost": list[i].costMoney
+                                "value": list[i].costMoney,
+                                "cost": list[i].cost
                             });
                         }
 
@@ -91,8 +106,8 @@
                             tooltip:{
                                 trigger:'axis',
                                 formatter: function (params,ticket,callback) {
-                                    var res = params[0].name + "<br/>工作时长(h)"+" : " + params[0].data.value 
-                                    + "h <br/>工作成本(元)"+" : " + params[0].data.cost + "元";
+                                    var res = params[0].name + "<br/>工作成本"+" : " + params[0].data.value 
+                                    + "元 <br/>工作时长"+" : " + params[0].data.cost + "小时";
                                     return res;
                                 }
                             },
@@ -105,11 +120,11 @@
                             yAxis: [{
                                 type : 'value',
                                 axisLabel: {
-                                    formatter:'{value} (h)'
+                                    formatter:'{value} ()'
                                 }
                             }],
                             series: [{
-                                name: '工作时长(h)',
+                                name: '工作成本(元)',
                                 type: 'bar',
                                 barMaxWidth: 30,
                                 data: yList,
@@ -141,6 +156,8 @@
             };
         },
         mounted() {
+            this.startDate = this.$route.query.startDate;
+            this.endDate = this.$route.query.endDate;
             this.getList();
             var _this = this;
             window.addEventListener("resize", function() {

+ 120 - 101
fhKeeper/formulahousekeeper/timesheet/src/views/project/detailDep.vue

@@ -28,6 +28,8 @@
     export default {
         data() {
             return {
+                startDate:null,
+                endDate: null,
                 detailId: this.$route.params.id,
                 detailName: this.$route.params.name,
 
@@ -46,7 +48,11 @@
         methods: {
             //返回
             backToList() {
-                this.$router.go(-1);
+                if (this.startDate != null) {
+                    this.$router.push("/cost?startDate="+this.startDate+"&endDate="+this.endDate);
+                } else {
+                    this.$router.push("/cost");
+                }
             },
 
             // 获取部门列表
@@ -100,122 +106,133 @@
                 this.listLoading = true;
                 this.http.post(this.port.project.userCost, {
                     departmentId: this.departmentId[this.departmentId.length-1],
+                    startDate: this.startDate,
+                    endDate: this.endDate,
                 },
                 res => {
                     this.listLoading = false;
                     var _this = this;
                     if (res.code == "ok") {
                         var xList = [] , yList = [] , list = res.data.list, array = [] , series = [];
-                        this.cost = res.data.totalCostMoney;
-                        var num = list[0].project.length;
-                        for(var i in list) {
-                            xList.push(list[i].name);
-                            var pro = list[i].project;
-                            for(var j in pro) {
-                                if(array.indexOf(pro[j].project) == -1) {
-                                    array.push(pro[j].project)
+                        if (list.length > 0) {
+                            this.cost = res.data.totalCostMoney;
+                            var num = list[0].project.length;
+                            for(var i in list) {
+                                xList.push(list[i].name);
+                                var pro = list[i].project;
+                                for(var j in pro) {
+                                    if(array.indexOf(pro[j].project) == -1) {
+                                        array.push(pro[j].project)
+                                    }
                                 }
                             }
-                        }
 
-                        for(var i in array) {
-                            yList.push(array[i]);
-                            var dataList = [];
-                            for(var j in list) {
-                                var project = list[j].project , num = 0;
-                                if(project.length != 0) {
-                                    for(var k in project) {
-                                        if(project[k].project == array[i]) {
-                                            dataList.push({
-                                                "value": project[k].time,
-                                                "cost": project[k].money,
-                                            })
-                                        } else {
-                                            num++;
-                                        }
-                                        if(k == project.length-1 && num != project.length-1) {
-                                            dataList.push({
-                                                "value": 0,
-                                                "cost": 0,
-                                            })
+                            for(var i in array) {
+                                yList.push(array[i]);
+                                var dataList = [];
+                                for(var j in list) {
+                                    var project = list[j].project , num = 0;
+                                    if(project.length != 0) {
+                                        for(var k in project) {
+                                            if(project[k].project == array[i]) {
+                                                dataList.push({
+                                                    "value": project[k].money,
+                                                    "cost": project[k].time,
+                                                })
+                                            } else {
+                                                num++;
+                                            }
+                                            if(k == project.length-1 && num != project.length-1) {
+                                                dataList.push({
+                                                    "value": 0,
+                                                    "cost": 0,
+                                                })
+                                            }
                                         }
+                                    } else {
+                                        dataList.push({
+                                            "value": 0,
+                                            "cost": 0,
+                                        })
                                     }
-                                } else {
-                                    dataList.push({
-                                        "value": 0,
-                                        "cost": 0,
-                                    })
                                 }
+                                series.push({
+                                    name: array[i],
+                                    type: 'bar',
+                                    stack:'1',
+                                    barMaxWidth: 30,
+                                    data: dataList,
+                                })
                             }
-                            series.push({
-                                name: array[i],
-                                type: 'bar',
-                                stack:'1',
-                                barMaxWidth: 30,
-                                data: dataList,
-                            })
-                        }
 
-                        var myChart = echarts.init(document.getElementById("container"));
-                        _this.myChart = myChart;
-                        var option = {
-                            // 工具箱
-                            legend: {
-                                x: 80,
-                                y: 10,
-                                data: yList
-                            },
-                            grid : {
-                                top : 80,    //距离容器上边界40像素
-                                bottom: 35   //距离容器下边界30像素
-                            },
-                            toolbox: {
-                                show: true,
-                                feature:{
-                                    saveAsImage:{
-                                        show:true
-                                    },
-                                    restore:{
-                                        show:true
-                                    },
-                                    dataView:{
-                                        show:true
-                                    },
-                                    dataZoom:{
-                                        show:true
-                                    },
-                                    magicType:{
-                                        type:['line','bar']
+                            var myChart = echarts.init(document.getElementById("container"));
+                            _this.myChart = myChart;
+                            var option = {
+                                // 工具箱
+                                legend: {
+                                    x: 80,
+                                    y: 10,
+                                    data: yList
+                                },
+                                grid : {
+                                    top : 80,    //距离容器上边界40像素
+                                    bottom: 35   //距离容器下边界30像素
+                                },
+                                toolbox: {
+                                    show: true,
+                                    feature:{
+                                        saveAsImage:{
+                                            show:true
+                                        },
+                                        restore:{
+                                            show:true
+                                        },
+                                        dataView:{
+                                            show:true
+                                        },
+                                        dataZoom:{
+                                            show:true
+                                        },
+                                        magicType:{
+                                            type:['line','bar']
+                                        }
                                     }
-                                }
-                            },
-                            tooltip:{
-                                trigger:'axis',
-                                formatter: function (params,ticket,callback) {
-                                    var res = params[0].name + "<br/>";
-                                    for(var i in params) {
-                                        res += "项目名称:" + params[i].seriesName 
-                                        + "<br/>工作时长(h)" + params[i].data.value
-                                        + "h <br/>工作成本(元)"+" : " + params[i].data.cost + "元</br></br>";
+                                },
+                                tooltip:{
+                                    trigger:'axis',
+                                    formatter: function (params,ticket,callback) {
+                                        var res = params[0].name + "<br/>";
+                                        for(var i in params) {
+                                            if (params[i].data.value > 0) {
+                                                res += "<div style='margin-top:3px;font-size:12px;'><font color='#ddd'>项目名称:" + params[i].seriesName 
+                                                    + "</font><br/>工作成本 : " + params[i].data.value
+                                                    + "元 <br/>工作时长"+" : " + params[i].data.cost + "小时</br></div>";
+                                            }
+                                        }
+                                        return res;
                                     }
-                                    return res;
-                                }
-                            },
-                            xAxis: {
-                                data: xList,
-                                axisLabel: {
-                                    interval:0,rotate:20
-                                }
-                            },
-                            yAxis: [{
-                                type : 'value',
-                                axisLabel: {
-                                    formatter:'{value} (h)'
-                                }
-                            }],
-                            series: series,
-                        };
-                        myChart.setOption(option);
+                                },
+                                xAxis: {
+                                    data: xList,
+                                    axisLabel: {
+                                        interval:0,rotate:20
+                                    }
+                                },
+                                yAxis: [{
+                                    type : 'value',
+                                    axisLabel: {
+                                        formatter:'{value} (元)'
+                                    }
+                                }],
+                                series: series,
+                            };
+                            myChart.setOption(option);
+                        } else {
+                            this.$message({
+                                message: "暂无数据",
+                                type: "error"
+                                });
+                        }
                     } else {
                         this.$message({
                         message: res.msg,
@@ -241,6 +258,8 @@
             };
         },
         mounted() {
+            this.startDate = this.$route.query.startDate;
+            this.endDate = this.$route.query.endDate;
             this.getDepartment();
             this.getList();
             var _this = this;

+ 366 - 0
fhKeeper/formulahousekeeper/timesheet/src/views/project/finance.vue

@@ -0,0 +1,366 @@
+<template>
+    <section>
+        <!--工具条-->
+        <el-col :span="24" class="toolbar" style="padding-bottom: 0px;">
+            <el-form :inline="true">
+                <el-form-item label="财务核算成本 | 月份选择" style="margin-top:5px;">
+                <el-date-picker size="small" v-model="date" :editable="false" format="yyyy-MM" value-format="yyyy-MM" @change="changeMonth" :clearable="false" type="month" placeholder="选择月份"></el-date-picker>
+            </el-form-item>
+            <el-form-item style="float:right;">
+                <el-link type="primary" :underline="false" href="./upload/财务人员成本模板.xlsx" download="财务人员成本模板.xlsx">财务模板下载</el-link>
+            </el-form-item>
+            <el-form-item style="float:right;">
+                <el-upload ref="upload" action="#" :limit="1" :http-request="importFinance" :show-file-list="false">
+                        <el-link type="primary" :underline="false" >财务数据上传</el-link>
+                    </el-upload>
+            </el-form-item>
+            </el-form>
+        </el-col>
+        
+        <!--列表-->
+        <el-table :data="list" highlight-current-row v-loading="listLoading" 
+        show-summary=true
+        ref="table"
+        height="300" style="width: 100%;">
+            <el-table-column prop="name" label="姓名" sortable width="150"></el-table-column>
+            <el-table-column prop="monthCost" label="工资"  width="150"></el-table-column>
+            <el-table-column prop="bonus" label="奖金" ></el-table-column>
+            <el-table-column prop="allowance" label="津贴" ></el-table-column>
+            <el-table-column prop="insuranceOld" label="养老保险" ></el-table-column>
+            <el-table-column prop="insuranceMedical" label="医疗保险" ></el-table-column>
+            <el-table-column prop="insuranceLosejob" label="失业保险" ></el-table-column>
+            <el-table-column prop="houseFund" label="住房公积金" ></el-table-column>
+            <el-table-column prop="others" label="其他" ></el-table-column>
+            <el-table-column prop="totalCost" label="总成本" ></el-table-column>
+        </el-table>
+       
+        <el-form :inline="true" >
+            <el-form-item >
+                <el-link type="primary" :underline="false" @click="assignToProject">查看项目成本分配</el-link>
+            </el-form-item>
+            <el-form-item style="float:right;">
+                <el-link type="primary" :underline="false" @click="exportData">导出数据</el-link>
+            </el-form-item>
+        </el-form>
+        <div id="container" style="height:300px"></div>
+        <!--新增界面-->
+        <el-dialog :title="title" v-if="addFormVisible" :visible.sync="addFormVisible" :close-on-click-modal="false" customClass="customWidth" width="600px">
+            <el-form ref="form1" :model="addForm" :rules="rules" label-width="100px">
+                <el-form-item label="项目编号" >
+                    <el-input v-model="addForm.code" placeholder="请输入项目编号" clearable></el-input>
+                </el-form-item>
+                <el-form-item label="项目名称" prop="name">
+                    <el-input v-model="addForm.name" placeholder="请输入项目名称" clearable></el-input>
+                </el-form-item>
+                <el-form-item label="全部参与者">
+                    <el-select v-model="addForm.userId" multiple filterable placeholder="请选择参与者" style="width:100%;" @change="changeParticipator">
+                        <el-option v-for="item in users" :key="item.id" :label="item.name" :value="item.id"></el-option>
+                    </el-select>
+                </el-form-item>
+                <el-form-item label="主要负责人" >
+                    <el-select v-model="addForm.inchargerId" :disabled="addForm.userId.length==0" filterable placeholder="请选择负责人" style="width:100%;" @change="changeIncharger">
+                        <el-option v-for="item in participator" :key="item.id" :label="item.name" :value="item.id"></el-option>
+                    </el-select>
+                </el-form-item>
+                
+            </el-form>
+            <div slot="footer" class="dialog-footer">
+                <el-button @click.native="addFormVisible = false">取消</el-button>
+                <el-button type="primary" @click="submitInsert" :loading="addLoading">提交</el-button>
+            </div>
+        </el-dialog>
+
+        <!--用户详细信息弹出框-->
+        <el-dialog title="查看详情" v-if="userDetailVisible" :visible.sync="userDetailVisible" :close-on-click-modal="false" customClass="customWidth" width="400px">
+            <div class="line"><span>姓名</span><span>{{userDetail.name}}</span></div>
+            <div class="line"><span>手机号码</span><span>{{userDetail.phone}}</span></div>
+            <div class="line"><span>部门</span><span>{{userDetail.departmentName}}</span></div>
+            <div class="line"><span>成本</span><span>{{userDetail.cost}}元/小时</span></div>
+            <div slot="footer" class="dialog-footer">
+                <el-button type="primary" @click="userDetailVisible = false" >确定</el-button>
+            </div>
+        </el-dialog>
+    </section>
+</template>
+<style scoped>
+.line {
+    padding:10px;
+}
+.line span{
+    font-size:18px;
+}
+.line span:nth-child(even){
+    float:right;
+}
+</style>
+<script>
+    import util from "../../common/js/util";
+
+    export default {
+        data() {
+            return {
+                user: JSON.parse(sessionStorage.getItem("user")),
+                userDetailVisible: false,
+                userDetail:{},
+                date: null,
+                tableHeight: 0,
+                listLoading: false,
+                list: [],
+
+                addLoading: false,
+                
+                myChart: null,
+                params: null,
+            };
+        },
+        methods: {
+
+            assignToProject(){
+                var _this = this;
+                this.http.post('/finance/getTimeCost', {yearMonth: this.date},
+                res => {
+                    if (res.code == "ok") {
+                        var xList = [], yList = [], list = res.data.costList, 
+                        totalMoneyCost = res.data.totalMoneyCost;
+                        for(var i in list) {
+                            xList.push(list[i].project);
+                                yList.push({
+                                    "value": list[i].cost,
+                                    "id": list[i].id,
+                                    "time": list[i].workingTime
+                                });
+                        }
+
+                        var myChart = echarts.init(document.getElementById("container"));
+                        _this.myChart = myChart;
+                        var option = {
+                            title: {
+                                text: '项目成本统计 总计' + totalMoneyCost + '元',
+                                left:'left',
+                            },
+                            // 工具箱
+                            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 + "<br/>工作成本"+" : " + params[0].data.value 
+                                    + "元 <br/>工作时长"+" : " + params[0].data.time + "小时";
+                                    _this.params = params;
+                                    return res;
+                                }
+                            },
+                            xAxis: {
+                                data: xList,
+                                axisLabel: {
+                                    interval:0,rotate:20
+                                }
+                            },
+                            yAxis: [{
+                                type : 'value',
+                                axisLabel: {
+                                    formatter:'{value} (元)'
+                                }
+                            }],
+                            series: [{
+                                name: '工作时长(h)',
+                                type: 'bar',
+                                barMaxWidth: 30,
+                                data: yList,
+                            }]
+                        };
+                        myChart.setOption(option);
+                        // myChart.getZr().on('click', params => {
+                        //     const pointInPixel = [params.offsetX, params.offsetY];
+                        //     if (myChart.containPixel('grid', pointInPixel)) {
+                        //         console.log(_this.params)
+                        //         if(_this.radio=='项目') {
+                        //             _this.$router.push("/cost/" + _this.params[0].data.id + "/" + _this.params[0].name);
+                        //         }
+                        //     }
+                        // });
+                    } else {
+                        this.$message({
+                            message: res.msg,
+                            type: "error"
+                        });
+                    }
+                },
+                error => {
+                    this.$message({
+                        message: error,
+                        type: "error"
+                    });
+                });
+            },
+            //导出财务数据
+            exportData() {
+                this.listLoading = true;
+                this.http.post('/finance/exportData', {
+                    date: this.date
+                },
+                res => {
+                    this.listLoading = false;
+                    if (res.code == "ok") {
+                        var aTag = document.createElement('a');
+                        aTag.download = "财务成本统计.xls";
+                        aTag.href = res.data;
+                        aTag.click();
+                    } else {
+                        this.$message({
+                        message: res.msg,
+                        type: "error"
+                        });
+                    }
+                },
+                error => {
+                    this.listLoading = false;
+                    this.$message({
+                        message: error,
+                        type: "error"
+                    });
+                });
+            },
+            getSummaries(param) {
+                const { columns, data } = param;
+                const sums = [];
+                columns.forEach((column, index) => {
+                if (index === 0) {
+                    sums[index] = '总价';
+                    return;
+                }
+                const values = data.map(item => Number(item[column.property]));
+                if (!values.every(value => isNaN(value))) {
+                    sums[index] = values.reduce((prev, curr) => {
+                    const value = Number(curr);
+                    if (!isNaN(value)) {
+                        return prev + curr;
+                    } else {
+                        return prev;
+                    }
+                    }, 0);
+                    sums[index] += ' 元';
+                } else {
+                    sums[index] = 'N/A';
+                }
+                });
+
+                return sums;
+            },
+            changeMonth() {
+                //改变月份
+                this.getList();
+            },
+            // 批量导入人员
+            importFinance(item) {
+                //首先判断文件类型
+                let str = item.file.name.split(".");
+                let format = str[str.length - 1];
+                if (format != "xls" && format != "xlsx") {
+                    this.$message({
+                        message: "请选择.xls或.xlsx文件",
+                        type: "error"
+                    });
+                } else {
+                    this.listLoading = true;
+                    let formData = new FormData();
+                    formData.append("file", item.file);
+                    formData.append("companyId", this.user.companyId);
+                    console.log('date====='+this.date);
+                    formData.append("yearMonth", this.date);
+                    this.http.uploadFile('/finance/importData', formData,
+                    res => {
+                        this.$refs.upload.clearFiles();
+                        this.listLoading = false;
+                        if (res.code == "ok") {
+                            this.$message({
+                                message: "导入成功",
+                                type: "success"
+                            });
+                            //重新读取列表
+                            this.getList();
+                        } else {
+                            this.$message({
+                                message: res.msg,
+                                type: "error"
+                            });
+                        }
+                    },
+                    error => {
+                        this.$refs.upload.clearFiles();
+                        this.listLoading = false;
+                        this.$message({
+                            message: error,
+                            type: "error"
+                        });
+                    });
+                }
+            },
+
+            
+            //获取项目列表
+            getList() {
+                this.listLoading = true;
+                this.http.post('/finance/getByMonth', {
+                    companyId: this.user.companyId,
+                    yearMonth: this.date
+                },
+                res => {
+                    this.listLoading = false;
+                    if (res.code == "ok") {
+                        var list = res.data;
+                        this.list = list;
+                    } else {
+                        this.$message({
+                        message: res.msg,
+                        type: "error"
+                        });
+                    }
+                },
+                error => {
+                    this.listLoading = false;
+                    this.$message({
+                        message: error,
+                        type: "error"
+                    });
+                });
+            },
+
+        },
+        created() {
+            let height = window.innerHeight;
+            this.tableHeight = height - 205;
+            const that = this;
+            window.onresize = function temp() {
+                that.tableHeight = window.innerHeight - 205;
+            };
+            var d = new Date();
+            this.date = d.getFullYear() +'-'+ ((d.getMonth()+1) < 10? '0'+(d.getMonth()+1):d.getMonth()+1);
+            
+        },
+        mounted() {
+            this.getList();
+        },
+        updated() {
+            this.$nextTick(() => {
+                this.$refs['table'].doLayout();
+            }) 
+        }
+    };
+</script>
+
+<style lang="scss" scoped>
+</style>

+ 160 - 16
fhKeeper/formulahousekeeper/timesheet/src/views/project/list.vue

@@ -4,14 +4,18 @@
         <el-col :span="24" class="toolbar" style="padding-bottom: 0px;">
             <el-form :inline="true">
                 <el-form-item style="float:right;">
-                    <el-link type="primary" :underline="false" @click="handleAdd(-1)">新增项目</el-link>
+                    <el-link type="primary" :underline="false" @click="handleAdd(-1,null)">新增项目</el-link>
                 </el-form-item>
             </el-form>
         </el-col>
 
         <!--列表-->
         <el-table :data="list" highlight-current-row v-loading="listLoading" :height="tableHeight" style="width: 100%;">
-            <el-table-column type="index" width="60"></el-table-column>
+            <el-table-column type="index" width="60">
+                <template slot-scope="scope" >
+                        {{scope.$index+1+(page-1)*size}}
+                    </template>
+            </el-table-column>
             <el-table-column prop="projectCode" label="项目编码" sortable width="150"></el-table-column>
             <el-table-column prop="projectName" label="项目名称" sortable></el-table-column>
             <el-table-column prop="inchargerName" label="负责人" sortable width="150">
@@ -27,11 +31,11 @@
                     </v-for>
                 </template>
             </el-table-column>
-            <el-table-column label="操作" width="220">
+            <el-table-column label="操作" width="290">
                 <template slot-scope="scope">
-                    <!-- <el-button size="small" type="primary" @click="detail(scope.$index)">详情</el-button> -->
-                    <el-button size="small" type="primary" @click="handleAdd(scope.$index)">编辑</el-button>
-                    <el-button size="small" type="danger" @click="deletePro(scope.$index)">删除</el-button>
+                    <el-button size="small" type="primary" @click="subProject(scope.row)">子项目</el-button>
+                    <el-button size="small" type="primary" @click="handleAdd(scope.$index, scope.row)">编辑</el-button>
+                    <el-button size="small" type="danger" @click="deletePro(scope.$index, scope.row)">删除</el-button>
                 </template>
             </el-table-column>
         </el-table>
@@ -86,6 +90,42 @@
                 <el-button type="primary" @click="userDetailVisible = false" >确定</el-button>
             </div>
         </el-dialog>
+        <!-- 子项目列表 -->
+        <el-dialog title="子项目列表" show-header="false" v-if="subProjectVisible" :visible.sync="subProjectVisible" :close-on-click-modal="false" customClass="customWidth" width="500px">
+            <el-table :data="subProjectList" highlight-current-row  height="400" style="width: 100%;">
+            <el-table-column type="index" width="60" label="序号">
+                <template slot-scope="scope" >
+                        {{scope.$index+1+(page-1)*size}}
+                    </template>
+            </el-table-column>
+            <el-table-column prop="name" label="名称" ></el-table-column>
+            <el-table-column label="操作" width="150">
+                <template slot-scope="scope" >
+                    <el-button size="small" type="primary" @click="addNewSubProject(scope.row)">编辑</el-button>
+                    <el-button size="small" type="danger" @click="deleteSubPro(scope.row)">删除</el-button>
+                </template>
+            </el-table-column>
+
+            </el-table>
+            <div slot="footer" class="dialog-footer">
+                <el-button type="primary" @click="subProjectVisible = false" >关闭</el-button>
+                <el-button type="primary" @click="addNewSubProject()" >新增子项目</el-button>
+            </div>
+        </el-dialog>
+
+
+        <!-- 新增子项目弹出框 -->
+        <el-dialog title="新增/修改子项目" v-if="addSubProject" :visible.sync="addSubProject" :close-on-click-modal="false" customClass="customWidth" width="500px">
+            <el-form ref="form2" :model="addForm" :rules="rules" label-width="100px">
+                <el-form-item label="项目名称" prop="name">
+                    <el-input v-model="addForm.name" placeholder="请输入项目名称" clearable></el-input>
+                </el-form-item>
+            </el-form>
+            <div slot="footer" class="dialog-footer">
+                <el-button @click.native="addSubProject = false">取消</el-button>
+                <el-button type="primary" @click="submitInsertSubProject" :loading="addLoading">提交</el-button>
+            </div>
+        </el-dialog>
     </section>
 </template>
 <style scoped>
@@ -117,7 +157,10 @@
                 page: 1,
                 size: 20,
                 list: [],
-
+                subProjectVisible: false,
+                subProjectList: [],//子项目列表
+                currentProject:{},
+                addSubProject: false,
                 addFormVisible: false,
                 addLoading: false,
                 title: "",
@@ -131,6 +174,76 @@
             };
         },
         methods: {
+            deleteSubPro(subProject) {
+                this.$confirm("确定要删除子项目" + subProject.name + "吗?","删除子项目", {
+                    confirmButtonText: "确定",
+                    cancelButtonText: "取消",
+                    type: "warning"
+                })
+                .then(() => {
+                    this.listLoading = true;
+                    this.http.post('/sub-project/deleteProject',{ 
+                        id: subProject.id 
+                    },
+                    res => {
+                        this.listLoading = false;
+                        if (res.code == "ok") {
+                            this.$message({
+                                message: "删除成功",
+                                type: "success"
+                            });
+                            this.subProject(this.currentProject);
+                        } else {
+                            this.$message({
+                                message: res.msg,
+                                type: "error"
+                            });
+                        }
+                    },
+                    error => {
+                        this.listLoading = false;
+                        this.$message({
+                            message: error,
+                            type: "error"
+                        });
+                        }
+                    );
+                })
+                .catch(() => {});
+            },
+            
+            addNewSubProject(subProject) {
+                if (subProject == null) {
+                    this.addForm = {projectId: this.currentProject.id}
+                } else {
+                    this.addForm = subProject;
+                }
+                this.addSubProject = true;
+            },
+            //显示子项目
+            subProject(item) {
+                this.subProjectVisible = true;
+                this.currentProject = item;
+                this.http.post('/sub-project/list', {
+                    projectId: item.id
+                },
+                res => {
+                    if (res.code == "ok") {
+                        this.subProjectList = res.data;
+                    } else {
+                        this.$message({
+                        message: res.msg,
+                        type: "error"
+                        });
+                    }
+                },
+                error => {
+                    this.$message({
+                        message: error,
+                        type: "error"
+                    });
+                });
+            },
             //显示用户详情
             showUser(userId) {
                 this.userDetailVisible = true;
@@ -242,7 +355,7 @@
             },
 
             //显示新增界面
-            handleAdd(i) {
+            handleAdd(i, item) {
                 if(i == -1) {
                     this.title = "新增项目";
                     this.addForm = {
@@ -253,23 +366,54 @@
                     }
                 } else {
                     this.title = "修改项目";
-                    var list = this.list[i].participator , arr = [];
+                    var list = item.participator , arr = [];
                     for(var j in list) {
                         arr.push(list[j].id)
                     }
                     
                     this.addForm = {
-                        id: this.list[i].id,
-                        name: this.list[i].projectName,
+                        id: item.id,
+                        name: item.projectName,
                         userId: arr,
-                        code:this.list[i].projectCode,
-                        inchargerId: this.list[i].inchargerId
+                        code:item.projectCode,
+                        inchargerId: item.inchargerId
                     }
                     this.changeParticipator();
                 }
                 this.addFormVisible = true;
             },
 
+            //提交子项目创建修改请求
+            submitInsertSubProject () {
+                this.$refs.form2.validate(valid => {
+                    if (valid) {
+                        this.http.post('/sub-project/saveOrUpdate',this.addForm,
+                        res => {
+                            if (res.code == "ok") {
+                                this.$message({
+                                    message: "操作成功",
+                                    type: "success"
+                                });
+                                this.subProject(this.currentProject);
+                                this.addSubProject = false;
+                            } else {
+                                this.$message({
+                                    message: res.msg,
+                                    type: "error"
+                                });
+                            }
+                        },
+                        error => {
+                            this.listLoading = false;
+                            this.$message({
+                                message: error,
+                                type: "error"
+                            });
+                            }
+                        );
+                        }
+                });
+            },
             submitInsert() {
                 this.$refs.form1.validate(valid => {
                     if (valid) {
@@ -320,8 +464,8 @@
             },
 
             // 删除
-            deletePro(i) {
-                this.$confirm("确定要项目" + this.list[i].projectName + "吗?","删除项目", {
+            deletePro(i, item) {
+                this.$confirm("确定要项目" + item.projectName + "吗?","删除项目", {
                     confirmButtonText: "确定",
                     cancelButtonText: "取消",
                     type: "warning"
@@ -329,7 +473,7 @@
                 .then(() => {
                     this.listLoading = true;
                     this.http.post(this.port.project.delete,{ 
-                        id: this.list[i].id 
+                        id: item.id 
                     },
                     res => {
                         this.listLoading = false;

+ 121 - 11
fhKeeper/formulahousekeeper/timesheet/src/views/settings/timetype.vue

@@ -1,12 +1,41 @@
 <template>
     <section>
-        <h4 style="width:450px;margin:0 auto;">工作时长设置</h4>
-        <!--设置内容-->
-        <el-form style="width:550px;margin:0 auto;padding:10px;" ref="form1" :model="timeType" :rules="rules" label-width="120px">
-        <el-form-item label="平均每月工作" prop="allday">
+        <el-col :span="24" class="toolbar" style="padding-bottom: 0px;">
+            <el-form :inline="true">
+                <el-form-item label="系统基础设置" style="margin-top:5px;">
+            </el-form-item>
+            </el-form>
+        </el-col>
+        <p style="padding-top:80px;margin-left:10px;color:#666;">员工时薪录入方式设置</p>
+        <div class="panel" style="height:100px;margin-left:20px;margin-right:20px;">
+        <el-radio v-model="timeType.hourCostInputType" :label="0" style="width:100%;margin-left:10px;">方式一: 录入月薪,自动计算时薪
+            <el-form ref="form0" :inline=true :model="timeType" label-width="120px">
+            <el-form-item label="平均每月工作" prop="monthDays">
             <el-input v-model="timeType.monthDays"  type="number" style="width:150px;"></el-input>
-        </el-form-item>    
+            </el-form-item>    
+            <el-form-item label="每日工作时长" prop="allday">
+                <el-select v-model="timeType.allday" placeholder="请选择工作时长" style="width:150px;" @change="timeChange">
+                    <el-option v-for="item in times" :key="item" :label="item" :value="item"></el-option>
+                </el-select>
+                小时<span style="color:orange;margin-left:10px;font-size:12px;vertical-align:center;">(时薪 = 月薪/每月工作天数/每天工作时长)</span>
+            </el-form-item>
+            </el-form>
+        </el-radio>
+        <el-radio v-model="timeType.hourCostInputType" :label="1" style="width:100%;margin-left:10px;">方式二:直接录入时薪</el-radio>
+        </div>
+        <el-divider></el-divider>
+        <!--设置时长样式内容-->
+        <p style="margin-left:10px;color:#666;">员工工作时长上报方式设置</p>
+        <el-row :gutter="20" style="padding-top:10px;width:100%;margin:0 auto;padding-left:10px;padding-right:10px;">
+        <el-col :span="8" >
+        <!-- 上下午固定时长-->
+        <div class="panel" >
+        <el-radio v-model="timeType.type" :label="0" style="width:100%">全天/上午/下午便捷上报
+        <el-form  ref="form1" :model="timeType" :rules="rules" label-width="120px" style="color:#333;">
+        <el-form-item>
+        </el-form-item>  
+        <span style="color:#999;">请设置时长</span>
         <el-form-item label="全天时长" prop="allday">
             <el-select v-model="timeType.allday" placeholder="请选择工作时长" style="width:150px;" @change="timeChange">
                 <el-option v-for="item in times" :key="item" :label="item" :value="item"></el-option>
@@ -14,7 +43,7 @@
             小时
         </el-form-item>
         <el-form-item label="上午时长" prop="am" >
-             <el-select v-model="timeType.am" placeholder="请选择工作时长" style="width:150px;" @change="timeChange">
+            <el-select v-model="timeType.am" placeholder="请选择工作时长" style="width:150px;" @change="timeChange">
                 <el-option v-for="item in halfTime" :key="item" :label="item" :value="item"></el-option>
             </el-select>
             小时
@@ -25,10 +54,72 @@
             </el-select>
             小时
         </el-form-item>
-        <div style="float:right;margin-right:300px;" >
-            <el-button type="primary" @click="submitInsert" :loading="addLoading">保存</el-button>
-        </div>
         </el-form>
+        </el-radio>
+        </div>
+        </el-col>
+        <!-- 选择小时数样式 -->
+        <el-col :span="8">   
+        <div class="panel">
+        <el-radio v-model="timeType.type" :label="1">自行选择工作时长
+        <div  class="sample">
+        <p>
+            展示样例
+        </p>
+        <div>
+            工作时长: 
+            <el-select v-model="selectTime" >
+                <el-option v-for="item in timeRange" :key="item" :value="item.toFixed(1)">{{item.toFixed(1)}}</el-option>
+            </el-select>
+            小时
+        </div>
+        
+        </div>
+        </el-radio>
+        </div>
+        
+        </el-col>
+        <!--选择时间段样式 -->
+        <el-col :span="8">  
+        <div  class="panel" >
+            <el-radio v-model="timeType.type" :label="2">自行选择时间范围
+            <div class="sample">
+            <p>
+            展示样例
+            </p>
+            <div style="width:500px;">
+                开始时间:<el-time-select
+                    placeholder="起始时间"
+                    v-model="startTime"
+                    :picker-options="{
+                    start: '08:30',
+                    step: '00:15',
+                    end: '18:30'
+                    }">
+                </el-time-select>
+            </div>
+            <div style="margin-top:5px;">
+               结束时间:<el-time-select
+                    placeholder="结束时间"
+                    v-model="endTime"
+                    :picker-options="{
+                    start: '08:30',
+                    step: '00:15',
+                    end: '18:30',
+                    minTime: startTime
+                    }">
+                </el-time-select>
+            </div>
+                </div>
+            </el-radio> 
+            
+        </div>
+        </el-col>
+        </el-row>
+
+        <div style="width:80px;margin:0 auto;padding:20px;">
+            <el-button  type="primary" @click="submitInsert" :loading="addLoading">保存</el-button>
+        </div>
         
     </section>
 </template>
@@ -38,12 +129,21 @@
     export default {
         data() {
             return {
+                startTime:null,
+                endTime:null,
+                timeRange:[0.5,1.0,1.5,2.0,2.5,3.0,3.5,4.0,4.5,5.0,5.5,6.0,6.5,7.0,7.5,8.0,8.5,9.0,9.5,10.0,10.5,11.0,11.5,12.5,13.0,13.5,14.0,14.5,15.0],
+                selectTime:null,
                 times:[],
                 halfTime:[],
                 user: JSON.parse(sessionStorage.getItem("user")),
-                timeType:{},
+                timeType:{allday: 8,
+                am: 4,
+                companyId: 10,
+                hourCostInputType: 0,
+                monthDays: 21.75,
+                pm: 4,
+                type: 0},
                 rules: {
-                    monthDays: [{ required: true, message: "请输入平均每月工作天数", trigger: "blur" }],
                     allday: [{ required: true, message: "请选择全天工作时长", trigger: "blur" }],
                     am: [{ required: true, message: "请输入上午工作时长", trigger: "blur" }],
                     pm: [{ required: true, message: "请输入下午工作时长", trigger: "blur" }],
@@ -51,6 +151,9 @@
             };
         },
         methods: {
+            selectPanel(type) {
+                this.timeType.type = type;
+            },
             timeChange() {
                 this.halfTime = [];
                 for (var i=1;i<=this.timeType.allday; i++) {
@@ -144,4 +247,11 @@
 </script>
 
 <style lang="scss" scoped>
+.panel {
+    padding:15px;height:300px;box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04)
+}
+.sample {
+    margin-top:30px;
+    color: #999;
+}
 </style>

+ 59 - 18
fhKeeper/formulahousekeeper/timesheet/src/views/team/index.vue

@@ -29,6 +29,9 @@
                             {{depData!=null?depData.label:''}}
                         </div>
                     </el-form-item>
+                    <el-form-item>
+                        <div style="color:#999;font-size:13px;">共{{total}}人</div>
+                    </el-form-item>
                     <el-form-item style="float:right;">
                         <el-link type="primary" :underline="false" @click="openInsertDialog(null)">添加人员</el-link>
                     </el-form-item>
@@ -53,15 +56,22 @@
 
             <!--列表-->
             <el-table :data="list" highlight-current-row v-loading="listLoading" :height="tableHeight" style="width: 100%;">
-                <el-table-column type="index" width="40"></el-table-column>
+                <el-table-column type="index" width="50">
+                    <template slot-scope="scope" >
+                        {{scope.$index+1+(page-1)*size}}
+                    </template>
+                </el-table-column>
                 <el-table-column prop="name" label="姓名" sortable></el-table-column>
                 <el-table-column prop="phone" label="手机" width="120"></el-table-column>
                 <el-table-column prop="departmentName" label="部门" sortable></el-table-column>
                 <el-table-column label="角色" width="100">
                     <template slot-scope="scope">{{scope.row.role == 0 ? "普通员工" : scope.row.role == 1 ? "负责人" : "管理员"}}</template>
                 </el-table-column>
-                <el-table-column prop="cost" label="成本" sortable>
-                    <template slot-scope="scope">{{scope.row.cost==null?0:scope.row.cost}} 元 / 小时</template>
+                <el-table-column prop="monthCost" label="月薪" sortable>
+                    <template slot-scope="scope">{{scope.row.monthCost==null?0:scope.row.monthCost}} 元</template>
+                </el-table-column>
+                <el-table-column prop="cost" label="时薪" sortable>
+                    <template slot-scope="scope">{{scope.row.cost==null?0:scope.row.cost}} 元</template>
                 </el-table-column>
                 <el-table-column label="操作" width="280">
                     <template slot-scope="scope">
@@ -80,7 +90,7 @@
                     @size-change="handleSizeChange"
                     @current-change="handleCurrentChange"
                     :page-sizes="[20 , 50 , 80 , 100]"
-                    :page-size="20"
+                    :page-size="size"
                     layout="total, sizes, prev, pager, next"
                     :total="total"
                     style="float:right;"
@@ -89,7 +99,7 @@
         </el-col>
 
         <!-- 新增部门 -->
-        <el-dialog :title="depTitle" :visible.sync="departmentVisible" width="400px">
+        <el-dialog :title="depTitle" :visible.sync="departmentVisible" width="400px" >
             <el-form ref="depForm" :model="depForm" :rules="depRules" label-width="80px">
                 <el-form-item label="部门名称" prop="name">
                     <el-input v-model="depForm.name" placeholder="请输入部门名称" clearable></el-input>
@@ -102,25 +112,31 @@
         </el-dialog>
 
         <!-- 新增单个人员的Dialog -->
-        <el-dialog :title="title" :visible.sync="dialogVisible" width="400px">
-            <el-form ref="form1" :model="insertForm" :rules="rules" label-width="60px">
+        <el-dialog :title="title" :visible.sync="dialogVisible" width="450px" >
+            <el-form ref="form1" :model="insertForm" :rules="rules" label-width="80px">
                 <el-form-item label="名字" prop="name">
                     <el-input v-model="insertForm.name" placeholder="请输入姓名" clearable></el-input>
                 </el-form-item>
                 <el-form-item label="电话" prop="phone">
                     <el-input v-model="insertForm.phone" placeholder="请输入电话号码" clearable></el-input>
                 </el-form-item>
-                <el-form-item label="月薪" prop="monthCost">
+                <el-form-item label="薪酬方式" prop="salaryType">
+                    <el-radio-group v-model="insertForm.salaryType" @change="onSalaryTypeChange">
+                    <el-radio  :label="0" >固定月薪</el-radio>
+                    <el-radio  :label="1">计时工资</el-radio>
+                    </el-radio-group>
+                </el-form-item>
+                <el-form-item label="月薪" prop="monthCost" v-if="insertForm.salaryType == 0">
                     <el-input v-model.number="insertForm.monthCost" @input="oninput" placeholder="请输入月薪,单位:元" clearable></el-input>
                     <span style="color:orange;font-size:12px;">按照每个月工作{{timeType.monthDays}}天,每天{{timeType.allday}}小时核算</span>
                     <el-link :underline="false" style="color:blue;font-size:12px;margin-left:7px;" href="#/timetype">修改工作时长</el-link>
                 </el-form-item>
                 <el-form-item label="时薪" prop="cost">
-                    <el-input v-model.number="insertForm.cost" disabled placeholder="请输入成本 单位:元/小时" clearable></el-input>
+                    <el-input v-model.number="insertForm.cost" :disabled="insertForm.salaryType == 0" placeholder="请输入成本 单位:元/小时" clearable></el-input>
                 </el-form-item>
                 <el-form-item label="部门" prop="departmentId">
                     <el-cascader v-model="insertForm.departmentId" placeholder="请选择部门" style="width: 100%"
-                    :options="option" :props="{ checkStrictly: true }" :show-all-levels="false" clearable></el-cascader>
+                    :options="option" :props="{ checkStrictly: false,expandTrigger: 'hover' }" :show-all-levels="false" clearable></el-cascader>
                 </el-form-item>
                 <el-form-item label="角色" prop="role">
                     <el-select v-model="insertForm.role" placeholder="请选择角色" style="width: 100%">
@@ -135,19 +151,29 @@
             </span>
         </el-dialog>
 
-        <el-dialog title="修改成本" :visible.sync="dialogVisible1" width="400px">
-            <el-form ref="form1" :model="insertForm" :rules="rules" label-width="60px">
-                <el-form-item label="月薪" prop="monthCost">
+        <el-dialog title="修改成本" :visible.sync="dialogVisible1" width="450px" >
+            <el-form ref="form1" :model="insertForm" :rules="rules" label-width="80px">
+                <el-form-item label="薪酬方式" prop="salaryType">
+                    <el-radio-group v-model="insertForm.salaryType" @change="onSalaryTypeChange">
+                    <el-radio  :label="0" >固定月薪</el-radio>
+                    <el-radio  :label="1">计时工资</el-radio>
+                    </el-radio-group>
+                </el-form-item>
+                <el-form-item label="月薪" prop="monthCost" v-if="insertForm.salaryType == 0">
                     <el-input v-model.number="insertForm.monthCost" @input="oninput" placeholder="请输入月薪,单位:元" clearable></el-input>
                     <span style="color:orange;font-size:12px;">按照每个月工作{{timeType.monthDays}}天,每天{{timeType.allday}}小时核算</span>
                     <el-link :underline="false" style="color:blue;font-size:12px;margin-left:7px;" href="#/timetype">修改工作时长</el-link>
                 </el-form-item>
                 <el-form-item label="时薪" prop="cost">
-                    <el-input v-model.number="insertForm.cost" disabled placeholder="请输入成本 单位:元/小时" clearable></el-input>
+                    <el-input v-model.number="insertForm.cost" :disabled="insertForm.salaryType == 0" placeholder="请输入成本 单位:元/小时" clearable></el-input>
                 </el-form-item>
                 <el-form-item label="部门" prop="departmentId">
-                    <el-cascader v-model="insertForm.departmentId" placeholder="请选择部门" style="width: 100%"
-                    :options="option" :props="{ checkStrictly: true }" :show-all-levels="false" clearable></el-cascader>
+                    <el-cascader v-model="insertForm.departmentId" 
+                    placeholder="请选择部门" 
+                    style="width: 100%"
+                    :options="option" 
+                    :props="{ checkStrictly: false,expandTrigger: 'hover' }" :show-all-levels="false" 
+                    clearable></el-cascader>
                 </el-form-item>
             </el-form>
             <span slot="footer" class="dialog-footer">
@@ -162,6 +188,7 @@
     export default {
         data() {
             return {
+                value:{},
                 user: JSON.parse(sessionStorage.getItem("user")),
 
                 tableHeight: 0,
@@ -201,12 +228,12 @@
                     monthCost:null,
                     cost: null,
                     departmentId: null,
+                    salaryType:0,
                 },
                 rules: {
                     name: [{ required: true, message: "请输入姓名", trigger: "blur" }],
                     phone: [{ required: true, message: "请输入电话", trigger: "blur" }],
                     role: [{ required: true, message: "请选择角色", trigger: "blur" }],
-                    monthCost: [{ required: true, message: "请输入月薪,单位:元", trigger: "blur" }],
                     cost: [{ required: true, message: "请输入成本", trigger: "blur" }]
                 },
 
@@ -226,6 +253,15 @@
             };
         },
         methods: {
+            onSalaryTypeChange(value) {
+                if (value == 1) {
+                    this.insertForm.monthCost = null;
+                }
+            },
+            //选中部门
+            choseDept(value) {
+                console.log(value);
+            },
             //月薪输入变化
             oninput(e) {
                 this.insertForm.cost = (this.insertForm.monthCost/this.timeType.monthDays/this.timeType.allday).toFixed(2);
@@ -362,6 +398,7 @@
                         monthCost:list.monthCost,
                         cost: list.cost,
                         departmentId: array.reverse(),
+                        salaryType: list.salaryType
                     };
                     this.title = "编辑人员"
                 } else {
@@ -373,6 +410,7 @@
                         monthCost:null,
                         cost: null,
                         departmentId: null,
+                        salaryType:0,
                     };
                     this.title = "新增人员"
                 }
@@ -388,7 +426,8 @@
                             phone: this.insertForm.phone,
                             role: this.insertForm.role,
                             monthCost: this.insertForm.monthCost,
-                            cost: this.insertForm.cost
+                            cost: this.insertForm.cost,
+                            salaryType: this.insertForm.salaryType
                         };
                         if (this.insertForm.id != null) {
                             form.id = this.insertForm.id;
@@ -512,6 +551,7 @@
                     monthCost:list1.monthCost,
                     cost: list1.cost,
                     departmentId: array1.reverse(),
+                    salaryType: list1.salaryType
                 };
                 this.dialogVisible1 = true;
             },
@@ -614,6 +654,7 @@
             handleNodeClick(data) {
                 if(this.depData == null || data.id != this.depData.id) {
                     this.depData = data;
+                    this.page = 1;
                     this.getUser();
                 }
             },

+ 331 - 105
fhKeeper/formulahousekeeper/timesheet/src/views/workReport/daily.vue

@@ -17,11 +17,11 @@
                     <span >
                     <span>日期:</span>
                     <span v-for="(item,index) in allDate" :id="'day'+index" :class="index==choseDay?'chooseDate date_item':'date_item'" 
-                    @click="choseDate(index)" :key="index">{{item}}</span>
+                    @click="choseDate(index, item)" :key="index">{{item}}</span>
                     </span>
                 </div>
-                <div>
-                <div style="float:left;width:200px;" v-if="user.role == 1">
+                <div style="display:flex;">
+                <div v-if="user.role > 0">
                     <div>
                         <el-select v-model="selectState" size="small" @change="stateChange">
                         <el-option value="-1" label="全部状态" >全部状态</el-option>
@@ -29,6 +29,7 @@
                         <el-option value="1" label="已通过">已通过</el-option>
                         <el-option value="0" label="待审核">待审核</el-option>
                         <el-option value="2" label="不通过">不通过</el-option>
+                        <el-option value="3" label="已撤回">已撤回</el-option>
                         </el-select></div>
                     <div>
                         <el-tree :data="data"  @node-click="handleNodeClick" >
@@ -48,23 +49,35 @@
                             <span v-if="data.isUser == 1 && data.state == 2" style="color:red;">
                             未通过
                             </span>
+                            <span v-if="data.isUser == 1 && data.state == 3" style="color:red;">
+                            已撤回
+                            </span>
                             </div>
                         </span>
                         </el-tree>
                     </div>
                 </div>
                 
-                <div :style="'height:'+tableHeight+'px;width:0.5px;background:#eee;margin-right:10px;float:left;'" ></div>
-                <div class="allDaily" style="float:left;">
-                    <div class="report_title"><span>工作日报 | {{depData.label}}</span> - 已填写<span style="margin-left:5px;margin-right:5px;color:red;">{{reportList.length}}</span>人,
+                <div :style="'height:'+tableHeight+'px;width:0.5px;background:#eee;margin-right:10px;margin-left:10px;'" ></div>
+                <div class="allDaily" style="float:left;flex-grow:1">
+                    <!--系统管理员 -->
+                    <div class="report_title" v-if="user.role > 0">
+                        <span>工作日报 | {{depData.label}}</span> - 已填写<span style="margin-left:5px;margin-right:5px;color:green;">{{reportList.length}}</span>人,
                     未填写<span style="margin-left:5px;margin-right:5px;color:red;">{{(depData == null?data[0].membCount:(depData.isUser == 1?1:depData.membCount))-reportList.length}}</span>人
                         <span style="float:right;">
                             <el-link type="primary" style="margin-right:10px;" :underline="false" @click="fillInReport(-1)">填写日报</el-link>
-                            <el-link type="primary" style="margin-right:10px;" :underline="false" v-if="user.role != 0" @click="exportReport">导出日报</el-link>
-                            <el-link type="primary" style="margin-right:10px;" :underline="false" v-if="user.role != 0" @click="batchApprove">批量审核</el-link>
+                            <el-link type="primary" style="margin-right:10px;" :underline="false" @click="exportReport">导出日报</el-link>
+                            <el-link type="primary" style="margin-right:10px;" :underline="false" @click="batchApprove">批量审核</el-link>
                         </span>
                     </div>
-                    <div style="height:490px;overflow:scroll;padding-top:10px;">
+                    <!--普通员工,含项目经理 -->
+                    <div class="report_title" v-if="user.role==0"><span>日报列表</span>
+                    <span style="float:right;" v-if="user.role==0">
+                            <el-link type="primary" style="margin-right:10px;" :underline="false" @click="fillInReport(-1)">填写日报</el-link>
+                            <el-link type="primary" v-if="user.leader" style="margin-right:10px;" :underline="false" @click="batchApprove">批量审核</el-link>
+                    </span>
+                    </div>
+                    <div :style="'height:'+(tableHeight-50)+'px;overflow:scroll;padding-top:10px;'">
                         <div class="one_daily" v-for="(item1,index1) in reportList" :key="index1">
                             <i class="fa fa-circle"></i>{{item1.name}}
                             <span style="margin-left:30px;">
@@ -76,24 +89,30 @@
                                     <span style="margin-left:10px;">成本:</span>
                                     <span >{{item1.cost}}</span>元
                                 </span>
-                                <!-- <el-link v-if="user.role != 0" type="primary" :underline="false" @click="junpToDeskTop(item1.id)">系统智能统计:{{item1.calculateTime}}h</el-link>
-                                <span v-else>系统智能统计:{{item1.calculateTime}}h</span> -->
-                                <span style="margin-left:15px;color:#DAA520;" v-if="item1.state == 0">[ 待审核 ]</span>
-                                <span style="margin-left:15px;color:#32CD32;" v-else-if="item1.state == 1">[ 已通过 ]</span>
-                                <span style="margin-left:15px;color:#FF0000;" v-else-if="item1.state == 2">[ 已驳回 ]</span>
                             </span>
                             <div class="checkbtn">
-                                <el-button v-if="user.role != 0 && item1.state == 0" type="primary" :loading="logining" size="small" @click="approve(item1.id)">通过</el-button>
-                                <el-button v-if="user.role != 0 && item1.state == 0" type="danger" :loading="logining" size="small" @click="deny(item1.id,0)">驳回</el-button>
-                                <el-button v-if="user.role != 0 && item1.state == 1" type="danger" :loading="logining" size="small" @click="deny(item1.id,1)">撤销</el-button>
-                                <el-button v-if="item1.state == 2 && user.id == item1.id" type="primary" size="small" @click="fillInReport(index1)">编辑日报</el-button>
+                                <el-button v-if="(user.role != 0 || user.id == item1.data[0].inchargerId) && item1.state == 0" type="primary" :loading="logining" size="small" @click="approve(item1.id, item1)">通过</el-button>
+                                <el-button v-if="(user.role != 0 || user.id == item1.data[0].inchargerId) && item1.state == 0" type="danger" :loading="logining" size="small" @click="deny(item1.id,0, item1)">驳回</el-button>
+                                <!--自己可以撤回待审核状态的报告 -->
+                                <el-button v-if="(user.id == item1.id) && item1.state == 0" type="normal" :loading="logining" size="small" @click="cancel(item1)">撤回</el-button>
+                                <el-button v-if="(user.role != 0 || user.id == item1.data[0].inchargerId) && item1.state == 1" type="normal" :loading="logining" size="small" @click="deny(item1.id,1, item1)">撤销</el-button>
+                                <el-button v-if="item1.state >= 2 && user.id == item1.id" type="primary" size="small" @click="fillInReport(index1)">编辑日报</el-button>
                             </div>
                             <div class="one_daily_body">
                                 <el-timeline>
                                     <el-timeline-item v-for="(item2,index2) in item1.data" :key="index2">
                                         <el-card shadow="never">
-                                            <p>项目:<b>{{item2.project}}</b></p>
-                                            <p>时长:{{item2.time}}h  ({{typeList[item2.timeType]}})</p>
+                                            <p>项目:<b>{{item2.project}}</b><span v-if="item2.subProjectName != null"> / {{item2.subProjectName}}</span>
+                                            <span style="margin-left:15px;color:#DAA520;" v-if="item2.state == 0">[ 待审核 ]</span>
+                                            <span style="margin-left:15px;color:#32CD32;" v-else-if="item2.state == 1">[ 已通过 ]</span>
+                                            <span style="margin-left:15px;color:#FF0000;" v-else-if="item2.state == 2">[ 已驳回 ]</span>
+                                            <span style="margin-left:15px;color:#FF0000;" v-else-if="item2.state == 3">[ 已撤回 ]</span>
+                                            </p>
+                                            <p>时长:
+                                                <span v-if="item2.reportTimeType == 0" style="margin-right:10px;">{{typeList[item2.timeType]}}</span>
+                                                <span v-if="item2.reportTimeType == 2" style="margin-right:10px;">{{item2.startTime+'-'+item2.endTime}}</span>
+                                            {{item2.time.toFixed(1)}}h  
+                                            </p>
                                             <p>事项:<span v-html="item2.content"></span></p>
                                         </el-card>
                                     </el-timeline-item>
@@ -101,7 +120,7 @@
                             </div>
                         </div>
                         <!-- 简陋的无报告提示 -->
-                        <div v-if="reportList.length==0" style="width:800px;font-size:17px;text-align:center;color:#aaa;">今日暂无报告</div>
+                        <div v-if="reportList.length==0" style="width:100%;font-size:17px;text-align:center;color:#aaa;">{{curDate}}暂无报告</div>
                     </div>
                 </div>
                 </div>
@@ -121,12 +140,15 @@
                 </el-form-item> -->
                 
                 <div v-for="(domain, index) in workForm.domains" :key="domain.id">
-                    <el-form-item label="工作时" :prop="'domains.' + index + '.timeType'"
-                        :rules="{ required: true, message: '请选择工作时', trigger: 'blur' }">
+                    <el-form-item label="工作时" :prop="'domains.' + index + '.timeType'"
+                        :rules="{ required: true, message: '请选择工作时', trigger: 'blur' }">
                         <!-- <el-input v-model.number="domain.workingTime" placeholder="请输入投入时长" type='number' clearable style="width:200px;"
                          :disabled="workForm.domains.length==0?true:(workForm.domains[0].state==2?false:true)"></el-input> -->
-                        <el-select v-model="domain.timeType" placeholder="请选择工作时间" 
-                        :disabled="workForm.domains.length==0?true:(workForm.domains[0].state==2?false:true)"
+                        <!-- 全天/上下午 -->
+                        <el-select v-model="domain.timeType" 
+                        v-if="reportTimeType.type == 0"
+                        placeholder="请选择工作时长" 
+                        :disabled="workForm.domains.length==0?true:(workForm.domains[index].state>=2?false:true)"
                         @change="onTimeTypeChange(domain.timeType)">
                         <el-option
                             v-for="item in timeType"
@@ -134,38 +156,78 @@
                             :label="item.label"
                             :value="item.value">
                             </el-option>
-                         </el-select>
+                        </el-select>
+                        <!-- 数字时长选择 -->
+                        <el-select v-model="domain.workingTime" 
+                        v-if="reportTimeType.type == 1"
+                        :disabled="workForm.domains.length==0?true:(workForm.domains[index].state>=2?false:true)"
+                        placeholder="请选择工作时长" >
+                        <el-option v-for="item in timeRange" :key="item" :value="item.toFixed(1)">{{item.toFixed(1)}}</el-option>
+                        </el-select>
+                        <span v-if="reportTimeType.type == 1">小时</span>
+                        <span v-if="reportTimeType.type == 2">
+                        <!--时间范围选择 -->
+                        <el-time-select 
+                        :disabled="workForm.domains.length==0?true:(workForm.domains[index].state>=2?false:true)"
+                            placeholder="起始时间"
+                            style="width:120px;"
+                            v-model="domain.startTime"
+                            :picker-options="{
+                            start: '08:00',
+                            step: '00:30',
+                            end: '23:30'
+                            }">
+                        </el-time-select> - <el-time-select 
+                        :disabled="workForm.domains.length==0?true:(workForm.domains[index].state>=2?false:true)"
+                            placeholder="结束时间"
+                            style="width:120px;"
+                            v-model="domain.endTime"
+                            :picker-options="{
+                            start: '08:00',
+                            step: '00:30',
+                            end: '23:30',
+                            minTime: domain.startTime
+                            }">
+                        </el-time-select>
+                        </span>
                     </el-form-item>
                     <el-form-item label="投入项目" :prop="'domains.' + index + '.projectId'"
                         :rules="{ required: true, message: '请选择投入项目', trigger: ['change','blur'] }">
-                        <el-select v-model="domain.projectId" placeholder="请选择" style="width:200px;"
-                        :disabled="workForm.domains.length==0?true:(workForm.domains[0].state==2?false:true)">
+                        <el-select v-model="domain.projectId" placeholder="请选择" style="width:200px;" clearable="true" @change="selectProject(domain, index)"
+                        :disabled="workForm.domains.length==0?true:(workForm.domains[index].state>=2?false:true)">
                             <el-option v-for="item in projectList" :key="item.id" :label="item.projectName" :value="item.id"></el-option>
                         </el-select>
+                        <!--子项目 -->
+                        <el-select v-model="domain.subProjectId" placeholder="请选择" style="width:200px;" clearable="true" v-if="domain.subProjectList != null && domain.subProjectList.length> 0"
+                        :disabled="workForm.domains.length==0?true:(workForm.domains[index].state>=2?false:true)">
+                            <el-option v-for="item in domain.subProjectList" :key="item.id" :label="item.name" :value="item.id"></el-option>
+                        </el-select>
+                        
                         <el-link v-if="index >= 1" type="primary" :underline="false" @click="delDomain(index)" style="float:right;margin-right:10px;"
-                            :disabled="workForm.domains.length==0?true:(workForm.domains[0].state==2?false:true)">
+                            :disabled="workForm.domains.length==0?true:(workForm.domains[index].state>=2?false:true)">
                             <i class="fa fa-trash" style="color: red;;font-size:18px;"></i>
                         </el-link>
                     </el-form-item>
                     <el-form-item label="工作事项" :prop="'domains.' + index + '.content'" >
-                        <el-input v-model="domain.content" type="textarea" :rows="4" placeholder="请输入投入时长" clearable
-                         :disabled="workForm.domains.length==0?true:(workForm.domains[0].state==2?false:true)"></el-input>
+                        <el-input v-model="domain.content" type="textarea" :rows="4" placeholder="请填写工作事项" clearable
+                         :disabled="workForm.domains.length==0?true:(workForm.domains[index].state>=2?false:true)"></el-input>
                     </el-form-item>
                     <el-divider v-if="workForm.domains.length>1"></el-divider>
                 </div>
                 <el-link v-if="showAddMore" type="primary" :underline="false" @click="addDomain" style="margin-left:40px">添加更多</el-link>
             </el-form>
             <span slot="footer" class="dialog-footer">
+                <el-button @click="deleteReport" v-if="workForm.domains[0].id != null">删除</el-button>
                 <el-button @click="dialogVisible = false">取消</el-button>
                 <el-button type="primary" @click="submitDepartment"
-                :disabled="workForm.domains.length==0?true:(workForm.domains[0].state==2?false:true)" >提交</el-button>
+                :disabled="workForm.domains.length==0?true:(canEdit?false:true)" >提交</el-button>
             </span>
         </el-dialog>
 
         <!-- 批量日报审核 -->
         <el-dialog title="批量日报审核" :visible.sync="approveDialogVisible" width="500px">
-            <el-checkbox v-model="isAllSelect" label="全选" style="margin-left:24px;" @change="selectAll" v-if="batchShowData.length > 0"></el-checkbox>
-            <el-tree ref="approveTree" node-key="id" :data="batchShowData" show-checkbox="true" @check-change="handleCheckChange" >
+            <el-checkbox v-model="isAllSelect" label="全选" style="margin-left:24px;" @change="selectAll" v-if="reportNames.length > 0"></el-checkbox>
+            <el-tree ref="approveTree" node-key="id" :data="reportNames" show-checkbox="true" @check-change="handleCheckChange" >
             </el-tree>
             <span slot="footer" class="dialog-footer">
                 <el-button @click="approveDialogVisible = false">取消</el-button>
@@ -182,6 +244,12 @@
     export default {
         data() {
             return {
+                subProjectList:[],
+                canEdit: true,
+                timeRange:[0.5,1.0,1.5,2.0,2.5,3.0,3.5,4.0,4.5,5.0,5.5,6.0,6.5,7.0,7.5,8.0,8.5,9.0,9.5,10.0,10.5,11.0,11.5,12.5,13.0,13.5,14.0,14.5,15.0],
+                selectTime:null,
+                reportTimeType:{},
+                curDate:'',
                 isAllSelect: false,
                 approveDialogVisible:false,
                 deptId:null,
@@ -200,6 +268,7 @@
 
                 projectList: [], //项目列表
                 reportList: [], //日报列表
+                reportNames:[], //批量审批列表
 
                 dialogVisible: false, //项目弹窗
                 report: '',
@@ -247,6 +316,70 @@
             };
         },
         methods: {
+            //项目选中了, 加载子项目
+            selectProject(domain, index) {
+                this.http.post('/sub-project/list',{ 
+                        projectId: domain.projectId
+                    },
+                    res => {
+                        if (res.code == "ok") {
+                            this.workForm.domains[index].subProjectList = res.data;
+                            // domain.subProjectList = res.data;
+                            // console.log(domain.subProjectList);
+                            this.$forceUpdate();
+                        } 
+                    },
+                    error => {
+                        this.listLoading = false;
+                        this.$message({
+                            message: error,
+                            type: "error"
+                        });
+                        }
+                    );
+            },
+            //删除自己的日报
+           deleteReport() {
+               this.$confirm("确定要删除该日报吗?","提示", {
+                    confirmButtonText: "确定",
+                    cancelButtonText: "取消",
+                    type: "warning"
+                })
+                .then(() => {
+                    this.listLoading = true;
+                    this.http.post('/report/delete',{ 
+                        userId: this.user.id,
+                        date: this.workForm.createDate
+                    },
+                    res => {
+                        this.listLoading = false;
+                        if (res.code == "ok") {
+                            this.$message({
+                                message: "删除成功",
+                                type: "success"
+                            });
+                            this.getReportList();
+                            this.getDepartment();
+                            this.dialogVisible = false;
+                        } else {
+                            this.$message({
+                                message: res.msg,
+                                type: "error"
+                            });
+                        }
+                    },
+                    error => {
+                        this.listLoading = false;
+                        this.$message({
+                            message: error,
+                            type: "error"
+                        });
+                        }
+                    );
+                })
+                .catch(() => {});
+                
+           },
             //提交批量审核数据
             submitBatchApprove() {
                 console.log(this.$refs.approveTree.getCheckedNodes());
@@ -266,6 +399,7 @@
                     }
                 }
                 let day = this.choseDay > 9 ? "-" + (this.choseDay + 1) : "-0" + (this.choseDay + 1);
+                console.log('ids==='+ids);
                 this.http.post("/report/batchApproveReport", {ids:ids, date:this.date + day},
                 res => {
                     if (res.code == "ok") {
@@ -293,7 +427,7 @@
             selectAll() {
                 if (this.isAllSelect) {
                     var keys = [];
-                    this.batchShowData.forEach(b=>{
+                    this.reportNames.forEach(b=>{
                         keys.push(b.id);
                     })
                     this.$refs.approveTree.setCheckedKeys(keys);
@@ -305,14 +439,21 @@
             batchApprove() {
                 this.approveDialogVisible = true;
                 console.log(this.allData);
-                this.batchShowData = JSON.parse(JSON.stringify(this.allData));
-                //去掉全部人员
-                this.batchShowData.splice(0,1);
-                //过滤。只显示待审核的
-                this.filterState(0, this.batchShowData);
-                this.calculateMembCount(this.batchShowData);
-                //去掉空的部门
-                this.removeEmptyNode(this.batchShowData);
+                this.reportNames = [];
+                for (var i=0;i<this.reportList.length; i++) {
+                    var report = this.reportList[i];
+                    var hasUnChecked =false;
+                    var id = '';
+                    for (var j=0;j<report.data.length; j++) {
+                        if (report.data[j].state == 0) {
+                            hasUnChecked = true;
+                            id += report.data[j].id+',';
+                        }
+                    }
+                    if (hasUnChecked) {
+                        this.reportNames.push({id:id, label: report.name});
+                    }
+                }
             },
             removeEmptyNode(list) {
                 for (var i=0;i<list.length;i++) {
@@ -514,6 +655,10 @@
                     res => {
                         if (res.code == "ok") {
                             var t = res.data;
+                            this.reportTimeType = t;
+                            if (this.reportTimeType.type > 0) {
+                                this.showAddMore = true;
+                            }
                             //转化时间格式
                             if (t.allday != null) {
                                 this.timeType.push({value:0, label:'全天 - '+t.allday+'小时', hours:t.allday});
@@ -522,7 +667,7 @@
                                 this.timeType.push({value:1, label:'上午 - '+t.am+'小时', hours: t.am});
                             }
                             if (t.pm != null) {
-                                this.timeType.push({value:2, label:'午 - '+t.pm+'小时', hours: t.pm});
+                                this.timeType.push({value:2, label:'午 - '+t.pm+'小时', hours: t.pm});
                             }
                         } else {
                             this.$message({
@@ -548,12 +693,13 @@
             },
 
             // 选择日期
-            choseDate(i) {
+            choseDate(i, item) {
                 this.choseDay = i;
                 let day = this.choseDay > 9 ? "-" + (this.choseDay + 1) : "-0" + (this.choseDay + 1);
                 sessionStorage.msg = this.date + day,
                 this.getReportList();
                 this.getDepartment();
+                this.curDate = item;
             },
 
             // 获取日期列表
@@ -579,6 +725,9 @@
                     dayArry.push(str);
                 }
                 this.allDate = dayArry;
+                if (sessionStorage.msg) {
+                    this.curDate = sessionStorage.msg;
+                }
             },
 
             getCountDays() {
@@ -691,6 +840,7 @@
                         this.report = list;
                         if(list.report.length != 0) {
                             var arr = [];
+                            this.canEdit = false;
                             for(var i in list.report) {
                                 arr.push({
                                     id: list.report[i].id,
@@ -700,6 +850,9 @@
                                     state: list.report[i].state,
                                     timeType: list.report[i].timeType
                                 })
+                                if (list.report[i].state >= 2) {
+                                    this.canEdit = true;
+                                }
                             }
                             this.workForm = {
                                 createDate: this.workForm.createDate,
@@ -717,6 +870,7 @@
                                     timeType:0,
                                 }],
                             }
+                            this.canEdit = true;
                         }
                     } else {
                         this.$message({
@@ -737,40 +891,46 @@
             fillInReport(i) {
                 if(i == -1) {
                     this.isDisable = false;
-                    let day = this.choseDay > 9 ? "-" + (this.choseDay + 1) : "-0" + (this.choseDay + 1);
-                    this.workForm.createDate = this.date + day;
                 } else {
                     this.isDisable = true;
-                    
                 }
+                let day = this.choseDay > 9 ? "-" + (this.choseDay + 1) : "-0" + (this.choseDay + 1);
+                this.workForm.createDate = this.date + day;
                 this.getReport(i);
                 this.dialogVisible = true;
             },
 
             // 添加模块
             addDomain() {
-                
                 this.workForm.domains.push({
                         projectId: "",
                         workingTime: "",
                         content: "",
+                        state:2,//2-表示待提交
                 });
-                //检测时间段数量,达到2个,不能再加了
-                var length = this.workForm.domains.length;
-                if (length == 2) {
-                    this.showAddMore = false;
+                
+                if (this.reportTimeType.type == 0) {
+                    //全天上下午模式下,检测时间段数量,达到2个,不能再加了
+                    var length = this.workForm.domains.length;
+                    if (length == 2) {
+                        this.showAddMore = false;
+                    }
                 }
+                
             },
 
             // 移除模块
             delDomain(i) {
                 this.workForm.domains.splice(i,1)
                 //检测当前剩下的一个,时间类型是否是全天
-                if (this.workForm.domains[0].timeType == 0) {
-                    this.showAddMore = false;
-                } else {
-                    this.showAddMore = true;
+                if (this.reportTimeType.type == 0) {
+                    if (this.workForm.domains[0].timeType == 0) {
+                        this.showAddMore = false;
+                    } else {
+                        this.showAddMore = true;
+                    }
                 }
+                
             },
 
             // 改变月份
@@ -783,47 +943,49 @@
                 this.$refs.workForm.validate(valid => {
                     if (valid) {
                         //检查时间,全天和上下午不能同时存在
-                        var alldayNum = 0;
-                        var amNum = 0;
-                        var pmNum = 0;
-                        for(var i in this.workForm.domains) {
-                            if (this.workForm.domains[i].timeType == 0) {
-                                alldayNum ++;
-                            } else if (this.workForm.domains[i].timeType == 1) {
-                                amNum++;
-                            } else if (this.workForm.domains[i].timeType == 2) {
-                                pmNum++;
+                        if (this.reportTimeType.type == 0) {
+                            var alldayNum = 0;
+                            var amNum = 0;
+                            var pmNum = 0;
+                            for(var i in this.workForm.domains) {
+                                if (this.workForm.domains[i].timeType == 0) {
+                                    alldayNum ++;
+                                } else if (this.workForm.domains[i].timeType == 1) {
+                                    amNum++;
+                                } else if (this.workForm.domains[i].timeType == 2) {
+                                    pmNum++;
+                                }
+                            }
+                            if (alldayNum > 1) {
+                                this.$message({
+                                        message: "工作时间-全天,只能选择一次",
+                                        type: "error"
+                                    });
+                                return;
+                            }
+                            if (amNum > 1) {
+                                this.$message({
+                                        message: "工作时间-上午,只能选择一次",
+                                        type: "error"
+                                    });
+                                return;
+                            }
+                            if (pmNum > 1) {
+                                this.$message({
+                                        message: "工作时间-下午,只能选择一次",
+                                        type: "error"
+                                    });
+                                return;
+                            }
+                            if (alldayNum == 1 && (amNum > 0 || pmNum > 0)) {
+                                this.$message({
+                                        message: "工作时间-全天,不能和上下午同时存在",
+                                        type: "error"
+                                    });
+                                return;
                             }
                         }
-                        if (alldayNum > 1) {
-                            this.$message({
-                                    message: "工作时间-全天,只能选择一次",
-                                    type: "error"
-                                });
-                            return;
-                        }
-                        if (amNum > 1) {
-                            this.$message({
-                                    message: "工作时间-上午,只能选择一次",
-                                    type: "error"
-                                });
-                            return;
-                        }
-                        if (pmNum > 1) {
-                            this.$message({
-                                    message: "工作时间-下午,只能选择一次",
-                                    type: "error"
-                                });
-                            return;
-                        }
-                        if (alldayNum == 1 && (amNum > 0 || pmNum > 0)) {
-                            this.$message({
-                                    message: "工作时间-全天,不能和上下午同时存在",
-                                    type: "error"
-                                });
-                            return;
-                        }
-
+                        
                         this.listLoading = true;
                         let formData = new FormData();
                         for(var i in this.workForm.domains) {
@@ -833,9 +995,25 @@
                                 formData.append("id", -1);
                             }
                             formData.append("projectId", this.workForm.domains[i].projectId);
-                            formData.append("timeType", this.workForm.domains[i].timeType);
-                            var workingTime = this.timeType.filter(t=>t.value == this.workForm.domains[i].timeType)[0].hours;
-                            formData.append("workingTime", workingTime);
+                            if (this.workForm.domains[i].subProjectId != null) {
+                                formData.append("subProjectId", this.workForm.domains[i].subProjectId);
+                            } else {
+                                formData.append("subProjectId", 0);
+                            }
+                            
+                            formData.append("reportTimeType", this.reportTimeType.type);
+                            if (this.reportTimeType.type == 0) {
+                                formData.append("timeType", this.workForm.domains[i].timeType);
+                                var workingTime = this.timeType.filter(t=>t.value == this.workForm.domains[i].timeType)[0].hours;
+                                formData.append("workingTime", workingTime);
+                            } else if (this.reportTimeType.type == 1){
+                                formData.append("workingTime", this.workForm.domains[i].workingTime);
+                            } else if (this.reportTimeType.type == 2) {
+                                formData.append("startTime", this.workForm.domains[i].startTime);
+                                formData.append("endTime", this.workForm.domains[i].endTime);
+                            }
+                            
+                            
                             if (this.workForm.domains[i].content == null || this.workForm.domains[i].content == '') {
                                 formData.append("content", '-');
                             } else {
@@ -880,10 +1058,16 @@
             },
 
             // 通过日报
-            approve(id) {
+            approve(id, item) {
                 this.logining = true;
                 let day = this.choseDay > 9 ? "-" + (this.choseDay + 1) : "-0" + (this.choseDay + 1);
-                this.http.post( this.port.report.approve, {id: id , date: this.date +day},
+
+                var ids = '';
+                var data = item.data;
+                data.forEach(element => {
+                    ids +=(element.id+',');
+                });
+                this.http.post( this.port.report.approve, {id: id , date: this.date +day, reportIds: ids},
                 res => {
                     this.logining = false;
                     if (res.code == "ok") {
@@ -909,11 +1093,51 @@
                 });
             },
 
+            //撤回日报
+            cancel(item) {
+                this.logining = true;
+                
+                var ids = '';
+                var data = item.data;
+                data.forEach(element => {
+                    ids +=(element.id+',');
+                });
+                this.http.post(this.port.report.cancelReport, {userId: this.user.id, reportIds: ids},
+                res => {
+                    this.logining = false;
+                    if (res.code == "ok") {
+                        this.$message({
+                            message:"撤回成功",
+                            type: "success"
+                        });
+                        this.getReportList();
+                        this.getDepartment();
+                    } else {
+                        this.$message({
+                            message: res.msg,
+                            type: "error"
+                        });
+                    }
+                },
+                error => {
+                    this.logining = false;
+                    this.$message({
+                        message: error,
+                        type: "error"
+                    });
+                });
+            },
+
             // 未通过日报
-            deny(id,i) {
+            deny(id,i, item) {
                 this.logining = true;
                 let day = this.choseDay > 9 ? "-" + (this.choseDay + 1) : "-0" + (this.choseDay + 1);
-                this.http.post( this.port.report.deny, {id: id , date: this.date +day},
+                var ids = '';
+                var data = item.data;
+                data.forEach(element => {
+                    ids +=(element.id+',');
+                });
+                this.http.post( this.port.report.deny, {id: id , date: this.date +day, reportIds: ids},
                 res => {
                     this.logining = false;
                     if (res.code == "ok") {
@@ -942,11 +1166,13 @@
         },
         created() {
             let height = window.innerHeight;
-            this.tableHeight = height - 233;
+            console.log('window inner height=='+height)
+            this.tableHeight = height - 153;
             const that = this;
             window.onresize = function temp() {
-                that.tableHeight = window.innerHeight - 233;
+                that.tableHeight = window.innerHeight - 153;
             };
+
         },
         mounted() {
             this.getAllDate();

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

@@ -54,9 +54,9 @@
             </el-table-column>
             <el-table-column label="操作" width="220">
                 <template slot-scope="scope">
-                    <el-button v-if="user.role != 0 && scope.row.state == 0" type="primary" :loading="logining" size="small" @click="approve(scope.row.id,scope.row.date)">通过</el-button>
-                    <el-button v-if="user.role != 0 && scope.row.state == 0" type="danger" :loading="logining" size="small" @click="deny(scope.row.id,0,scope.row.date)">驳回</el-button>
-                    <el-button v-if="user.role != 0 && scope.row.state == 1" type="danger" :loading="logining" size="small" @click="deny(scope.row.id,1,scope.row.date)">撤销</el-button>
+                    <el-button v-if="scope.row.state == 0" type="primary" :loading="logining" size="small" @click="approve(scope.row.id,scope.row.date, scope.row)">通过</el-button>
+                    <el-button v-if="scope.row.state == 0" type="danger" :loading="logining" size="small" @click="deny(scope.row.id,0,scope.row.date, scope.row)">驳回</el-button>
+                    <el-button v-if="scope.row.state == 1" type="danger" :loading="logining" size="small" @click="deny(scope.row.id,1,scope.row.date, scope.row)">撤销</el-button>
                 </template>
             </el-table-column>
         </el-table>
@@ -144,7 +144,8 @@
             },
 
             // 通过日报
-            approve(id,date) {
+            approve(id,date, item) {
+                console.log(item);
                 this.logining = true;
                 var time = "";
                 if(this.search.value == -1) {
@@ -152,7 +153,13 @@
                 } else {
                     time = date;
                 }
-                this.http.post( this.port.report.approve, {id: id , date: time},
+                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},
                 res => {
                     this.logining = false;
                     if (res.code == "ok") {
@@ -178,7 +185,7 @@
             },
 
             // 未通过日报
-            deny(id,i,date) {
+            deny(id,i,date, item) {
                 this.logining = true;
                 var time = "";
                 if(this.search.value == -1) {
@@ -186,7 +193,12 @@
                 } else {
                     time = date;
                 }
-                this.http.post( this.port.report.deny, {id: id , date: time},
+                var ids = '';
+                var data = item.data;
+                data.forEach(element => {
+                    ids +=(element.id+',');
+                });
+                this.http.post( this.port.report.deny, {id: id , date: time, reportIds: ids},
                 res => {
                     this.logining = false;
                     if (res.code == "ok") {

+ 370 - 0
fhKeeper/formulahousekeeper/timesheet/src/views/workReport/timer.vue

@@ -0,0 +1,370 @@
+<template>
+    <section>
+        <!--工具条-->
+        <el-col :span="24" class="toolbar" style="padding-bottom: 0px;">
+            <el-form :inline="true">
+                <el-form-item label="我的工作计时列表" >
+                   
+                </el-form-item>
+                <el-form-item style="float:right;">
+                    <el-link type="primary" :underline="false" @click="dialogVisible=true">新增工作计时</el-link>
+                </el-form-item>
+            </el-form>
+        </el-col>
+
+        <!--列表-->
+        <el-table :data="list" highlight-current-row v-loading="listLoading" :height="tableHeight" style="width: 100%;">
+            <el-table-column prop="projectName" label="项目" ></el-table-column>
+            <el-table-column prop="subProjectName" label="子项目" ></el-table-column>
+            <el-table-column prop="startTime" label="开始时间" >
+            </el-table-column>
+            <el-table-column prop="endTime" label="结束时间" >
+            </el-table-column>
+            <el-table-column prop="timerShow" label="工作时长" >
+            </el-table-column>
+            
+            <el-table-column prop="endTime" label="状态" >
+                <template slot-scope="scope">
+                    <span style="color:red;" v-if="scope.row.endTime == null">进行中</span>
+                    <span style="color:green;" v-if="scope.row.endTime != null">计时完成</span>
+                </template>
+            </el-table-column>
+            
+            <el-table-column label="操作" width="320">
+                <template slot-scope="scope">
+                    <el-button  type="default" :disabled="scope.row.endTime != null" :loading="logining" size="small" @click="stopTimer(scope.row.id)">停止</el-button>
+                    <el-button  type="default" :loading="logining" :disabled="scope.row.endTime == null" size="small" @click="report(scope.row)">{{scope.row.reportId==null?'转日报':'查看日报'}}</el-button>
+                    <el-button  type="default" :loading="logining" size="small"
+                     @click="deleteItem(scope.row.id)">删除</el-button>
+                </template>
+            </el-table-column>
+        </el-table>
+        <!-- 创建自动计时的dialog -->
+        <el-dialog title="创建自动计时" :visible.sync="dialogVisible" width="550px">
+            <el-form ref="workForm" :model="workForm" label-width="100px">
+                <el-form-item label="投入项目" :prop="projectId"
+                        :rules="{ required: true, message: '请选择投入项目', trigger: ['change','blur'] }">
+                        <el-select v-model="workForm.projectId" placeholder="请选择" style="width:200px;" 
+                        @change="selectProject()"
+                        >
+                        <el-option v-for="item in projectList" 
+                        :key="item.id" :label="item.projectName" :value="item.id"></el-option>
+                        </el-select>
+                        <!--子项目 -->
+                        <el-select v-model="workForm.subProjectId" 
+                        placeholder="请选择" style="width:200px;" clearable="true" 
+                        >
+                        <el-option v-for="item in subProjectList" :key="item.id" :label="item.name" :value="item.id"></el-option>
+                        </el-select>
+                    </el-form-item>
+            </el-form>
+            <span slot="footer" class="dialog-footer">
+                <el-button @click="dialogVisible = false">取消</el-button>
+                <el-button type="primary" @click="createTimer" >开始计时</el-button>
+            </span>
+        </el-dialog>
+
+        <!-- 创建日报的dialog -->
+        <el-dialog title="转日报" :visible.sync="reportDialog" width="550px">
+            <el-form ref="reportForm" :model="reportForm" label-width="100px">
+                <el-form-item label="投入项目" >
+                     {{reportForm.projectName}}  <span v-if="reportForm.subProjectId != null"> / {{reportForm.subProjectName}}   </span> 
+                </el-form-item>
+                <el-form-item label="开始时间" >
+                     {{reportForm.startTime}}
+                </el-form-item>
+                <el-form-item label="结束时间" >
+                     {{reportForm.endTime}}
+                </el-form-item>
+                <el-form-item label="时长" >
+                     {{reportForm.timerShow}}
+                </el-form-item>
+                <el-form-item label="工作事项" >
+                     <el-input v-model="reportForm.content" type="textarea" :rows="4" placeholder="请填写工作事项" clearable
+                         ></el-input>
+                </el-form-item>
+            </el-form>
+            <span slot="footer" class="dialog-footer">
+                <el-button @click="reportDialog = false">取消</el-button>
+                <el-button type="primary" @click="submitReport" >提交日报</el-button>
+            </span>
+        </el-dialog>
+    </section>
+    
+
+</template>
+
+<script>
+    import util from "../../common/js/util";
+
+    export default {
+        data() {
+            return {
+                firstLoadTime:null,
+                projectList: [], //项目列表
+                subProjectList:[],
+                user: JSON.parse(sessionStorage.getItem("user")),
+                dialogVisible: false,
+                search: {
+                    value: 0,
+                    date: util.formatDate.format(new Date(new Date()), "yyyy-MM-dd"),
+                },
+                workForm:{},
+                users: [],
+
+                tableHeight: 0,
+                listLoading: false,
+                total: 0,
+                page: 1,
+                size: 20,
+                list: [],
+                logining: false,
+                timer:null,
+                reportForm:{},
+                reportDialog: false
+            };
+        },
+        methods: {
+            submitReport() {
+                this.http.post('/project-timer/tranferToReport',this.reportForm,
+                    res => {
+                        if (res.code == "ok") {
+                            this.reportDialog = false;
+                            this.getList();
+                            this.$message({
+                                message: '日报已提交,等待项目经理审核',
+                                type: "success"
+                            });
+                        } 
+                    },
+                    error => {
+                        this.listLoading = false;
+                        this.$message({
+                            message: error,
+                            type: "error"
+                        });
+                        }
+                    );
+            },
+            report(row) {
+                if (row.reportId == null) {
+                    this.reportForm = row;
+                    this.reportDialog = true;
+                } else {
+                    this.$router.push('/daily');
+                }
+                
+            },
+            stopTimer(id) {
+                this.$confirm("确定要停止计时吗?","提示", {
+                    confirmButtonText: "确定",
+                    cancelButtonText: "取消",
+                    type: "warning"
+                })
+                .then(() => {
+                    this.listLoading = true;
+                    this.http.post('/project-timer/endTimer',{id: id},
+                    res => {
+                        if (res.code == "ok") {
+                            this.getList();
+                        } 
+                    },
+                    error => {
+                        this.listLoading = false;
+                        this.$message({
+                            message: error,
+                            type: "error"
+                        });
+                        }
+                    );
+                })
+                .catch(() => {});
+            },
+            deleteItem(id) {
+                this.$confirm("确定要删除该记录吗?","提示", {
+                    confirmButtonText: "确定",
+                    cancelButtonText: "取消",
+                    type: "warning"
+                })
+                .then(() => {
+                    this.listLoading = true;
+                    this.http.post('/project-timer/deleteTimer',{id: id},
+                    res => {
+                        if (res.code == "ok") {
+                            this.getList();
+                        } 
+                    },
+                    error => {
+                        this.listLoading = false;
+                        this.$message({
+                            message: error,
+                            type: "error"
+                        });
+                        }
+                    );
+                })
+                .catch(() => {});
+                
+            },
+            //创建计时器
+            createTimer() {
+                this.$refs.workForm.validate(valid => {
+                    if (valid) {
+                        if (this.workForm.projectId == null) {
+                            this.$message({
+                                message: '请选择投入项目',
+                                type: "error"
+                            });
+                            return;
+                        }
+                        this.workForm.projectName = this.projectList.filter(p=>p.id == this.workForm.projectId)[0].projectName;
+                        if (this.workForm.subProjectId != null) {
+                            this.workForm.subProjectName = this.subProjectList.filter(s=>s.id == this.workForm.subProjectId)[0].name;
+                        }
+                        this.http.post('/project-timer/addTimer',this.workForm,
+                            res => {
+                                if (res.code == "ok") {
+                                    this.dialogVisible = false;
+                                    this.getList();
+                                } 
+                            },
+                            error => {
+                                this.listLoading = false;
+                                this.$message({
+                                    message: error,
+                                    type: "error"
+                                });
+                                }
+                            );
+                    }
+                });
+            },
+            //项目选中了, 加载子项目
+            selectProject() {
+                this.workForm.subProjectId = null;
+                this.subProjectList = [];
+                this.http.post('/sub-project/list',{ 
+                        projectId: this.workForm.projectId
+                    },
+                    res => {
+                        if (res.code == "ok") {
+                            this.subProjectList = res.data;
+                        } 
+                    },
+                    error => {
+                        this.listLoading = false;
+                        this.$message({
+                            message: error,
+                            type: "error"
+                        });
+                        }
+                    );
+            },
+            //获取项目列表
+            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"
+                    });
+                });
+            },
+            //获取定时任务列表
+            getList() {
+                this.listLoading = true;
+                this.http.post('/project-timer/getMyTimer', {},
+                res => {
+                    this.listLoading = false;
+                    if (res.code == "ok") {
+                        this.list = res.data;
+                    } else {
+                        this.$message({
+                        message: res.msg,
+                        type: "error"
+                        });
+                    }
+                },
+                error => {
+                    this.listLoading = false;
+                    this.$message({
+                        message: error,
+                        type: "error"
+                    });
+                });
+            },
+            calculateTimer() {
+                if (this.list != null) {
+                    var now = new Date();
+                    var myList = JSON.parse(JSON.stringify(this.list));
+                    console.log(myList);
+                    for (var i=0;i<myList.length; i++) {
+                        if (myList[i].endTime == null) {
+                            if (myList[i].timerShow == null) {
+                                myList[i].timerShow = this.formatTimer(myList[i].timer);
+                                this.firstLoadTime = now;
+                            } else {
+                                myList[i].timerShow = this.formatTimer(myList[i].timer + ((now.getTime() - this.firstLoadTime.getTime())/1000));
+                            }
+                        } else {
+                            myList[i].timerShow = this.formatTimer(myList[i].timer);
+                        }
+                        
+                    }
+                    this.list = myList;
+                    // this.$forceUpdate();
+                }
+            },
+            formatTimer(t) {
+                var hours = parseInt(t/3600);
+                var minutes = parseInt(t%3600/60);
+                var seconds = parseInt(t%60);
+                var show = '';
+                console.log('hours=='+hours);
+                show += hours<10?('0'+hours):hours;
+                show += ':';
+                show += minutes<10?('0'+minutes):minutes;
+                show += ':';
+                show += seconds<10?('0'+seconds):seconds;
+                
+                return show;
+            }
+
+        },
+        created() {
+            let height = window.innerHeight;
+            this.tableHeight = height - 85;
+            const that = this;
+            window.onresize = function temp() {
+                that.tableHeight = window.innerHeight - 85;
+            };
+        },
+        
+        mounted() {
+            this.getList();
+            this.getProjectList();
+            this.timer = setInterval(() => {
+                this.calculateTimer();
+            }, 1000);
+        },
+        beforeDestroy() {
+            clearInterval(this.timer);
+        }
+    };
+</script>
+
+<style lang="scss" scoped>
+</style>

+ 3 - 2
fhKeeper/formulahousekeeper/timesheet_h5/src/main.js

@@ -13,11 +13,12 @@ import "@/components/Vant";
 
 import { Form , Toast , Grid, GridItem , DatetimePicker ,
 Picker , Dialog , NumberKeyboard , Sticky , Skeleton ,
-Panel , Divider , List , pullRefresh , SwipeCell } from 'vant';
+Panel , Divider , List , pullRefresh , SwipeCell, Checkbox, Search } from 'vant';
 
 Vue.use(Form).use(Toast).use(Grid).use(GridItem).use(DatetimePicker)
 .use(Picker).use(Dialog).use(NumberKeyboard).use(Sticky).use(Skeleton)
-.use(Panel).use(Divider).use(List).use(pullRefresh).use(SwipeCell);
+.use(Panel).use(Divider).use(List).use(pullRefresh).use(SwipeCell)
+.use(Checkbox).use(Search);
 
 // rem
 import "amfe-flexible";

+ 7 - 0
fhKeeper/formulahousekeeper/timesheet_h5/src/router/index.js

@@ -53,6 +53,13 @@ const router = new Router({
         },
         component: () => import("@/views/review/index")
     },
+    {
+        path: "/msg",
+        meta: {
+            title: "消息记录"
+        },
+        component: () => import("@/views/msg/index")
+    },
     {
         path: "/project",
         meta: {

+ 4 - 4
fhKeeper/formulahousekeeper/timesheet_h5/src/utils/request.js

@@ -6,13 +6,13 @@ import qs from "qs"
 // 创建axios实例
 const service = axios.create({
     baseURL: "/api",//process.env.VUE_APP_URL, // api 的 VUE_APP_URL
-    timeout: 50000 // 请求超时时间(因为需要调试后台,所以设置得比较大)
+    timeout: 30000 // 请求超时时间
 });
 
 // request拦截器,在请求之前做一些处理
 service.interceptors.request.use(
     config => {
-        if(config.url != "/report/editReport") {
+        if(config.url != "/report/editReport" && config.url != "/project/editProject") {
             config.data = qs.stringify(config.data);
             config.headers["Content-Type"] = "application/x-www-form-urlencoded; charset=UTF-8";
         } else {
@@ -22,8 +22,8 @@ service.interceptors.request.use(
             config.contentType= false;
         }
         
-        if (sessionStorage.userInfo) {
-            config.headers["Token"] = JSON.parse(sessionStorage.userInfo).id;
+        if (localStorage.userInfo) {
+            config.headers["Token"] = JSON.parse(localStorage.userInfo).id;
         }
         return config;
     },

+ 232 - 14
fhKeeper/formulahousekeeper/timesheet_h5/src/views/edit/index.vue

@@ -9,9 +9,9 @@
                 <van-datetime-picker v-model="currentDate" type="date" :min-date="minDate" :max-date="maxDate" @confirm="changeTime" @cancel="showPicker = false"/>
             </van-popup>
 
-            <van-cell title="待分配时长" :value="report.time + 'h'" size="large"></van-cell>
+            <!-- <van-cell title="待分配时长" :value="report.time + 'h'" size="large"></van-cell> -->
 
-            <div class="form_domains" v-for="(item,index) in form.domains">
+            <div class="form_domains" v-for="(item,index) in form.domains" :key="item.id">
                 <van-button v-if="index == 0" @click="addNewPro" class="form_addNew" icon="plus" type="info" size="mini">新增项目</van-button>
                 <van-icon v-else class="form_del" name="delete" @click="delPro(index)" />
 
@@ -22,22 +22,65 @@
                         <van-picker show-toolbar :columns="project" value-key="projectName" @confirm="choseProject" @cancel="showPickerProject = false" />
                     </van-popup>
 
-                    <van-field readonly clickable class="form_input" :value="item.workingTime" name="workingTime" label="工作时长" placeholder="请输入工作时长(单位:小时)"
+                    <!-- <van-field readonly clickable class="form_input" :value="item.workingTime" name="workingTime" label="工作时长" placeholder="请输入工作时长(单位:小时)"
                     :rules="[{ required: true, message: '请输入工作时长(单位:小时)' }]" @touchstart.native.stop="showNumberKey = true"/>
-                    <van-number-keyboard v-model="item.workingTime" :show="showNumberKey" close-button-text="完成" extra-key="." :maxlength="4" @blur="showNumberKey = false" />
+                    <van-number-keyboard v-model="item.workingTime" :show="showNumberKey" close-button-text="完成" extra-key="." :maxlength="4" @blur="showNumberKey = false" /> -->
+                    <!-- 全天上下午模式 -->
+                    <van-field v-if="reportTimeType.type < 2" readonly clickable  :value="item.label" label="工作时长" placeholder="请选择工作时长(小时)" @click="clickTimePicker(index)"
+                    :rules="[{ required: true, message: '请选择工作时长' }]"/>
+                    <van-popup v-model="showPickerTime" position="bottom">
+                        <van-picker show-toolbar :columns="timeType"  value-key="label" @confirm="choseTimePick" @cancel="showPickerTime = false" />
+                    </van-popup>
+                    
+                    <!-- 选择数字时间长度模式 -->
+                    <van-popup v-model="showPickerHours" position="bottom">
+                        <van-picker show-toolbar :columns="timeRange" 
+                        :default-index="15"
+                        @confirm="choseTimePick" @cancel="showPickerHours = false" />
+                    </van-popup>
 
-                    <van-field class="form_input" v-model="item.content" name="content" type="textarea" label="工作事项" placeholder="请输入工作事项" 
-                    rows="3" autosize :rules="[{ required: true, message: '请输入工作时长' }]" />
+                    <!-- 时间段选择模式 -->
+                    <van-field readonly v-if="reportTimeType.type == 2" clickable name="datetimePicker" :value="item.startTime" label="开始时间" placeholder="点击选择时间" 
+                        @click="showStartTime = true" />
+                    <van-popup v-model="showStartTime" position="bottom">
+                        <van-datetime-picker
+                        v-model="startTime"
+                        type="time"
+                        @confirm="confirmTime(item,0);"
+                        @cancel="showStartTime = false"
+                        :min-hour="8"
+                        :max-hour="23"
+                        :filter="filter"
+                        />
+                    </van-popup>
+                    <van-field v-if="reportTimeType.type == 2" readonly clickable name="datetimePicker" :value="item.endTime" label="结束时间" placeholder="点击选择时间" 
+                        @click="showEndTime = true" />
+                    <van-popup v-model="showEndTime" position="bottom" >
+                        <van-datetime-picker
+                        v-model="endTime"
+                        type="time"
+                        :min-hour="8"
+                        :max-hour="23"
+                        :filter="filter"
+                        @confirm="confirmTime(item,1)"
+                        @cancel="showEndTime = false"
+                        />
+                    </van-popup>
+                    <van-field class="form_input" 
+                    v-model="item.content" name="content" type="textarea" label="工作事项" placeholder="请输入工作事项" 
+                    rows="3" autosize  />
                 </van-cell-group>
             </div>
             <div class="form_btn" style="margin: 16px;">
-                <van-button v-if="canClick == 2" round block type="info" native-type="submit"> 提交 </van-button>
+                <van-button v-if="canEdit" round block type="info" native-type="submit"> 提交 </van-button>
                 <van-button v-else round block type="info" disabled native-type="submit"> 提交 </van-button>
-                <div class="form_tip" v-if="canClick == 0"> 当前日报审核中,无法修改 </div>
-                <div class="form_tip" v-if="canClick == 1"> 当前日报审核通过 </div>
             </div>
         </van-form>
-        </van-list>
+        <div style="padding:15px;">
+            <van-button  v-if="canCancel" round block type="default" @click="cancel"> 撤销 </van-button>
+        </div>
+        
+        <div class="form_tip" v-if="!canEdit"> 当前日报无法修改 </div> 
     </div>
 </template>
 
@@ -45,16 +88,29 @@
     export default {
         data() {
             return {
+                canCancel:false,
+                canEdit:false,
+                showEndTime: false,
+                showStartTime: false,
+                startTime:'09:00',
+                endTime: '18:00',
+                nowTime:new Date(),
+                showPickerHours: false,
+                timeRange:[0.5,1.0,1.5,2.0,2.5,3.0,3.5,4.0,4.5,5.0,5.5,6.0,6.5,7.0,7.5,8.0,8.5,9.0,9.5,10.0,10.5,11.0,11.5,12.5,13.0,13.5,14.0,14.5,15.0],
+                selectTime:null,
+                reportTimeType:{},
+                user: JSON.parse(localStorage.userInfo),
                 minDate: new Date(2010, 0, 1),
                 maxDate: new Date(new Date().getFullYear(),new Date().getMonth(),new Date().getDate()),
                 currentDate: new Date(),
-
+                showPickerTime: false,
                 showPicker: false,
                 showPickerProject: false,
                 clickIndex: 0,
+                clickTimeIndex: 0,
                 showNumberKey: false,
                 canClick: 2,
-
+                timeType:[],
                 form: {
                     createDate: this.format(new Date(new Date()),"yyyy-MM-dd"),
                     domains: [{
@@ -81,6 +137,94 @@
         },
 
         methods: {
+            cancel() {
+                const toast = this.$toast.loading({
+                    forbidClick: true,
+                    duration: 0
+                });
+                var ids = '';
+                var data = this.form.domains;
+                data.forEach(element => {
+                    if (element.id != null && element.id != '') {
+                        ids +=(element.id+',');
+                    }
+                });
+                this.$axios.post("/report/cancel", {userId: this.user.id, reportIds:ids})
+                .then(res => {
+                    if(res.code == "ok") {
+                        toast.clear();
+                        this.$toast.success('撤销成功');
+                        this.getReport();
+                    } else {
+                        toast.clear();
+                        this.$toast.fail('获取失败');
+                    }
+                }).catch(err=> {toast.clear();});
+            },
+
+            confirmTime(item, field) {
+                if (field == 0) {
+                    item.startTime = this.startTime;
+                    this.showStartTime = false;
+                } else {
+                    item.endTime = this.endTime;
+                    this.showEndTime = false;
+                }
+            },
+            filter(type, options) {
+                if (type === 'minute') {
+                    return options.filter(option => option % 30 === 0);
+                }
+
+                return options;
+            },
+            choseTimePick(value, index) {
+                //选中时间
+                if (this.reportTimeType.type == 0) {
+                    this.form.domains[this.clickTimeIndex].timeType = value.value;
+                    this.form.domains[this.clickTimeIndex].workingTime = value.hours;
+                    this.form.domains[this.clickTimeIndex].label = value.label;
+                    this.showPickerTime = false;
+                } else if (this.reportTimeType.type == 1) {
+                    console.log('this.reportTimeType.type=='+value);
+                    this.form.domains[this.clickTimeIndex].workingTime = value;
+                    this.form.domains[this.clickTimeIndex].label = value.toFixed(1)+'小时';
+                    this.showPickerHours = false;
+                }
+      
+            },
+            clickTimePicker(i) {
+                this.clickTimeIndex = i;
+                
+                if (this.reportTimeType.type == 0) {
+                    this.showPickerTime = true;
+                } else if (this.reportTimeType.type == 1) {
+                    this.showPickerHours = true;
+                }
+            },
+            getTimeType() {
+                this.$axios.post('/time-type/getCompanyTimeSetting', { companyId: this.user.companyId})
+                .then(res => {
+                    if(res.code == "ok") {
+                        var t = res.data;
+                        this.reportTimeType = t;
+                        //转化时间格式
+                        if (t.allday != null) {
+                            this.timeType.push({value:0, label:'全天 - '+t.allday+'小时', hours:t.allday});
+                        }
+                        if (t.am != null) {
+                            this.timeType.push({value:1, label:'上午 - '+t.am+'小时', hours: t.am});
+                        }
+                        if (t.pm != null) {
+                            this.timeType.push({value:2, label:'下午 - '+t.pm+'小时', hours: t.pm});
+                        }
+                    } else {
+                        toast.clear();
+                        this.$toast.fail(res.msg);
+                    }
+                }).catch(err=> {toast.clear();});
+            },
+
             // 返回
             back() {
                 history.back();
@@ -138,9 +282,22 @@
                     if(res.code == "ok") {
                         toast.clear();
                         this.report = res.data;
+                        var t = res.data.timeType;
+                        var timeType=[];
+                        //转化时间格式
+                        if (t.allday != null) {
+                            timeType.push({value:0, label:'全天 - '+t.allday+'小时', hours:t.allday});
+                        }
+                        if (t.am != null) {
+                            timeType.push({value:1, label:'上午 - '+t.am+'小时', hours: t.am});
+                        }
+                        if (t.pm != null) {
+                            timeType.push({value:2, label:'下午 - '+t.pm+'小时', hours: t.pm});
+                        }
                         var list = res.data.report;
                         if(list.length != 0) {
-                            this.canClick = list[0].state;
+                            this.canEdit = false;
+                            this.canCancel = false;
                             let array = [];
                             for(var i in list) {
                                 var projectName = "";
@@ -156,10 +313,18 @@
                                     workingTime: String(list[i].workingTime),
                                     content: list[i].content,
                                     state: list[i].state,
+                                    timeType: list[i].timeType,
+                                    label: timeType[list[i].timeType].label
                                 })
+                                if (list[i].state >= 2) {
+                                    this.canEdit = true;
+                                } else if (list[i].state == 0) {
+                                    this.canCancel = true;
+                                }
                             }
                             this.form.domains = array;
                         } else {
+                            //没有填报的可以点击提交
                             this.form.domains = [{
                                 id: null,
                                 projectId: "",
@@ -168,6 +333,7 @@
                                 content: "",
                                 state: 2,
                             }]
+                            this.canEdit = true;
                         }
                     } else {
                         toast.clear();
@@ -226,6 +392,39 @@
                     duration: 0
                 });
                 let formData = new FormData();
+                if (this.reportTimeType.type == 0) {
+                    var alldayNum = 0;
+                    var amNum = 0;
+                    var pmNum = 0;
+                    for(var i in this.form.domains) {
+                        if (this.form.domains[i].timeType == 0) {
+                            alldayNum ++;
+                        } else if (this.form.domains[i].timeType == 1) {
+                            amNum++;
+                        } else if (this.form.domains[i].timeType == 2) {
+                            pmNum++;
+                        }
+                    }
+                    if (alldayNum > 1) {
+                        this.$toast.fail("工作时间-全天,只能选择一次");
+                        return;
+                    }
+                    if (amNum > 1) {
+                        this.$toast.fail("工作时间-上午,只能选择一次");
+                        
+                        return;
+                    }
+                    if (pmNum > 1) {
+                        this.$toast.fail("工作时间-下午,只能选择一次");
+                        return;
+                    }
+                    if (alldayNum == 1 && (amNum > 0 || pmNum > 0)) {
+                        this.$toast.fail("工作时间-全天,不能和上下午同时存在");
+                        return;
+                    }
+                }
+                
+                //填字段
                 for(var i in this.form.domains) {
                     if (this.form.domains[i].id != null) {
                         formData.append("id", this.form.domains[i].id);
@@ -233,7 +432,18 @@
                         formData.append("id", -1);
                     }
                     formData.append("projectId", parseFloat(this.form.domains[i].projectId));
-                    formData.append("workingTime", parseFloat(this.form.domains[i].workingTime));
+                    formData.append("reportTimeType", this.reportTimeType.type);
+                    if (this.reportTimeType.type == 0) {
+                        formData.append("timeType", this.form.domains[i].timeType);
+                        formData.append("workingTime", parseFloat(this.form.domains[i].workingTime));
+                    } else if (this.reportTimeType.type == 1) {
+                        formData.append("workingTime", parseFloat(this.form.domains[i].workingTime));
+                    } else if (this.reportTimeType.type == 2) {
+                        formData.append("startTime", this.form.domains[i].startTime);
+                        formData.append("endTime",this.form.domains[i].endTime);
+                    }
+                    
+                    
                     formData.append("content", this.form.domains[i].content);
                     formData.append("createDate", this.form.createDate);
                 }
@@ -252,8 +462,16 @@
         },
         
         mounted() {
+            //获取传递过来的日期
+            var passDate = this.$route.query.date;
+            if (passDate != null) {
+                this.form.createDate = this.$route.query.date;
+            }
+            
             this.getProject();
             this.getReport();
+            this.getTimeType();
+
         }
     };
 </script>

+ 59 - 19
fhKeeper/formulahousekeeper/timesheet_h5/src/views/index/index.vue

@@ -6,11 +6,13 @@
             </van-swipe-item>
         </van-swipe>
         <van-grid :column-num="3">
-            <van-grid-item v-for="(item,index) in routers" v-show="(index==2||index==3)?(user.role==0?false:true):true" :key="index" :icon="item.icon" :text="item.name" :to="item.url"/>
+            <van-grid-item v-for="(item,index) in routers" :key="index" :icon="item.icon" :text="item.name" 
+            :info="unreadNum>0?item.info:''"
+            :to="item.url">
             </van-grid-item>
         </van-grid>
         <div class="tip">
-            新注册用户请登录PC版,完善项目及组织结构信息<br>
+            新注册用户请登录PC版,完善组织结构信息<br>
             http://worktime.ttkuaiban.com
         </div>
         <Footer page="index"></Footer>
@@ -23,7 +25,8 @@
     export default {
         data() {
             return {
-                user: JSON.parse(sessionStorage.userInfo),
+                user: JSON.parse(localStorage.userInfo),
+                unreadNum:0,
                 images: [
                     require('../../assets/img/index/banner_1.png'),
                     require('../../assets/img/index/banner_2.png'),
@@ -40,27 +43,51 @@
                         url: '/edit',
                         icon: 'edit'
                     },
-                    {
-                        name: '审核日报',
-                        url: '/review',
-                        icon: 'todo-list-o'
-                    },
-                    {
-                        name: '项目管理',
-                        url: '/project',
-                        icon: 'label-o'
-                    },
-                    {
-                        name: '暂无更多',
-                        url: '',
-                        icon: 'more-o'
-                    }
+                    
                 ],
             };
         },
         created() {
             let index = this.active + 1;
             this.list = this[`list${index}`]; // this.list1
+            
+        },
+        mounted() {
+            if (this.user.role == 0) {
+                //普通员工
+                if (this.user.leader) {
+                    this.routers.push({
+                        name: '审核日报',
+                        url: '/review',
+                        icon: 'todo-list-o'
+                    });
+                    this.routers.push({
+                                name: '消息记录',
+                                url: '/msg',
+                                icon: 'todo-list-o',
+                                info: this.unreadNum
+                            });
+                } 
+            } else {
+                this.routers.push({
+                        name: '审核日报',
+                        url: '/review',
+                        icon: 'todo-list-o'
+                    });
+                this.routers.push({
+                        name: '项目管理',
+                        url: '/project',
+                        icon: 'label-o'
+                    });
+                this.routers.push({
+                            name: '消息记录',
+                            url: '/msg',
+                            icon: 'todo-list-o',
+                            info: this.unreadNum
+                        });
+            }
+
+            this.getMessage();
         },
         components: {
             Footer
@@ -76,7 +103,20 @@
                     .catch(err => {
                     console.log("err", err);
                     });
-            }
+            },
+            //获取消息
+            getMessage() {
+                this.$axios.post("/information/list", {
+                })
+                .then(res => {
+                    if(res.code == "ok") {
+                        var list = res.data;
+                        this.unreadNum = list.filter(l=>l.checked==0).length;
+                        console.log(this.unreadNum);
+                        
+                    } 
+                }).catch(err=> {toast.clear();});
+            },
         }
     };
 </script>

+ 7 - 1
fhKeeper/formulahousekeeper/timesheet_h5/src/views/login/index.vue

@@ -45,7 +45,7 @@
                         this.$toast.success('登录成功');
                         let user = res.data;
                         this.$store.commit("updateLogin", true);
-                        sessionStorage.userInfo = JSON.stringify(user);
+                        localStorage.userInfo = JSON.stringify(user);
                         this.$router.push("/index");
                     } else {
                         toast.clear();
@@ -58,6 +58,12 @@
                 this.$router.push("/register");
             }
         },
+        mounted() {
+            //自动检测账号,登录进入系统
+            if (localStorage.userInfo != null) {
+                this.$router.push("/index");
+            }
+        }
     };
 </script>
 

+ 134 - 0
fhKeeper/formulahousekeeper/timesheet_h5/src/views/msg/index.vue

@@ -0,0 +1,134 @@
+<template>
+    <div>
+        <van-nav-bar title="消息记录" left-text="返回" @click-left="back" fixed left-arrow/>
+        
+        <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', ' ')" >
+                    <span v-if="item.checked == 1" style="color:green">已读</span>
+                    <span v-if="item.checked == 0" style="color:red">未读</span>
+                </van-cell>
+            </van-list>
+        </div>
+    </div>
+</template>
+
+<script>
+    export default {
+        data() {
+            return {
+                user: JSON.parse(localStorage.userInfo),
+                
+                total: 0,
+                page: 1,
+                size: 20,
+                list: [],
+                loading: false,
+                finished: false,
+                error: false,
+                refreshing: false,
+                
+                show: false,
+                title: "标题",
+                
+            };
+        },
+        created() {
+        },
+        methods: {
+            
+            // 返回
+            back() {
+                history.back();
+            },
+
+            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();});
+            },
+            
+            //获取消息
+            getMessage() {
+                if (this.refreshing) {
+                    this.list = [];
+                    this.refreshing = false;
+                }
+                if(this.total == this.list.length && this.list.length != 0) {
+                    this.loading = false;
+                    this.finished = true;
+                    return false;
+                }
+                this.$axios.post("/information/list", {
+                })
+                .then(res => {
+                    if(res.code == "ok") {
+                        this.loading = false;
+                        this.finished = true;
+                        this.list = res.data;
+                    } else {
+                        this.$toast.fail('获取失败');
+                    }
+                }).catch(err=> {toast.clear();});
+            },
+
+            onRefresh() {
+                this.finished = false;
+                this.loading = true;
+                this.page = 1;
+                this.getMessage();
+            },
+
+        },
+
+        mounted() {
+        }
+    };
+</script>
+
+<style lang="less" scoped>
+    .login_form {
+        margin-top: 46px;
+    }
+
+    .one_report {
+        margin-bottom: 15px;
+    }
+
+    .form_text {
+        margin: 15px 0 30px;
+        padding: 0 12px;
+    }
+    
+    .form_btn {
+        text-align: right;
+    }
+
+    .form_btn button {
+        margin-left: 10px;
+    }
+
+    .one_report_data {
+        margin-bottom: 20px;
+        padding: 0 22px;
+        div {
+            line-height: 30px;
+        }
+    }
+    .userCheckbox {
+        padding: 10px;;
+    }
+</style>
+<style lang="less">
+    .van-nav-bar .van-icon , .van-nav-bar__text {
+        color: #20a0ff;
+    }
+</style>

+ 2 - 2
fhKeeper/formulahousekeeper/timesheet_h5/src/views/my/children/center.vue

@@ -37,14 +37,14 @@
 
         data() {
             return {
-                userInfo: JSON.parse(sessionStorage.userInfo),
+                userInfo: JSON.parse(localStorage.userInfo),
             }
         },
 
         methods: {
             logout() {
                 this.$store.commit("updateLogin", false);
-                sessionStorage.removeItem("userInfo");
+                localStorage.removeItem("userInfo");
                 this.$router.push("/login");
             }
         },

+ 119 - 7
fhKeeper/formulahousekeeper/timesheet_h5/src/views/project/index.vue

@@ -6,7 +6,7 @@
             <van-pull-refresh v-model="refreshing" @refresh="onRefresh">
                 <van-list v-model="loading" :finished="finished" finished-text="没有更多了" :error.sync="error" error-text="请求失败,点击重新加载" @load="getProject">
                     <van-swipe-cell v-for="(item,index) in list" :key="index">
-                        <van-cell :border="false" :title="item.projectName"/>
+                        <van-cell :border="false" :title="item.projectName" :value="item.projectCode"/>
                         <template slot="right">
                             <van-button square type="info" text="编辑" @click="openDialog(index)"/>
                             <van-button square type="danger" text="删除" @click="delPro(index)"/>
@@ -17,9 +17,24 @@
 
             <van-dialog v-model="show" :title="title" show-cancel-button :beforeClose="chargeBtn">
                 <van-form style="margin: 0.4rem 0;">
+                    <van-field v-model="form.projectCode" name="项目编号" label="项目编号" placeholder="请填写项目编号" />
                     <van-field v-model="form.projectName" name="项目名称" label="项目名称" placeholder="请填写项目名称" :rules="[{ required: true, message: '请填写项目名称' }]"/>
+                    <van-field readonly clickable name="userNames" v-model="form.userNames"  label="参与人" 
+                    placeholder="请选择参与人" @click="clickPicker()" />
+                    <van-field readonly clickable  v-model="form.inchargerName"  label="负责人" 
+                    placeholder="请选择负责人" @click="showPickerIncharger = true" />
                 </van-form>
             </van-dialog>
+            <van-popup v-model="showPickerUser" position="bottom">
+                <van-search v-model="userName" placeholder="输入员工姓名搜索" @search="onSearch"></van-search>
+                <div style="minHeight:300px;">
+                <van-checkbox class="userCheckbox" v-for="(item) in userList" :key="item.id" v-model="item.isChecked" >{{item.name}}</van-checkbox>
+                <van-button style="width:100%;" @click="refreshParticipate();showPickerUser=false">确定</van-button>
+                </div>
+            </van-popup>
+            <van-popup v-model="showPickerIncharger" position="bottom">
+                <van-picker show-toolbar :columns="inchargerUserList" value-key="name" @confirm="choseIncharger" @cancel="showPickerIncharger = false" />
+            </van-popup>
         </div>
     </div>
 </template>
@@ -28,8 +43,10 @@
     export default {
         data() {
             return {
-                user: JSON.parse(sessionStorage.userInfo),
-                
+                user: JSON.parse(localStorage.userInfo),
+                showPickerUser: false,
+                showPickerIncharger: false,
+                userName:null,
                 total: 0,
                 page: 1,
                 size: 20,
@@ -38,7 +55,9 @@
                 finished: false,
                 error: false,
                 refreshing: false,
-
+                allUserList:[],
+                userList:[],
+                inchargerUserList:[],
                 show: false,
                 title: "标题",
                 form: {
@@ -50,10 +69,64 @@
         created() {
         },
         methods: {
+            choseIncharger(value, index) {
+                this.showPickerIncharger = false;
+                this.form.inchargerName = value.name;
+                this.form.inchargerId = value.id;
+            },
+            onSearch(val) {
+                console.log(val);
+                this.userList = [];
+                this.allUserList.forEach(u=>{if (u.name.startsWith(val)) {
+                    this.userList.push(u);
+                }})
+                
+            },
+            //刷新参与人
+            refreshParticipate() {
+                this.form.userNames = '';
+                var that = this;
+                that.inchargerUserList = [];
+                that.form.userId = [];
+                this.userList.filter(u=>u.isChecked).forEach(u=>{
+                    that.form.userNames+=(u.name+',');
+                    that.form.userId.push(u.id);
+                    that.inchargerUserList.push(u);
+                });
+                if (this.form.userNames.length > 0) {
+                    this.form.userNames = this.form.userNames.substring(0, this.form.userNames.length-1);
+                }
+            },
+            onChange() {
+                console.log('===');
+            },
+            choseUsers() {
+
+            },
+            clickPicker() {
+                this.showPickerUser = true;
+            },
             // 返回
             back() {
                 history.back();
             },
+            //获取用户列表
+            getUsers() {
+                this.$axios.post("/user/getEmployeeList", {
+                    departmentId: -1,
+                    pageIndex: 1,
+                    pageSize: 99999
+                })
+                .then(res => {
+                    if(res.code == "ok") {
+                        this.loading = false;
+                        this.userList = res.data.records;
+                        this.allUserList = res.data.records;
+                    } else {
+                        this.$toast.fail('获取失败');
+                    }
+                }).catch(err=> {toast.clear();});
+            },
 
             // 获取项目
             getProject() {
@@ -96,11 +169,29 @@
                     this.form = {
                         id: null,
                         projectName: "",
+                        projectCode:null,
+                        inchargerName:null,
+                        inchargerId:null,
+                        userId:null,
+                        userNames:null
                     }
+                    // this.userList.forEach(u=>u.isChecked=false);
+                    // this.refreshParticipate();
                 } else {
                     this.form = {
                         id: this.list[i].id,
                         projectName: this.list[i].projectName,
+                        projectCode: this.list[i].projectCode,
+                        inchargerId: this.list[i].inchargerId,
+                        inchargerName: this.list[i].inchargerName,
+                    }
+                    var part = this.list[i].participator;
+                    
+                    if (part.length>0) {
+                        for (var j in part) {
+                            this.userList.filter(u=>u.id == part[j].id)[0].isChecked = true;
+                        }
+                        this.refreshParticipate();
                     }
                 }
                 this.show = true;
@@ -113,13 +204,30 @@
                         forbidClick: true,
                         duration: 0
                     });
+                    let formData = new FormData();
+                    formData.append("name", this.form.projectName);
+                    formData.append("code", this.form.projectCode);
+                    formData.append("inchargerId", this.form.inchargerId);
+                    for (var j in this.form.userId) {
+                        formData.append("userId", this.form.userId[j]);
+                    }
+                    
                     let form = {
-                        name: this.form.projectName
+                        name: this.form.projectName,
+                        code:this.form.projectCode,
+                        inchargerId: this.form.inchargerId,
+                        userId:this.form.userId
                     }
                     if(this.form.id != null) {
-                        form.id = this.form.id;
+                        // form.id = this.form.id;
+                        formData.append("id", this.form.id);
                     }
-                    this.$axios.post("/project/editProject", form)
+                    const config = {
+                        headers: {
+                        'Content-Type': 'multipart/form-data'
+                        }
+                    }    
+                    this.$axios.post("/project/editProject", formData, config)
                     .then(res => {
                         if(res.code == "ok") {
                             toast.clear();
@@ -167,6 +275,7 @@
         },
 
         mounted() {
+            this.getUsers();
         }
     };
 </script>
@@ -200,6 +309,9 @@
             line-height: 30px;
         }
     }
+    .userCheckbox {
+        padding: 10px;;
+    }
 </style>
 <style lang="less">
     .van-nav-bar .van-icon , .van-nav-bar__text {

+ 23 - 9
fhKeeper/formulahousekeeper/timesheet_h5/src/views/review/index.vue

@@ -17,7 +17,7 @@
                             总填报:
                             <span :style="parseFloat(item.reportTime)>parseFloat(item.calculateTime)+0.5?'color:red':''">{{item.reportTime}}h</span>
                         </span>
-                        <span>系统智能统计:{{item.calculateTime}}h</span>
+                        <!-- <span>系统智能统计:{{item.calculateTime}}h</span> -->
                     </div>
                     <div v-for="(item1,index1) in item.data" :key="index1" class="one_report_data">
                         <div class="project_title">项目:{{item1.project}}</div>
@@ -26,9 +26,9 @@
                         <van-divider />
                     </div>
                     <div class="form_btn" slot="footer">
-                        <van-button v-if="user.role != 0 && item.state == 0" size="small" type="info" @click="approve(item.id)">通过</van-button>
-                        <van-button v-if="user.role != 0 && item.state == 0" size="small" type="danger" @click="deny(item.id,1)">驳回</van-button>
-                        <van-button v-if="user.role != 0 && item.state == 1" size="small" type="danger" @click="deny(item.id,2)">撤销</van-button>
+                        <van-button v-if="(user.role != 0 || user.id == item.data[0].inchargerId) && item.state == 0" size="small" type="info" @click="approve(item.id, item)">通过</van-button>
+                        <van-button v-if="(user.role != 0 || user.id == item.data[0].inchargerId) && item.state == 0" size="small" type="danger" @click="deny(item.id,1, item)">驳回</van-button>
+                        <van-button v-if="(user.role != 0 || user.id == item.data[0].inchargerId) && item.state == 1" size="small" type="danger" @click="deny(item.id,2, item)">撤销</van-button>
                     </div>
                 </van-panel>
             </van-skeleton>
@@ -40,7 +40,7 @@
     export default {
         data() {
             return {
-                user: JSON.parse(sessionStorage.userInfo),
+                user: JSON.parse(localStorage.userInfo),
                 minDate: new Date(2010, 0, 1),
                 maxDate: new Date(new Date().getFullYear(),new Date().getMonth(),new Date().getDate()),
                 currentDate: new Date(),
@@ -106,12 +106,19 @@
                 }).catch(err=> {toast.clear();});
             },
 
-            approve(id) {
+            approve(id, item) {
                 const toast = this.$toast.loading({
                     forbidClick: true,
                     duration: 0
                 });
-                this.$axios.post("/report/approve", {id: id , date: this.nowTime})
+                var ids = '';
+                var data = item.data;
+                data.forEach(element => {
+                    if (element.id != null && element.id != '') {
+                        ids +=(element.id+',');
+                    }
+                });
+                this.$axios.post("/report/approve", {id: id , date: this.nowTime, reportIds: ids})
                 .then(res => {
                     if(res.code == "ok") {
                         toast.clear();
@@ -124,12 +131,19 @@
                 }).catch(err=> {toast.clear();});
             },
 
-            deny(id,i) {
+            deny(id,i, item) {
                 const toast = this.$toast.loading({
                     forbidClick: true,
                     duration: 0
                 });
-                this.$axios.post("/report/deny", {id: id , date: this.nowTime})
+                var ids = '';
+                var data = item.data;
+                data.forEach(element => {
+                    if (element.id != null && element.id != '') {
+                        ids +=(element.id+',');
+                    }
+                });
+                this.$axios.post("/report/deny", {id: id , date: this.nowTime, reportIds: ids})
                 .then(res => {
                     if(res.code == "ok") {
                         toast.clear();

+ 25 - 9
fhKeeper/formulahousekeeper/timesheet_h5/src/views/view/index.vue

@@ -9,19 +9,22 @@
             <van-popup v-model="showPicker" position="bottom">
                 <van-datetime-picker v-model="currentDate" type="date" :min-date="minDate" :max-date="maxDate" @confirm="changeTime" @cancel="showPicker = false"/>
             </van-popup>
-            <van-skeleton v-if="report.length!=0" v-for="(item,index) in report" title avatar :row="3" :loading="false">
-                <van-panel class="one_report" :title="item.name" :status="item.state==0?'待审核':item.state==1?'已通过':'已驳回'">
+            <van-skeleton  v-if="report.length!=0" v-for="(item,index) in report" title avatar :row="3" :loading="false">
+                <van-panel class="one_report" :title="item.name" :status="statusTxt[item.state]">
                     <div class="form_text">
-                        <span style="margin-right:20px;">
-                            <i v-if="parseFloat(item.reportTime)>parseFloat(item.calculateTime)+0.5" style="color:red;margin-right:8px;" class="fa fa-exclamation-triangle"></i>
+                        <span style="margin-right:20px;margin-left:5px;font-size:14px;">
+                            <!-- <i v-if="parseFloat(item.reportTime)>parseFloat(item.calculateTime)+0.5" 
+                                style="color:red;margin-right:8px;" class="fa fa-exclamation-triangle"></i> -->
                             总填报:
                             <span :style="parseFloat(item.reportTime)>parseFloat(item.calculateTime)+0.5?'color:red':''">{{item.reportTime}}h</span>
                         </span>
-                        <span>系统智能统计:{{item.calculateTime}}h</span>
+                        <!-- <span>系统智能统计:{{item.calculateTime}}h</span> -->
                     </div>
                     <div v-for="(item1,index1) in item.data" class="one_report_data">
                         <div class="project_title">项目:{{item1.project}}</div>
-                        <div class="project_time">时长:{{item1.time}}h</div>
+                        <div class="project_time">时长:
+                            <span v-if="item1.reportTimeType == 0" style="margin-right:10px;">{{fullDayTxt[item1.timeType]}}</span>
+                            <span v-if="item1.reportTimeType == 2" style="margin-right:10px;">{{item1.startTime+'-'+item1.endTime}}</span>{{item1.time}}h</div>
                         <div class="project_content">事项:<span v-html="item1.content"></span></div>
                         <van-divider />
                     </div>
@@ -35,13 +38,17 @@
     export default {
         data() {
             return {
-                user: JSON.parse(sessionStorage.userInfo),
+                hasWaiting: false,
+                state: 0,
+                user: JSON.parse(localStorage.userInfo),
                 minDate: new Date(2010, 0, 1),
                 maxDate: new Date(new Date().getFullYear(),new Date().getMonth(),new Date().getDate()),
                 currentDate: new Date(),
                 nowTime: this.format(new Date(new Date()),"yyyy-MM-dd"),
                 showPicker: false,
                 report: [],
+                fullDayTxt:['全天','上午','下午'],
+                statusTxt:["待审核", "已通过", "已驳回", "已撤销"],
             };
         },
         created() {
@@ -85,6 +92,7 @@
 
             // 获取日报
             getReport() {
+                this.hasWaiting = false;
                 const toast = this.$toast.loading({
                     forbidClick: true,
                     duration: 0
@@ -94,6 +102,13 @@
                     if(res.code == "ok") {
                         toast.clear();
                         this.report = res.data;
+                        //计算状态
+                        for (var i=0;i<this.report.length; i++) {
+                            var item = this.report[i];
+                            if (item.state == 0) {
+                                this.hasWaiting = true;
+                            }
+                        }
                     } else {
                         toast.clear();
                         this.$toast.fail('获取失败');
@@ -115,10 +130,11 @@
 
     .one_report {
         margin-bottom: 15px;
+        font-size:14px;
     }
 
     .form_text {
-        margin: 15px 0 30px;
+        margin: 15px 0 15px;
         padding: 0 12px;
     }
     
@@ -131,7 +147,7 @@
     }
 
     .one_report_data {
-        margin-bottom: 20px;
+        margin-bottom: 10px;
         padding: 0 22px;
         div {
             line-height: 30px;