瀏覽代碼

增加项目团队管理功能

seyason 4 年之前
父節點
當前提交
52a6580587
共有 84 個文件被更改,包括 3561 次插入235 次删除
  1. 2 2
      fhKeeper/formulahousekeeper/inva_4_tivo/about.html
  2. 12 0
      fhKeeper/formulahousekeeper/inva_4_tivo/css/styles.css
  3. 2 2
      fhKeeper/formulahousekeeper/inva_4_tivo/download.html
  4. 105 17
      fhKeeper/formulahousekeeper/inva_4_tivo/index.html
  5. 2 2
      fhKeeper/formulahousekeeper/inva_4_tivo/mobile.html
  6. 14 0
      fhKeeper/formulahousekeeper/management-platform/pom.xml
  7. 90 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/GroupTemplateController.java
  8. 21 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/GroupTmpstagesController.java
  9. 47 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/PdfFileController.java
  10. 59 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ProjectController.java
  11. 302 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ProjectDocumentController.java
  12. 4 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/ReportController.java
  13. 123 15
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/StagesController.java
  14. 393 5
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/TaskController.java
  15. 61 4
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/TaskGroupController.java
  16. 21 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/UserRecentTaskController.java
  17. 54 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/GroupTemplate.java
  18. 45 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/GroupTmpstages.java
  19. 54 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/PdfFile.java
  20. 27 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/Project.java
  21. 1 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/ProjectDocfolder.java
  22. 14 3
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/ProjectDocument.java
  23. 14 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/Report.java
  24. 36 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/Task.java
  25. 16 41
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/TaskLog.java
  26. 7 3
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/User.java
  27. 52 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/UserRecentTask.java
  28. 16 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/GroupTemplateMapper.java
  29. 16 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/GroupTmpstagesMapper.java
  30. 16 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/PdfFileMapper.java
  31. 5 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/ProjectMapper.java
  32. 5 1
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/TaskMapper.java
  33. 16 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/mapper/UserRecentTaskMapper.java
  34. 16 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/GroupTemplateService.java
  35. 16 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/GroupTmpstagesService.java
  36. 16 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/PdfFileService.java
  37. 8 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/ProjectService.java
  38. 6 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/TaskService.java
  39. 16 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/UserRecentTaskService.java
  40. 20 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/GroupTemplateServiceImpl.java
  41. 20 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/GroupTmpstagesServiceImpl.java
  42. 20 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/PdfFileServiceImpl.java
  43. 104 10
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ProjectServiceImpl.java
  44. 20 3
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ReportServiceImpl.java
  45. 24 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/TaskServiceImpl.java
  46. 20 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/UserRecentTaskServiceImpl.java
  47. 5 4
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/UserServiceImpl.java
  48. 16 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/util/ColorUtil.java
  49. 41 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/util/DocumentTypeUtil.java
  50. 19 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/util/FileUtil.java
  51. 133 0
      fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/util/OpenOfficeService.java
  52. 二進制
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/lib/jodconverter-core-3.0.jar
  53. 18 0
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/GroupTemplateMapper.xml
  54. 18 0
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/GroupTmpstagesMapper.xml
  55. 19 0
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/PdfFileMapper.xml
  56. 3 2
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/ProjectDocumentMapper.xml
  57. 5 1
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/ProjectMapper.xml
  58. 12 6
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/ReportMapper.xml
  59. 4 8
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/TaskLogMapper.xml
  60. 30 1
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/TaskMapper.xml
  61. 2 2
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/UserMapper.xml
  62. 20 0
      fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/UserRecentTaskMapper.xml
  63. 225 7
      fhKeeper/formulahousekeeper/timesheet/package-lock.json
  64. 1 0
      fhKeeper/formulahousekeeper/timesheet/package.json
  65. 561 14
      fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/demo_index.html
  66. 97 7
      fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.css
  67. 二進制
      fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.eot
  68. 1 1
      fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.js
  69. 161 0
      fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.json
  70. 42 0
      fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.svg
  71. 二進制
      fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.ttf
  72. 二進制
      fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.woff
  73. 二進制
      fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.woff2
  74. 29 1
      fhKeeper/formulahousekeeper/timesheet/src/common/js/util.js
  75. 7 3
      fhKeeper/formulahousekeeper/timesheet/src/main.js
  76. 46 19
      fhKeeper/formulahousekeeper/timesheet/src/routes.js
  77. 0 2
      fhKeeper/formulahousekeeper/timesheet/src/views/Home.vue
  78. 1 1
      fhKeeper/formulahousekeeper/timesheet/src/views/project/cost.vue
  79. 7 6
      fhKeeper/formulahousekeeper/timesheet/src/views/project/finance.vue
  80. 17 16
      fhKeeper/formulahousekeeper/timesheet/src/views/project/list.vue
  81. 2 2
      fhKeeper/formulahousekeeper/timesheet/src/views/settings/timetype.vue
  82. 15 7
      fhKeeper/formulahousekeeper/timesheet/src/views/team/index.vue
  83. 44 8
      fhKeeper/formulahousekeeper/timesheet/src/views/workReport/daily.vue
  84. 2 2
      fhKeeper/formulahousekeeper/timesheet/src/views/workReport/timer.vue

+ 2 - 2
fhKeeper/formulahousekeeper/inva_4_tivo/about.html

@@ -66,9 +66,9 @@
                     <li class="nav-item">
                         <a class="nav-link page-scroll" href="./mobile.html">手机版</a>
                     </li>
-                    <li class="nav-item">
+                    <!-- <li class="nav-item">
                         <a class="nav-link page-scroll" target="_blank" href="http://apps.ttkuaiban.com">团队协作</a>
-                    </li>
+                    </li> -->
                     <li class="nav-item other-item">
                         <a class="active nav-link page-scroll" href="./about.html">关于我们</a>
                     </li>

+ 12 - 0
fhKeeper/formulahousekeeper/inva_4_tivo/css/styles.css

@@ -125,12 +125,24 @@ a.white {
     background: #20a0ff;
 }
 
+.btn-orange {
+	border: 0.125rem solid #FF8C00;
+	border-radius: 2rem;
+	background-color: #FF8C00;
+}
+
 .btn-solid-reg:hover {
 	background-color: transparent;
 	color: #20a0ff;
 	text-decoration: none;
 }
 
+.btn-orange:hover {
+	background-color: transparent;
+	color: #FF8C00;
+	text-decoration: none;
+}
+
 .btn-solid-lg {
 	display: inline-block;
 	padding: 1.375rem 2.625rem 1.375rem 2.625rem;

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

@@ -51,9 +51,9 @@
                     <li class="nav-item">
                         <a class="nav-link page-scroll" href="./mobile.html">手机版</a>
                     </li>
-                    <li class="nav-item">
+                    <!-- <li class="nav-item">
                         <a class="nav-link page-scroll" target="_blank" href="http://apps.ttkuaiban.com">团队协作</a>
-                    </li>
+                    </li> -->
                     <li class="nav-item other-item">
                         <a class="nav-link page-scroll" href="./about.html">关于我们</a>
                     </li>

+ 105 - 17
fhKeeper/formulahousekeeper/inva_4_tivo/index.html

@@ -75,9 +75,9 @@
                     <li class="nav-item">
                         <a class="nav-link page-scroll" href="./mobile.html">手机版</a>
                     </li>
-                    <li class="nav-item">
+                    <!-- <li class="nav-item">
                         <a class="nav-link page-scroll" target="_blank" href="http://apps.ttkuaiban.com">团队协作</a>
-                    </li>
+                    </li> -->
                     <li class="nav-item other-item">
                         <a class="nav-link page-scroll" href="./about.html">关于我们</a>
                     </li>
@@ -99,13 +99,14 @@
                 <div class="row">
                     <div class="col-lg-12 col-xl-12">
                         <div class="text-container">
-                            <h2 style="color: #fff;">专注工时管理,数据客观真实,企业IPO利器</h2>
+                            <h2 style="color: #fff;">专注企业成本管理,提升团队工作效率</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>工时,实现可视化工时数据展示。</p>
+                            <p class="p-large">OKR项目管理方案践行者,实现高度灵活且配合紧密的团队协作</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 overload" style="margin-right: 5rem;">软件演示
                                     <div class="service2">
@@ -155,11 +156,11 @@
                         <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>
+                                <p>设计师填报工时,公司核算项目费用便捷准确。</p>
                             </div>
                         </div>
                         
@@ -174,17 +175,17 @@
                         </div>
                         <div class="scenes-body">
                             <img class="img-fluid" src="images/pic_1.png" alt="alternative">
-                            <p>按实际投入的工作时间核算成本,计算酬劳更方便。</p>
+                            <p>实现远程办公,兼职人员每日上报工作内容和花费时间,雇佣者审核确认后发放薪资</p>
                         </div>
                     </div>
                     <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>
+                            <p>高效协作,共享数据,实现快速迭代敏捷开发,每周一个版本不是梦</p>
                         </div>
                     </div>
                 </div>
@@ -212,33 +213,34 @@
                     </div>
                     <div class="card">
                         <div class="card-image">
-                            <img class="img-fluid" src="images/2.png" alt="alternative">
+                            <img class="img-fluid" src="images/4.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">
                         <div class="card-image">
-                            <img class="img-fluid" src="images/1.png" alt="alternative">
+                            <img class="img-fluid" src="images/2.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>
             </div>
             <div class="row">
                 <div class="col-lg-12">
                     <div class="card">
                         <div class="card-image">
-                            <img class="img-fluid" src="images/4.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 class="card">
@@ -315,6 +317,7 @@
                     <h2 class="h2-heading">定价方案</h2>
                 </div> <!-- end of col -->
             </div> <!-- end of row -->
+            <p style="font-size:20px;color:#20a0ff;text-align:left;">基础版-工时管理</p>
             <div class="row">
                 <div class="col-lg-12">
                     <div class="card">
@@ -395,6 +398,89 @@
                             </div>
                         </div>
                     </div>
+                </div>
+            </div>
+            <p style="font-size:20px;color:#FF8C00;text-align:left;">专业版-工时管理+团队协作</p>
+            <div class="row">
+                <div class="col-lg-12">
+                    <div class="card">
+                        <div class="card-body">
+                            <div class="card-title" style="color:#FF8C00">3人以内</div>
+                            <div class="price"><span class="currency"></span><span class="value" >免费</span></div>
+                            <div class="frequency " >1年</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>
+                                </li>
+                                <li class="media">
+                                    <div class="media-body"><i class="fa fa-check"></i>&nbsp;&nbsp;&nbsp;5G空间</div>
+                                </li>
+                            </ul>
+                            <div class="button-wrapper">
+                                <a class="btn-solid-reg page-scroll btn-orange" href="http://worktime.ttkuaiban.com/#/login" target="_blank">免费使用</a>
+                            </div>
+                        </div>
+                    </div>
+                    <div class="card">
+                        <div class="card-body">
+                            <div class="card-title" style="color:#FF8C00">10人以内</div>
+                            <div class="price"><span class="currency">¥</span><span class="value">3500</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>
+                                </li>
+                                <li class="media">
+                                    <div class="media-body"><i class="fa fa-check"></i>&nbsp;&nbsp;&nbsp;20G空间</div>
+                                </li>
+                            </ul>
+                            <div class="button-wrapper">
+                                <a class="btn-solid-reg page-scroll btn-orange" href="http://worktime.ttkuaiban.com/#/login" target="_blank">免费试用</a>
+                            </div>
+                        </div>
+                    </div>
+
+                    <div class="card">
+                        <div class="card-body">
+                            <div class="card-title" style="color:#FF8C00">30人以内</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>
+                                </li>
+                                <li class="media">
+                                    <div class="media-body"><i class="fa fa-check"></i>&nbsp;&nbsp;&nbsp;50G空间</div>
+                                </li>
+                            </ul>
+                            <div class="button-wrapper">
+                                <a class="btn-solid-reg page-scroll btn-orange" href="http://worktime.ttkuaiban.com/#/login" target="_blank">免费试用</a>
+                            </div>
+                        </div>
+                    </div>
+                    <div class="card">
+                        <div class="card-body">
+                            <div class="card-title" style="color:#FF8C00">50人以内</div>
+                            <div class="price"><span class="currency">¥</span><span class="value">15000</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>
+                                </li>
+                                <li class="media">
+                                    <div class="media-body"><i class="fa fa-check"></i>&nbsp;&nbsp;&nbsp;100G空间</div>
+                                </li>
+                            </ul>
+                            <div class="button-wrapper">
+                                <a class="btn-solid-reg page-scroll btn-orange" href="http://worktime.ttkuaiban.com/#/login" target="_blank">免费试用</a>
+                            </div>
+                        </div>
+                    </div>
+
                     <h4 class="overload">
                         定制开发,私有部署以及其他问题,请<span>咨询客服</span>。
                         <div class="service">
@@ -405,6 +491,8 @@
                     </h4>
                 </div>
             </div>
+
+
         </div>
     </div>
 

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

@@ -51,9 +51,9 @@
                     <li class="nav-item">
                         <a class="nav-link page-scroll active" href="./mobile.html">手机版</a>
                     </li>
-                    <li class="nav-item">
+                    <!-- <li class="nav-item">
                         <a class="nav-link page-scroll" target="_blank" href="http://apps.ttkuaiban.com">团队协作</a>
-                    </li>
+                    </li> -->
                     <li class="nav-item other-item">
                         <a class="nav-link page-scroll" href="./about.html">关于我们</a>
                     </li>

+ 14 - 0
fhKeeper/formulahousekeeper/management-platform/pom.xml

@@ -71,6 +71,20 @@
             <artifactId>fastjson</artifactId>
         </dependency>
 
+        <!-- openoffice -->
+        <dependency>
+            <groupId>com.artofsolving</groupId>
+            <artifactId>jodconverter</artifactId>
+            <version>2.2.1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.artofsolving</groupId>
+            <artifactId>jodconverter-core-3.0.jar</artifactId>
+            <version>1.0</version>
+            <scope>system</scope>
+            <systemPath>${basedir}/src/main/resources/lib/jodconverter-core-3.0.jar</systemPath>
+        </dependency>
+
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-data-redis</artifactId>

+ 90 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/GroupTemplateController.java

@@ -0,0 +1,90 @@
+package com.management.platform.controller;
+
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.management.platform.entity.GroupTemplate;
+import com.management.platform.entity.GroupTmpstages;
+import com.management.platform.entity.User;
+import com.management.platform.service.GroupTemplateService;
+import com.management.platform.service.GroupTmpstagesService;
+import com.management.platform.service.UserService;
+import com.management.platform.util.HttpRespMsg;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import java.util.List;
+
+/**
+ * <p>
+ *  前端控制器
+ * </p>
+ *
+ * @author Seyason
+ * @since 2021-05-05
+ */
+@RestController
+@RequestMapping("/group-template")
+public class GroupTemplateController {
+    @Resource
+    private HttpServletRequest request;
+    @Resource
+    private GroupTemplateService groupTemplateService;
+    @Resource
+    private GroupTmpstagesService groupTmpstagesService;
+    @Resource
+    private UserService userService;
+
+    @RequestMapping("/initData")
+    public HttpRespMsg initData() {
+        if (groupTemplateService.count() == 0) {
+            //系统中没有数据,需要初始化
+            String[] templateNames = {"工程设计","软硬件研发","客服工单处理"};
+            String[][] stages = {{"信息收集","策划","原型图","效果图","审核中","修改调整","完成"},
+                                {"需求分析","设计中","研发中","测试中","修改BUG","已发布"},
+                                {"用户问题","解决中","已解决","反馈用户&问题解决"}
+                                };
+            for (int i=0;i<templateNames.length;i++) {
+                String s = templateNames[i];
+                GroupTemplate template = new GroupTemplate();
+                template.setName(s);
+                template.setIsSystem(1);
+                groupTemplateService.save(template);
+                String[] curStages = stages[i];
+                int seq = 1;
+                for(String name:curStages) {
+                    GroupTmpstages sItem = new GroupTmpstages();
+                    sItem.setSequence(seq);
+                    sItem.setTemplateId(template.getId());
+                    sItem.setStagesName(name);
+                    groupTmpstagesService.save(sItem);
+                    seq++;
+                }
+            }
+        }
+        return new HttpRespMsg();
+    }
+
+    @RequestMapping("/getList")
+    public HttpRespMsg getList() {
+        if (groupTemplateService.count() == 0) {
+            initData();
+        }
+        String uid = request.getHeader("Token");
+        User user = userService.getById(uid);
+        QueryWrapper<GroupTemplate> templateQueryWrapper = new QueryWrapper<>();
+        templateQueryWrapper.eq("company_id", user.getCompanyId()).or().eq("is_system",1).orderByAsc("id");
+        List<GroupTemplate> list = groupTemplateService.list(templateQueryWrapper);
+        //查找任务列表名称
+        for (GroupTemplate template:list
+             ) {
+            template.setStagesList(groupTmpstagesService.list(new QueryWrapper<GroupTmpstages>().eq("template_id", template.getId())));
+        }
+        HttpRespMsg msg = new HttpRespMsg();
+        msg.data = list;
+        return msg;
+    }
+}
+

+ 21 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/GroupTmpstagesController.java

@@ -0,0 +1,21 @@
+package com.management.platform.controller;
+
+
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * <p>
+ *  前端控制器
+ * </p>
+ *
+ * @author Seyason
+ * @since 2021-05-05
+ */
+@RestController
+@RequestMapping("/group-tmpstages")
+public class GroupTmpstagesController {
+
+}
+

+ 47 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/PdfFileController.java

@@ -0,0 +1,47 @@
+package com.management.platform.controller;
+
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.management.platform.entity.PdfFile;
+import com.management.platform.service.PdfFileService;
+import com.management.platform.util.HttpRespMsg;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * <p>
+ *  前端控制器
+ * </p>
+ *
+ * @author Seyason
+ * @since 2021-04-27
+ */
+@RestController
+@RequestMapping("/pdf-file")
+public class PdfFileController {
+    @Resource
+    private PdfFileService pdfFileService;
+
+    /**
+     * 获取项目文档
+     * @param fileId
+     * @return
+     */
+    @RequestMapping("/getProjectFile")
+    private HttpRespMsg getProjectFile(Integer fileId) {
+        List<PdfFile> pdfFileList = pdfFileService.list(new QueryWrapper<PdfFile>().eq("type", 1).eq("file_id", fileId));
+        HttpRespMsg msg = new HttpRespMsg();
+        if (pdfFileList.size() > 0) {
+            msg.data = pdfFileList.get(0).getPdfUrl();
+        } else {
+            msg.setError("该格式不支持在线预览");
+        }
+
+        return msg;
+    }
+}
+

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

@@ -1,6 +1,7 @@
 package com.management.platform.controller;
 
 
+import com.management.platform.entity.Project;
 import com.management.platform.service.ProjectService;
 import com.management.platform.util.HttpRespMsg;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -62,7 +63,6 @@ public class ProjectController {
                                    Integer level,
                                    Integer budget
                                    ) {
-
         return projectService.editProject(id, name, code, userId, inchargerId, planStartDate, planEndDate, level, budget,request);
     }
 
@@ -120,5 +120,63 @@ public class ProjectController {
     public HttpRespMsg getProjectCost(String startDate, String endDate, @RequestParam Integer id) {
         return projectService.getProjectCost(startDate, endDate, id, request);
     }
+
+    /**
+     * 获取项目详细信息
+     * @param id
+     * @return
+     */
+    @RequestMapping("/detail")
+    public HttpRespMsg detail(@RequestParam Integer id) {
+        return projectService.detail(id, request);
+    }
+
+    /**
+     * 项目统计任务数量分布
+     * @param id
+     * @return
+     */
+    @RequestMapping("/taskSum")
+    public HttpRespMsg taskSum(@RequestParam Integer id) {
+        return projectService.taskSum(id, request);
+    }
+
+    @RequestMapping("/finish")
+    public HttpRespMsg finish(Integer id) {
+        Project project = new Project();
+        project.setId(id);
+        project.setStatus(2);
+        project.setFinishDate(LocalDate.now());
+        projectService.updateById(project);
+        return new HttpRespMsg();
+    }
+
+    @RequestMapping("/cancel")
+    public HttpRespMsg cancel(Integer id) {
+        HttpRespMsg msg = new HttpRespMsg();
+        Project old = projectService.getById(id);
+        if (old.getStatus() == 2) {
+            msg.setError("该项目已完成,无法撤销");
+        } else {
+            Project project = new Project();
+            project.setId(id);
+            project.setStatus(3);
+            projectService.updateById(project);
+        }
+
+        return msg;
+    }
+
+    @RequestMapping("/start")
+    public HttpRespMsg start(Integer id) {
+        projectService.restartProject(id);
+        return new HttpRespMsg();
+    }
+
+    @RequestMapping("/addMemb")
+    public HttpRespMsg addMemb(Integer id, String[] userId) {
+        return projectService.addMemb(id, userId);
+    }
+
 }
 

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

@@ -1,9 +1,41 @@
 package com.management.platform.controller;
 
 
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.management.platform.constant.Constant;
+import com.management.platform.entity.PdfFile;
+import com.management.platform.entity.ProjectDocfolder;
+import com.management.platform.entity.ProjectDocument;
+import com.management.platform.entity.User;
+import com.management.platform.mapper.PdfFileMapper;
+import com.management.platform.mapper.ProjectDocfolderMapper;
+import com.management.platform.mapper.ProjectDocumentMapper;
+import com.management.platform.mapper.UserMapper;
+import com.management.platform.service.ProjectDocumentService;
+import com.management.platform.util.DocumentTypeUtil;
+import com.management.platform.util.FileUtil;
+import com.management.platform.util.HttpRespMsg;
+import com.management.platform.util.OpenOfficeService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.web.bind.annotation.RequestMapping;
 
+import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.multipart.commons.CommonsMultipartFile;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
 
 /**
  * <p>
@@ -14,8 +46,277 @@ import org.springframework.web.bind.annotation.RestController;
  * @since 2021-04-19
  */
 @RestController
-@RequestMapping("/project-document")
+@RequestMapping("/document")
 public class ProjectDocumentController {
+    @Resource
+    private HttpServletRequest request;
+
+    @Resource
+    private UserMapper userMapper;
+    @Resource
+    private ProjectDocumentMapper projectDocumentMapper;
+    @Resource
+    private ProjectDocumentService projectDocumentService;
+    @Resource
+    private ProjectDocfolderMapper projectDocfolderMapper;
+    @Resource
+    private PdfFileMapper pdfFileMapper;
+    @Value("${upload.path}")
+    private String uploadPath;
+
+    /**
+     * 上传文件
+     * @param projectId 项目id
+     * @param folderId 文件夹id
+     * @param files 上传的文件
+     * @param response
+     * @return
+     * @throws Exception
+     */
+    @RequestMapping(value="uploadDocument")
+    public HttpRespMsg uploadDocument(
+            @RequestParam Integer projectId,
+            @RequestParam(required=false) Integer folderId,
+            @RequestParam("file") MultipartFile[] files,
+            HttpServletResponse response) throws Exception {
+        HttpRespMsg msg = new HttpRespMsg();
+        User user = (User) userMapper.selectById(request.getHeader("Token"));
+
+        OpenOfficeService openOfficeService = new OpenOfficeService();
+//        List<Part> partLists = partMapper.selectList(new QueryWrapper<Part>().eq("mould_id", userVO.getMouldId()));
+        openOfficeService.start();
+        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
+        for (MultipartFile file : files) {
+            ProjectDocument record = new ProjectDocument();
+            record.setCreatorId(user.getId());
+            record.setCreatorName(user.getName());
+            record.setDocumentName(file.getOriginalFilename());
+            record.setFolderId(folderId);
+            record.setProjectId(projectId);
+            if (file != null && !file.isEmpty()) {
+                //截取文件后缀
+                String fileSuffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
+                record.setDocumentType(DocumentTypeUtil.DocumentType(fileSuffix));
+                //处理文件
+                File dir = new File(uploadPath);
+                if (!dir.exists()) {
+                    dir.mkdir();
+                }
+                String fileName= "";
+                if (file!=null && !file.isEmpty()) {
+                    fileName = file.getOriginalFilename();
+                    System.out.println("上传文件名称"+file.getName() +  ", dir = " + dir.getAbsolutePath());
+                    int pos = fileName.lastIndexOf(".");
+                    String suffix = fileName.substring(pos).toLowerCase();
+                    //用uuid替换原始的文件名
+                    String purFName = UUID.randomUUID().toString().replaceAll("-", "");
+                    fileName = purFName + suffix;
+                    System.out.println(fileName);
+                    File saveFile = new File(dir, fileName);
+                    try {
+                        saveFile.createNewFile();
+                        file.transferTo(saveFile);
+                        //计算文件大小
+                        long fileSize = saveFile.length();
+                        String fileLength = FileUtil.getReadableFileSize(fileSize);
+                        record.setServerName(uploadPath + fileName);
+                        record.setSize(fileLength);
+                        String pathPrefix = "/upload/";
+                        record.setUrl(pathPrefix + fileName);
+                        //上传图片到OSS
+//                        OSSClient ossClient=AliyunOSSClientUtil.getOSSClient();
+//                        String md5key = AliyunOSSClientUtil.uploadObject2OSS(ossClient, saveFile, OSSClientConstants.BUCKET_NAME, OSSClientConstants.FOLDER);
+//                        String url = AliyunOSSClientUtil.getFullUrl(fileName);
+//                        record.setUrl(url);
+                        projectDocumentMapper.insert(record);
+                        String path = uploadPath;
+                        if (OpenOfficeService.canTransferToPdf(suffix)) {
+                            //上传完,需要生成pdf
+                            String dFile1 = path + UUID.randomUUID().toString().replaceAll("-", "") + ".pdf";
+                            File newFile = new File(dFile1);
+                            if (!newFile.exists()) {
+                                openOfficeService.office2PDF(path + fileName, dFile1);
+                                PdfFile pdfFile = new PdfFile();
+                                pdfFile.setPdfUrl(pathPrefix + dFile1.substring(path.length()));
+                                pdfFile.setFileId(record.getId());
+                                pdfFile.setType(1);
+                                pdfFile.setSourceFileUrl(record.getUrl());
+                                pdfFileMapper.insert(pdfFile);
+                            }
+                        }
+
+                        //生成原文件名称与服务器文件名称对应
+                        msg.data = record;
+                    } catch (IOException e) {
+                        e.printStackTrace();
+                        fileName = null;
+                        msg.setError(e.getMessage()+", path="+dir.getAbsolutePath());
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                        fileName = null;
+                        msg.setError(e.getMessage()+", path="+dir.getAbsolutePath());
+                    }
+                } else {
+                    msg.setError("文件不存在");
+                }
+            }
+        }
+
+        return msg;
+    }
+    //在线预览
+    //inputFilePath 文件路径
+    @RequestMapping(value="onlineShow")
+    public HttpRespMsg onlineShow(@RequestParam String inputFilePath) {
+        String destFileName = inputFilePath.substring(0, inputFilePath.lastIndexOf(".")+1)+"pdf";
+        File dir = new File(uploadPath);
+        if (!dir.exists()) {
+            dir.mkdir();
+        }
+
+        HttpRespMsg msg = new HttpRespMsg();
+        Map<String,String> map = new HashMap<String,String>();
+        File destFile = new File(dir, destFileName);
+        if(destFile.exists()) {
+            //文件已存在直接显示
+            map.put("pdfFileName", uploadPath + destFile.getName());
+        }else {
+            //文件不存在,转化后显示
+            OpenOfficeService service = new OpenOfficeService();
+            service.start();
+            File inputFile = new File(dir, inputFilePath);
+            Integer state = service.office2PDF(inputFile.getAbsolutePath(),destFile.getAbsolutePath());
+            if(state == 0){
+                //转换成功
+                map.put("pdfFileName", uploadPath + destFile.getName());
+            }else {
+                //转换失败
+            }
+            service.shutdown();
+        }
+        msg.data = map;
+        return msg;
+    }
+    @RequestMapping(value="delete")
+    public HttpRespMsg delDocument(@RequestParam Integer id, Integer isFolder) {
+        ProjectDocument record = new ProjectDocument();
+        record.setId(id);
+        record.setIsDeleted(1);
+        projectDocumentMapper.updateById(record);
+        //全部子文件都移到回收站
+        if (isFolder == 1) {
+            deleteSubFiles(record);
+        }
+        HttpRespMsg msg = new HttpRespMsg();
+        msg.data="删除成功";
+        return msg;
+    }
+
+    private void deleteSubFiles(ProjectDocument record) {
+        List<ProjectDocument> projectDocumentList = projectDocumentMapper.selectList(new QueryWrapper<ProjectDocument>().eq("folder_id", record.getId()));
+        projectDocumentList.forEach(p->{
+            //删除自己
+            ProjectDocument d = new ProjectDocument();
+            d.setId(p.getId());
+            d.setIsDeleted(1);
+            projectDocumentMapper.updateById(d);
+
+            if (p.getIsFolder() == 1) {
+                deleteSubFiles(p);
+            }
+        });
+    }
+
+    @RequestMapping(value="createDocument")
+    public HttpRespMsg createDocument(Integer id, Integer projectId, String documentName, Integer folderId, Integer isFolder) {
+        User user = userMapper.selectById(request.getHeader("Token"));
+        ProjectDocument record = new ProjectDocument();
+        record.setId(id);
+        record.setIsFolder(isFolder);
+        record.setDocumentName(documentName);
+        record.setFolderId(folderId);
+        record.setProjectId(projectId);
+        record.setCreatorId(user.getId());
+        record.setCreatorName(user.getName());
+        projectDocumentService.saveOrUpdate(record);
+        HttpRespMsg msg = new HttpRespMsg();
+        return msg;
+    }
+
+    /**
+     * 最近更新文件列表
+     * projectId 项目id
+     */
+    @RequestMapping(value="recentlyList")
+    public HttpRespMsg getRecentlyList(@RequestParam String projectId) {
+        QueryWrapper<ProjectDocument> exp = new QueryWrapper<ProjectDocument>();
+        exp.eq("project_id", projectId).eq("is_deleted", 0).eq("is_folder", 0).orderByDesc("indate").last("limit 20");
+        HttpRespMsg msg = new HttpRespMsg();
+        msg.data = projectDocumentMapper.selectList(exp);
+        return msg;
+    }
+    /**
+     * 所有文件列表
+     * projectId 项目id
+     */
+    @RequestMapping(value="allList")
+    public HttpRespMsg getAllList(Integer projectId, Integer parentFid) {
+        //检查,如果是首次使用没有数据,需要创建数据
+        String userId = request.getHeader("Token");
+        User user = userMapper.selectById(userId);
+        if (parentFid == null) {
+            QueryWrapper<ProjectDocument> firstQuery = new QueryWrapper<ProjectDocument>();
+            firstQuery.eq("project_id", projectId);
+            if (projectDocumentMapper.selectCount(firstQuery) == 0) {
+                String[] names = new String[]{"立项准备材料","项目过程文档","项目交付件"};
+                for (String name : names) {
+                    ProjectDocument doc = new ProjectDocument();
+                    doc.setProjectId(projectId);
+                    doc.setIsFolder(1);
+                    doc.setDocumentName(name);
+                    doc.setCreatorId(userId);
+                    doc.setCreatorName(user.getName());
+                    projectDocumentMapper.insert(doc);
+                }
+            }
+        }
+
+
+        QueryWrapper<ProjectDocument> exp = new QueryWrapper<ProjectDocument>();
+        exp.eq("project_id", projectId).ne("is_deleted",1);
 
+        if (parentFid != null) {
+            exp.eq("folder_id", parentFid);
+        } else {
+            exp.isNull("folder_id");
+        }
+        exp.orderByDesc("is_folder","indate");
+        List<ProjectDocument> docList = projectDocumentMapper.selectList(exp);
+        Map<String,Object> map = new HashMap<String,Object>();
+        HttpRespMsg msg = new HttpRespMsg();
+        msg.data=docList;
+        return msg;
+    }
+    /**
+     * 子文件及文件夹列表
+     * projectId 项目id
+     */
+    @RequestMapping(value="sonList")
+    public HttpRespMsg getsonList(@RequestParam("parentFid") Integer folderId, @RequestParam String projectId) {
+        QueryWrapper<ProjectDocument> exp = new QueryWrapper<ProjectDocument>();
+        exp.eq("project_id", projectId).ne("is_deleted",1).eq("folder_id", folderId);
+        exp.orderByDesc("indate");
+        List<ProjectDocument> docList = projectDocumentMapper.selectList(exp);
+        QueryWrapper<ProjectDocfolder> gde = new QueryWrapper<ProjectDocfolder>();
+        gde.eq("project_id", projectId).eq("parent_fid", folderId);
+        gde.orderByDesc("update_time");
+        List<ProjectDocfolder> folderList = projectDocfolderMapper.selectList(gde);
+        Map<String,Object>map = new HashMap<String,Object>();
+        map.put("docList", docList);
+        map.put("folderList", folderList);
+        HttpRespMsg msg = new HttpRespMsg();
+        msg.data=map;
+        return msg;
+    }
 }
 

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

@@ -84,7 +84,8 @@ public class ReportController {
                                   String[] startTime,
                                   String[] endTime,
                                   Integer[] reportTimeType,
-                                  String[] createDate) {
+                                  String[] createDate,
+                                  Integer[] taskId) {
         List<Report> reportList = new ArrayList<>();
         String token = request.getHeader("Token");
         BigDecimal hourCost = userService.getById(token).getCost();
@@ -95,10 +96,12 @@ public class ReportController {
             System.out.println("reportTimeType.length=="+reportTimeType.length);
             System.out.println("content.length=="+content.length);
             for (int i = 0; i < id.length; i++) {
+                System.out.println("任务ID=="+taskId[i]);
                 Report report = new Report()
                         .setId(id[i] == -1 ? null : id[i])
                         .setProjectId(projectId[i])
                         .setSubProjectId(subProjectId[i] == 0?null:subProjectId[i])
+                        .setTaskId(taskId[i] == null||taskId[i] == 0?null:taskId[i])
                         .setReportTimeType(reportTimeType[i])
                         .setContent(content[i])
                         .setState(0)

+ 123 - 15
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/StagesController.java

@@ -17,6 +17,8 @@ import org.springframework.web.bind.annotation.RestController;
 
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
+import java.time.LocalDate;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.stream.Collectors;
@@ -65,9 +67,27 @@ public class StagesController {
         queryWrapper.orderByAsc("sequence");
 
         List<Stages> list = stagesService.list(queryWrapper);
-        List<Task> tasks = taskService.list(new QueryWrapper<Task>().in("group_id", item.getGroupId()));
+
+        QueryWrapper<Task> taskQueryWrapper = new QueryWrapper<Task>();
+        taskQueryWrapper.in("group_id", item.getGroupId());
+        taskQueryWrapper.isNull("parent_tid");
+        taskQueryWrapper.orderByAsc("task_status","seq");
+
+        List<Task> tasks = taskService.list(taskQueryWrapper);
+        List<Integer> collect = tasks.stream().map(Task::getId).collect(Collectors.toList());
+        collect.add(-1);
+        List<Task> subTasks = taskService.list(new QueryWrapper<Task>().in("parent_tid", collect));
+
         list.forEach(stages -> {
-            stages.setTaskList(tasks.stream().filter(t->t.getStagesId().equals(stages.getId())).collect(Collectors.toList()));
+            List<Task> taskList = tasks.stream().filter(t -> t.getStagesId().equals(stages.getId())).collect(Collectors.toList());
+            stages.setTaskList(taskList);
+            //设置子任务
+            taskList.forEach(t->{
+                List<Task> subList = subTasks.stream().filter(s -> s.getParentTid().equals(t.getId())).collect(Collectors.toList());
+                t.setSubTaskList(subList);
+                long count = subList.stream().filter(s -> s.getTaskStatus() == 1).count();
+                t.setSubTaskFinishNum((int)count);
+            });
         });
 
         msg.data = list;
@@ -83,14 +103,23 @@ public class StagesController {
     public HttpRespMsg delete(Stages item) {
         HttpRespMsg msg = new HttpRespMsg();
         //检查,如果分组下有任务,不得删除
-        int cnt = taskService.count(new QueryWrapper<Task>().eq("group_id", item.getId()));
+        int cnt = taskService.count(new QueryWrapper<Task>().eq("stages_id", item.getId()));
         if (cnt > 0) {
-            msg.setError("该分组下存在任务,不可删除");
+            msg.setError("该任务列表下存在任务,不可删除");
         } else {
+            //查询当前要删除的任务列表的位置排序,重新调整后面的列表排序
+            Stages stages = stagesService.getById(item.getId());
+            stages.getSequence();
+            QueryWrapper<Stages> stagesQueryWrapper = new QueryWrapper<>();
+            stagesQueryWrapper.eq("group_id", item.getGroupId()).gt("sequence", stages.getSequence());
             stagesService.removeById(item.getId());
-            QueryWrapper<Stages> queryWrapper = new QueryWrapper<Stages>();
-            queryWrapper.eq("group_id", item.getGroupId());
-            msg.data = stagesService.list(queryWrapper);
+            List<Stages> afterList = stagesService.list(stagesQueryWrapper);
+            afterList.forEach(a->{
+                a.setSequence(a.getSequence() -1);
+            });
+            stagesService.updateBatchById(afterList);
+
+            return list(item);
         }
 
         return msg;
@@ -104,21 +133,100 @@ public class StagesController {
     @RequestMapping("/list")
     public HttpRespMsg list(Stages item) {
         HttpRespMsg msg = new HttpRespMsg();
-        QueryWrapper<Stages> queryWrapper = new QueryWrapper<Stages>();
-        queryWrapper.eq("group_id", item.getGroupId());
-        queryWrapper.orderByAsc("sequence");
-
-        List<Stages> list = stagesService.list(queryWrapper);
+        QueryWrapper<Stages> stagesQueryWrapper = new QueryWrapper<Stages>();
+        stagesQueryWrapper.eq("group_id", item.getGroupId());
+        String userId = request.getHeader("Token");
+        stagesQueryWrapper.orderByAsc("sequence");
+        if (stagesService.count(stagesQueryWrapper) == 0) {
+            //创建默认列表
+            Stages stage = new Stages();
+            stage.setGroupId(item.getGroupId());
+            stage.setSequence(1);
+            stage.setProjectId(item.getProjectId());
+            stage.setStagesName("工作开展");
+            stagesService.save(stage);
+        }
+        List<Stages> list = stagesService.list(stagesQueryWrapper);
 
-        List<Task> tasks = taskService.list(new QueryWrapper<Task>().eq("group_id", item.getGroupId()));
+        QueryWrapper<Task> queryWrapper = new QueryWrapper<Task>();
+        //按任务分组查看
+        queryWrapper.eq("group_id", item.getGroupId());
+        queryWrapper.isNull("parent_tid");
+        queryWrapper.orderByAsc("seq");
+        List<Task> tasks = taskService.list(queryWrapper);
+        List<Task> subTasks = new ArrayList<>();
+        if (tasks.size() > 0) {
+            List<Integer> collect = tasks.stream().map(Task::getId).collect(Collectors.toList());
+            subTasks.addAll(taskService.list(new QueryWrapper<Task>().in("parent_tid", collect)));
+        }
         System.out.println("总任务数量"+tasks.size()+","+item.getGroupId());
+
         list.forEach(stages -> {
-            stages.setTaskList(tasks.stream().filter(t->t.getStagesId().equals(stages.getId())).collect(Collectors.toList()));
-            System.out.println(stages.getStagesName() + "-任务:"+stages.getTaskList().size());
+            List<Task> taskList = tasks.stream().filter(t -> t.getStagesId().equals(stages.getId())).collect(Collectors.toList());
+            stages.setTaskList(taskList);
+            if (taskList.size() > 0) {
+                //设置子任务
+                taskList.forEach(t->{
+                    List<Task> subList = subTasks.stream().filter(s -> s.getParentTid().equals(t.getId())).collect(Collectors.toList());
+                    t.setSubTaskList(subList);
+                    long count = subList.stream().filter(s -> s.getTaskStatus() == 1).count();
+                    t.setSubTaskFinishNum((int)count);
+                });
+            }
         });
 
         msg.data = list;
         return msg;
     }
+
+    @RequestMapping("/changeStageOrder")
+    public HttpRespMsg changeStageOrder(Integer groupId, Integer oldIndex, Integer newIndex) {
+        QueryWrapper<Stages> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("group_id", groupId).orderByAsc("sequence").last("limit " + oldIndex+",1");
+        List<Stages> sList = stagesService.list(queryWrapper);
+        //先按顺序取到移动的元素
+        Stages curItem = sList.get(0);
+
+        queryWrapper = new QueryWrapper<>();
+        int startSeq = 0;
+        if (newIndex > 0) {
+            int beforeItemIndex = 0;
+            beforeItemIndex = newIndex > oldIndex?newIndex:newIndex-1;
+
+            queryWrapper.eq("group_id", groupId).orderByAsc("sequence").last("limit " +beforeItemIndex+", 1");
+            List<Stages> dataList = stagesService.list(queryWrapper);
+            if (dataList.size() > 0) {
+                Stages beforeItem = dataList.get(0);
+                System.out.println("前面的列表:"+beforeItem.getStagesName()+", seq="+beforeItem.getSequence());
+                startSeq = beforeItem.getSequence() + 1;
+            } else {
+                startSeq = 1;
+            }
+        } else {
+            //移动到了第一个位置
+            startSeq = 1;
+        }
+
+        curItem.setSequence(startSeq);
+        //在新位置下面的包括原来占据新位置的,全部调整,从startSeq开始递增
+        queryWrapper = new QueryWrapper<Stages>();
+        queryWrapper.eq("group_id", groupId).ge("sequence", startSeq).orderByAsc("sequence");
+        List<Stages> dataList = stagesService.list(queryWrapper);
+        if (dataList.size() > 0) {
+            List<Stages> batchList = new ArrayList<>();
+            for (Stages t:dataList) {
+                Stages item = new Stages();
+                item.setId(t.getId());
+                startSeq++;
+                item.setSequence(startSeq);
+                batchList.add(item);
+            }
+            stagesService.updateBatchById(batchList);
+        }
+
+        stagesService.updateById(curItem);
+
+        return new HttpRespMsg();
+    }
 }
 

+ 393 - 5
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/TaskController.java

@@ -1,12 +1,13 @@
 package com.management.platform.controller;
 
 
+import com.alibaba.fastjson.JSONArray;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.management.platform.entity.Task;
-import com.management.platform.entity.User;
+import com.management.platform.entity.*;
 import com.management.platform.mapper.UserMapper;
-import com.management.platform.service.TaskService;
+import com.management.platform.service.*;
 import com.management.platform.util.HttpRespMsg;
+import org.springframework.util.StringUtils;
 import org.springframework.web.bind.annotation.RequestMapping;
 
 import org.springframework.web.bind.annotation.RestController;
@@ -14,7 +15,9 @@ import org.springframework.web.bind.annotation.RestController;
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
 import java.time.LocalDate;
+import java.util.ArrayList;
 import java.util.List;
+import java.util.stream.Collectors;
 
 /**
  * <p>
@@ -32,8 +35,17 @@ public class TaskController {
     @Resource
     private TaskService taskService;
     @Resource
+    private StagesService stagesService;
+    @Resource
+    private ProjectService projectService;
+    @Resource
+    private UserRecentTaskService userRecentTaskService;
+    @Resource
     private UserMapper userMapper;
-
+    @Resource
+    private TaskLogService taskLogService;
+    @Resource
+    private TaskCommentService taskCommentService;
     @RequestMapping("/save")
     public HttpRespMsg save(Task task) {
         String userId = request.getHeader("Token");
@@ -43,10 +55,22 @@ public class TaskController {
         task.setCreateDate(LocalDate.now());
         task.setCreaterId(userId);
         task.setCreaterName(user.getName());
+        task.setCreatorColor(user.getColor());
         task.setCompanyId(user.getCompanyId());
-        task.setExecutorName(userMapper.selectById(task.getExecutorId()).getName());
+        if (!StringUtils.isEmpty(task.getExecutorId())) {
+            User executor = userMapper.selectById(task.getExecutorId());
+
+            task.setExecutorName(executor.getName());
+            task.setExecutorColor(executor.getColor());
+        }
+        //有父任务,需要设置名称
+        if (task.getParentTid() != null && task.getParentTname() == null) {
+            task.setParentTname(taskService.getById(task.getParentTid()).getName());
+        }
+        boolean isNew = false;
         //新建的任务需要计算排序
         if (task.getId() == null) {
+            isNew = true;
             QueryWrapper<Task> queryWrapper = new QueryWrapper<Task>();
             queryWrapper.eq("stages_id", task.getStagesId()).orderByDesc("seq").last("limit 1");
             List<Task> taskList = taskService.list(queryWrapper);
@@ -55,10 +79,374 @@ public class TaskController {
             } else {
                 task.setSeq(taskList.get(0).getSeq() + 1);
             }
+        } else {
+            //更新的情况,需要对比是否修改了任务标题,更新子任务的parentTname
+            if (!taskService.getById(task.getId()).getName().equals(task.getName())) {
+                Task sample = new Task();
+                sample.setParentTname(task.getName());
+                taskService.update(sample, new QueryWrapper<Task>().eq("parent_tid", task.getId()));
+
+                UserRecentTask userRecentTask = new UserRecentTask();
+                userRecentTask.setTaskName(task.getName());
+                userRecentTaskService.update(userRecentTask, new QueryWrapper<UserRecentTask>().eq("task_id", task.getId()));
+            }
         }
 
         taskService.saveOrUpdate(task);
+        //更新执行人近期任务
+        if (!StringUtils.isEmpty(task.getExecutorId())) {
+            saveOrUpdateRecentTask(task, task.getExecutorId());
+        }
+
+        //新增任务,需要重新计算项目进度
+        if (isNew) {
+            updateProjectProgress(task.getProjectId());
+        }
+        return msg;
+    }
+
+    private void updateProjectProgress(Integer projectId) {
+        //更新项目完成度
+        //只有第一级任务才更新项目进度, 非已撤销状态的
+        List<Task> all = taskService.list(new QueryWrapper<Task>().eq("project_id", projectId).isNull("parent_tid").ne("task_status", 2));
+
+        if (all.size() > 0) {
+            long running = all.stream().filter(a -> a.getTaskStatus() == 1).count();
+            int progress = ((int) running) * 100 / all.size();
+            Project project = new Project();
+            project.setId(projectId);
+            project.setProgress(progress);
+            projectService.updateById(project);
+        }
+    }
+
+    @RequestMapping("/finish")
+    public HttpRespMsg finish(Task task) {
+        HttpRespMsg msg = new HttpRespMsg();
+        //进行完成操作时需要检查子任务是否全部完成
+        if (task.getTaskStatus() == 0) {
+            QueryWrapper<Task> subQuery = new QueryWrapper<Task>();
+            subQuery.eq("parent_tid", task.getId()).eq("task_status", 0);
+            int count = taskService.count(subQuery);
+            if (count > 0) {
+                msg.setError("请先完成全部子任务");
+                return msg;
+            }
+        }
+
+        if (task.getTaskStatus() == 0) {
+            task.setTaskStatus(1);
+            task.setFinishDate(LocalDate.now());
+            //计算排序,需要移动到最后
+            Task old = taskService.getById(task.getId());
+            if (task.getParentTid() == null) {
+                QueryWrapper<Task> queryWrapper = new QueryWrapper<>();
+                queryWrapper.eq("stages_id", old.getStagesId()).isNull("parent_tid").orderByDesc("seq").last("limit 1");
+                List<Task> afterList = taskService.list(queryWrapper);
+                if (afterList.size() > 0) {
+                    //取第一个,也就是正序排序的最后一个
+                    Task lastItem = afterList.get(0);
+                    if (!lastItem.getId().equals(old.getId())) {
+                        task.setSeq(lastItem.getSeq() + 1);//当前操作的任务不是最后一个的情况下,需要把它排到最后,+1
+                    }
+                }
+            }
+
+        } else if (task.getTaskStatus() == 1) {
+            task.setTaskStatus(0);
+        } else {
+            msg.setError("状态不对,无法操作");
+            return msg;
+        }
+
+        taskService.updateById(task);
+        //更新项目完成度
+        Task item = taskService.getById(task.getId());
+        if (item.getParentTid() == null) {
+            //只有第一级任务才更新项目进度, 非已撤销状态的
+            List<Task> all = taskService.list(new QueryWrapper<Task>().eq("project_id", item.getProjectId()).isNull("parent_tid").ne("task_status", 2));
+
+            if (all.size() > 0) {
+                long running = all.stream().filter(a -> a.getTaskStatus() == 1).count();
+                int progress = ((int) running) * 100 / all.size();
+                Project project = new Project();
+                project.setId(item.getProjectId());
+                project.setProgress(progress);
+                projectService.updateById(project);
+            }
+
+        }
+        return msg;
+    }
+
+    @RequestMapping("/changeOrder")
+    public HttpRespMsg changeOrder(Integer id, Integer oldIndex, Integer newIndex, Integer oldStagesId, Integer newStagesId) {
+        HttpRespMsg msg = new HttpRespMsg();
+        Task curItem = new Task();
+        curItem.setId(id);
+        if (!oldStagesId.equals(newStagesId)) {
+            //获取移动到的目标位置上一个数据的seq,计算当前任务的新seq
+            //跨stage移动,旧的stage上移除,切换stages后,旧的任务列表自动会重新排序,不需要再操作
+            curItem.setStagesId(newStagesId);
+            curItem.setStagesName(stagesService.getById(newStagesId).getStagesName());
+        }
+
+        QueryWrapper<Task> queryWrapper = new QueryWrapper<Task>();
+        int startSeq = 0;
+        if (newIndex > 0) {
+            int beforeItemIndex = 0;
+            if (oldStagesId.equals(newStagesId)) {
+                beforeItemIndex = newIndex > oldIndex?newIndex:newIndex-1;
+            } else {
+                //跨stages移动,相当于从下往上移动
+                beforeItemIndex = newIndex-1;
+            }
+            queryWrapper.eq("stages_id", newStagesId).isNull("parent_tid").orderByAsc("seq").last("limit " +beforeItemIndex+", 1");
+            List<Task> taskList = taskService.list(queryWrapper);
+            if (taskList.size() > 0) {
+                Task beforeItem = taskList.get(0);
+                System.out.println("前面的任务:"+beforeItem.getName()+", seq="+beforeItem.getSeq());
+                startSeq = beforeItem.getSeq() + 1;
+            } else {
+                startSeq = 1;
+            }
+        } else {
+            //移动到了第一个位置
+            startSeq = 1;
+        }
+
+        curItem.setSeq(startSeq);
+        //在新位置下面的包括原来占据新位置的,全部调整,从startSeq开始递增
+        queryWrapper = new QueryWrapper<Task>();
+        queryWrapper.eq("stages_id", newStagesId).isNull("parent_tid").ge("seq", startSeq).orderByAsc("seq");
+        List<Task> taskList = taskService.list(queryWrapper);
+        if (taskList.size() > 0) {
+            List<Task> batchList = new ArrayList<>();
+            for (Task t:taskList) {
+                Task item = new Task();
+                item.setId(t.getId());
+                startSeq++;
+                item.setSeq(startSeq);
+                batchList.add(item);
+            }
+            taskService.updateBatchById(batchList);
+        }
+
+        taskService.updateById(curItem);
         return msg;
     }
+
+
+    @RequestMapping("/list")
+    public HttpRespMsg list(Task task, Integer viewId, String order, boolean isDesc) {
+        HttpRespMsg msg = new HttpRespMsg();
+        String userId = request.getHeader("Token");
+        QueryWrapper<Task> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("project_id", task.getProjectId());
+        List<Stages> stagesList = stagesService.list(new QueryWrapper<Stages>().eq("project_id", task.getProjectId()));
+        if (isDesc) {
+            queryWrapper.orderByDesc(order);
+        } else {
+            queryWrapper.orderByAsc(order);
+        }
+
+        //按视图查看
+        if (viewId == 1) {
+            //全部任务
+        } else if (viewId == 2) {
+            //进行中的任务
+            queryWrapper.eq("task_status", 0);
+        } else if (viewId == 3) {
+            //已完成的任务
+            queryWrapper.eq("task_status", 1);
+        } else if (viewId == 4) {
+            //待安排的任务
+            queryWrapper.isNull("executor_id");
+        } else if (viewId == 5) {
+            //我创建的任务
+            queryWrapper.eq("creater_id", userId);
+        } else if (viewId == 6) {
+            //我执行的任务
+            queryWrapper.eq("executor_id", userId);
+        } else if (viewId == 7) {
+            //今天的任务
+            queryWrapper.eq("end_date", LocalDate.now());
+        } else if (viewId == 8) {
+            //已超期的任务,未完成的任务
+            queryWrapper.lt("end_date", LocalDate.now()).eq("task_status", 0);
+        }
+        List<Task> list = taskService.list(queryWrapper);
+        //设置列表名称
+        list.forEach(item->{
+            item.setStagesName(stagesList.stream().filter(s->s.getId().equals(item.getStagesId())).findFirst().get().getStagesName());
+        });
+        msg.data = list;
+        return msg;
+    }
+
+
+    /**
+     * 认领任务
+     * @param id
+     * @return
+     */
+    @RequestMapping("/addAsMyTask")
+    public HttpRespMsg addAsMyTask(Integer id) {
+        HttpRespMsg msg = new HttpRespMsg();
+        String userId = request.getHeader("Token");
+        Task task = new Task();
+        //检查是否已经被认领
+        Task t = taskService.getById(id);
+        if (t.getExecutorId() != null) {
+            if (t.getExecutorId().equals(userId)) {
+                msg.setError("您已认领过该任务,请勿重复操作");
+            } else {
+                msg.setError("该任务已被其他人认领");
+            }
+        } else {
+            task.setId(id);
+            task.setExecutorId(userId);
+            User user = userMapper.selectById(userId);
+            task.setExecutorName(user.getName());
+            task.setExecutorColor(user.getColor());
+            taskService.updateById(task);
+
+            //更新用户近期任务
+            saveOrUpdateRecentTask(task, userId);
+        }
+        return msg;
+    }
+
+    private void saveOrUpdateRecentTask(Task task, String userId) {
+        //更新用户近期任务
+        List<UserRecentTask> recentTaskList = userRecentTaskService.list(new QueryWrapper<UserRecentTask>().eq("task_id", task.getId()).eq("user_id", userId));
+        UserRecentTask recentTask = null;
+        if (recentTaskList.size() > 0) {
+            recentTask = recentTaskList.get(0);
+            if (recentTask != null) {
+                userRecentTaskService.removeById(recentTask.getId());
+            }
+        }
+        recentTask = new UserRecentTask();
+        recentTask.setTaskId(task.getId());
+        recentTask.setTaskName(task.getName());
+        recentTask.setProjectId(task.getProjectId());
+        recentTask.setUserId(userId);
+        userRecentTaskService.save(recentTask);
+    }
+
+    /**
+     * 获取任务详情
+     * @param id
+     * @return
+     */
+    @RequestMapping("/getTask")
+    public HttpRespMsg getTask(Integer id) {
+        HttpRespMsg msg = new HttpRespMsg();
+        String userId = request.getHeader("Token");
+        Task task = new Task();
+        Task t = taskService.getById(id);
+        //查询直接子任务
+        QueryWrapper<Task> subQuery = new QueryWrapper<Task>().eq("parent_tid", id);
+        t.setSubTaskList(taskService.list(subQuery));
+        msg.data = t;
+        return msg;
+    }
+
+    @RequestMapping("/getSubTask")
+    public HttpRespMsg getSubTask(Integer id) {
+        HttpRespMsg msg = new HttpRespMsg();
+        String userId = request.getHeader("Token");
+
+        //查询直接子任务
+        QueryWrapper<Task> subQuery = new QueryWrapper<Task>().eq("parent_tid", id);
+        msg.data = taskService.list(subQuery);
+        return msg;
+    }
+
+    @RequestMapping("/getRecentTask")
+    public HttpRespMsg getRecentTask(Integer projectId) {
+        HttpRespMsg msg = new HttpRespMsg();
+        String userId = request.getHeader("Token");
+
+        //查询直接子任务
+        QueryWrapper<UserRecentTask> queryWrapper = new QueryWrapper<UserRecentTask>().eq("project_id", projectId).eq("user_id", userId);
+        queryWrapper.orderByDesc("id");
+        msg.data = userRecentTaskService.list(queryWrapper);
+        return msg;
+    }
+
+
+    @RequestMapping("/getMileStoneList")
+    public HttpRespMsg getMileStoneList(Integer projectId) {
+        HttpRespMsg msg = new HttpRespMsg();
+        String userId = request.getHeader("Token");
+
+        QueryWrapper<Task> queryWrapper = new QueryWrapper<Task>().eq("project_id", projectId).eq("task_type", 1);
+        queryWrapper.orderByAsc("id");
+        msg.data = taskService.list(queryWrapper);
+        return msg;
+    }
+
+
+    @RequestMapping("/getExecutorPanel")
+    public HttpRespMsg getExecutorPanel(Integer projectId) {
+        return taskService.getExecutorPanel(projectId);
+    }
+
+    @RequestMapping("/getStagesPanel")
+    public HttpRespMsg getStagesPanel(Integer projectId) {
+        return taskService.getStagesPanel(projectId);
+    }
+    @RequestMapping("/getTopCostTask")
+    public HttpRespMsg getTopCostTask(Integer projectId) {
+        return taskService.getTopCostTask(projectId);
+    }
+
+    @RequestMapping("/delete")
+    public HttpRespMsg delete(Integer id) {
+        Task task = taskService.getById(id);
+        if (task.getParentTid() == null) {
+            //删除的是第一级任务,需要调整顺序
+            List<Task> afterList = taskService.list(new QueryWrapper<Task>().eq("stages_id", task.getStagesId()).isNull("parent_tid").gt("seq", task.getSeq()));
+            if (afterList.size() > 0) {
+                List<Task> finalList = new ArrayList<>();
+                afterList.forEach(a->{
+                    Task t = new Task();
+                    t.setId(a.getId());
+                    t.setSeq(a.getSeq() -1);
+                    finalList.add(t);
+                });
+                taskService.updateBatchById(finalList);
+            }
+        }
+        taskService.removeById(id);
+        //删除任务日志
+        taskLogService.remove(new QueryWrapper<TaskLog>().eq("task_id",  id));
+        //删除留言
+        taskCommentService.remove(new QueryWrapper<TaskComment>().eq("task_id", id));
+        deleteSubTask(task);
+
+        //删除根任务,需要重新计算项目进度
+        if (task.getParentTid() == null) {
+            updateProjectProgress(task.getProjectId());
+        }
+        return new HttpRespMsg();
+    }
+
+    private void deleteSubTask(Task task) {
+        List<Task> subTasks = taskService.list(new QueryWrapper<Task>().eq("parent_tid", task.getId()));
+        if (subTasks.size() > 0) {
+            taskService.remove(new QueryWrapper<Task>().eq("parent_tid", task.getId()));
+            List<Integer> collect = subTasks.stream().map(Task::getId).collect(Collectors.toList());
+            //删除任务日志
+            taskLogService.remove(new QueryWrapper<TaskLog>().in("task_id",  collect));
+            //删除留言
+            taskCommentService.remove(new QueryWrapper<TaskComment>().in("task_id", collect));
+            subTasks.forEach(s->{
+                deleteSubTask(s);
+            });
+        }
+    }
 }
 

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

@@ -2,10 +2,8 @@ package com.management.platform.controller;
 
 
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.management.platform.entity.Task;
-import com.management.platform.entity.TaskGroup;
-import com.management.platform.service.TaskGroupService;
-import com.management.platform.service.TaskService;
+import com.management.platform.entity.*;
+import com.management.platform.service.*;
 import com.management.platform.util.HttpRespMsg;
 import org.springframework.util.StringUtils;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -14,6 +12,8 @@ import org.springframework.web.bind.annotation.RestController;
 
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * <p>
@@ -33,6 +33,10 @@ public class TaskGroupController {
     private TaskGroupService taskGroupService;
     @Resource
     private TaskService taskService;
+    @Resource
+    private StagesService stagesService;
+    @Resource
+    private GroupTmpstagesService groupTmpstagesService;
     /**
      * 保存任务分组
      */
@@ -78,8 +82,61 @@ public class TaskGroupController {
         HttpRespMsg msg = new HttpRespMsg();
         QueryWrapper<TaskGroup> queryWrapper = new QueryWrapper<TaskGroup>();
         queryWrapper.eq("project_id", item.getProjectId());
+        if (taskGroupService.count(queryWrapper) == 0) {
+            //创建默认分组
+            TaskGroup group = new TaskGroup();
+            group.setProjectId(item.getProjectId());
+            group.setName("项目阶段");
+            taskGroupService.save(group);
+        }
         msg.data = taskGroupService.list(queryWrapper);
         return msg;
     }
+
+
+    @RequestMapping("/copy")
+    public HttpRespMsg copy(Integer id) {
+        TaskGroup taskGroup = taskGroupService.getById(id);
+        //复制分组下的任务列表
+        List<Stages> stagesList = stagesService.list(new QueryWrapper<Stages>().eq("group_id", id).orderByAsc("sequence"));
+        TaskGroup copyItem = new TaskGroup();
+        copyItem.setProjectId(taskGroup.getProjectId());
+        copyItem.setName(taskGroup.getName()+"-复制");
+        taskGroupService.save(copyItem);
+        if (stagesList.size() > 0) {
+            for (Stages stages : stagesList) {
+                stages.setId(null);
+                stages.setGroupId(copyItem.getId());
+            }
+        }
+        stagesService.saveBatch(stagesList);
+
+        return new HttpRespMsg();
+    }
+
+
+    @RequestMapping("/createFromTemplate")
+    public HttpRespMsg createFromTemplate(GroupTemplate template, Integer projectId) {
+        TaskGroup taskGroup = new TaskGroup();
+        taskGroup.setName(template.getName());
+        taskGroup.setProjectId(projectId);
+        taskGroupService.save(taskGroup);
+
+        //从模板创建任务列表
+        List<GroupTmpstages> stages = groupTmpstagesService.list(new QueryWrapper<GroupTmpstages>().eq("template_id", template.getId()));
+        List<Stages> batchList = new ArrayList<>();
+        stages.forEach(s->{
+            Stages item = new Stages();
+            item.setGroupId(taskGroup.getId());
+            item.setStagesName(s.getStagesName());
+            item.setSequence(s.getSequence());
+            item.setProjectId(projectId);
+            batchList.add(item);
+        });
+        stagesService.saveBatch(batchList);
+
+        return new HttpRespMsg();
+    }
+
 }
 

+ 21 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/controller/UserRecentTaskController.java

@@ -0,0 +1,21 @@
+package com.management.platform.controller;
+
+
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * <p>
+ *  前端控制器
+ * </p>
+ *
+ * @author Seyason
+ * @since 2021-04-27
+ */
+@RestController
+@RequestMapping("/user-recent-task")
+public class UserRecentTaskController {
+
+}
+

+ 54 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/GroupTemplate.java

@@ -0,0 +1,54 @@
+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 java.util.List;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 
+ * </p>
+ *
+ * @author Seyason
+ * @since 2021-05-05
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class GroupTemplate extends Model<GroupTemplate> {
+
+    private static final long serialVersionUID=1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    @TableField("name")
+    private String name;
+
+    @TableField("is_system")
+    private Integer isSystem;
+
+    /**
+     * 公司id
+     */
+    @TableField("company_id")
+    private Integer companyId;
+
+
+    @TableField(exist = false)
+    private List<GroupTmpstages> stagesList;
+    @TableField(exist = false)
+    private Boolean selected = false;
+    @Override
+    protected Serializable pkVal() {
+        return this.id;
+    }
+
+}

+ 45 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/GroupTmpstages.java

@@ -0,0 +1,45 @@
+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-05-05
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class GroupTmpstages extends Model<GroupTmpstages> {
+
+    private static final long serialVersionUID=1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    @TableField("template_id")
+    private Integer templateId;
+
+    @TableField("stages_name")
+    private String stagesName;
+
+    @TableField("sequence")
+    private Integer sequence;
+
+
+    @Override
+    protected Serializable pkVal() {
+        return this.id;
+    }
+
+}

+ 54 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/PdfFile.java

@@ -0,0 +1,54 @@
+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-04-27
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class PdfFile extends Model<PdfFile> {
+
+    private static final long serialVersionUID=1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    @TableField("pdf_url")
+    private String pdfUrl;
+
+    @TableField("file_id")
+    private Integer fileId;
+
+    /**
+     * 文件类型, 1-项目文档
+     */
+    @TableField("type")
+    private Integer type;
+
+    /**
+     * 源文件路径
+     */
+    @TableField("source_file_url")
+    private String sourceFileUrl;
+
+
+    @Override
+    protected Serializable pkVal() {
+        return this.id;
+    }
+
+}

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

@@ -6,6 +6,9 @@ import java.time.LocalDate;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableField;
 import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.experimental.Accessors;
@@ -16,7 +19,7 @@ import lombok.experimental.Accessors;
  * </p>
  *
  * @author Seyason
- * @since 2021-04-19
+ * @since 2021-04-30
  */
 @Data
 @EqualsAndHashCode(callSuper = false)
@@ -97,7 +100,30 @@ public class Project extends Model<Project> {
     @TableField("budget")
     private Integer budget;
 
+    /**
+     * 创建人id
+     */
+    @TableField("creator_id")
+    private String creatorId;
+
+    /**
+     * 创建人姓名
+     */
+    @TableField("creator_name")
+    private String creatorName;
+
+    /**
+     * 创建日期
+     */
+    @TableField("create_date")
+    private LocalDate createDate;
+
+
+    @TableField(exist = false)
+    private String inchargerName;
 
+    @TableField(exist = false)
+    private List<Map<String, Object>> participationList;
     @Override
     protected Serializable pkVal() {
         return this.id;

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

@@ -16,7 +16,7 @@ import lombok.experimental.Accessors;
  * </p>
  *
  * @author Seyason
- * @since 2021-04-19
+ * @since 2021-04-27
  */
 @Data
 @EqualsAndHashCode(callSuper = false)

+ 14 - 3
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/ProjectDocument.java

@@ -6,9 +6,12 @@ import com.baomidou.mybatisplus.annotation.TableId;
 import java.time.LocalDateTime;
 import com.baomidou.mybatisplus.annotation.TableField;
 import java.io.Serializable;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.experimental.Accessors;
+import org.springframework.format.annotation.DateTimeFormat;
 
 /**
  * <p>
@@ -16,7 +19,7 @@ import lombok.experimental.Accessors;
  * </p>
  *
  * @author Seyason
- * @since 2021-04-19
+ * @since 2021-04-28
  */
 @Data
 @EqualsAndHashCode(callSuper = false)
@@ -62,6 +65,8 @@ public class ProjectDocument extends Model<ProjectDocument> {
      * 创建时间
      */
     @TableField("indate")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    @JsonFormat(pattern = "yyyy-MM-dd")
     private LocalDateTime indate;
 
     /**
@@ -88,8 +93,14 @@ public class ProjectDocument extends Model<ProjectDocument> {
     /**
      * 文件状态0-存在,1-删除
      */
-    @TableField("flat")
-    private Integer flat;
+    @TableField("is_deleted")
+    private Integer isDeleted;
+
+    /**
+     * 是否是文件夹
+     */
+    @TableField("is_folder")
+    private Integer isFolder;
 
 
     @Override

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

@@ -1,6 +1,8 @@
 package com.management.platform.entity;
 
 import java.math.BigDecimal;
+
+import com.baomidou.mybatisplus.annotation.FieldStrategy;
 import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.extension.activerecord.Model;
 import java.time.LocalDate;
@@ -8,6 +10,8 @@ import com.baomidou.mybatisplus.annotation.TableId;
 import java.time.LocalDateTime;
 import com.baomidou.mybatisplus.annotation.TableField;
 import java.io.Serializable;
+import java.util.List;
+
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.experimental.Accessors;
@@ -18,7 +22,7 @@ import lombok.experimental.Accessors;
  * </p>
  *
  * @author Seyason
- * @since 2021-03-17
+ * @since 2021-04-27
  */
 @Data
 @EqualsAndHashCode(callSuper = false)
@@ -111,7 +115,16 @@ public class Report extends Model<Report> {
     @TableField("sub_project_id")
     private Integer subProjectId;
 
+    /**
+     * 任务id
+     */
+    @TableField(value = "task_id")
+    private Integer taskId;
 
+    @TableField(exist = false)
+    private List<SubProject> subProjectList;
+    @TableField(exist = false)
+    private List<UserRecentTask> taskList;
     @Override
     protected Serializable pkVal() {
         return this.id;

+ 36 - 1
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/Task.java

@@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.annotation.TableId;
 import java.time.LocalDateTime;
 import com.baomidou.mybatisplus.annotation.TableField;
 import java.io.Serializable;
+import java.util.List;
 
 import com.fasterxml.jackson.annotation.JsonFormat;
 import lombok.Data;
@@ -20,7 +21,7 @@ import org.springframework.format.annotation.DateTimeFormat;
  * </p>
  *
  * @author Seyason
- * @since 2021-04-21
+ * @since 2021-05-01
  */
 @Data
 @EqualsAndHashCode(callSuper = false)
@@ -56,6 +57,9 @@ public class Task extends Model<Task> {
     @TableField("creater_name")
     private String createrName;
 
+    @TableField("creator_color")
+    private String creatorColor;
+
     /**
      * 执行人id
      */
@@ -68,6 +72,9 @@ public class Task extends Model<Task> {
     @TableField("executor_name")
     private String executorName;
 
+    @TableField("executor_color")
+    private String executorColor;
+
     /**
      * 任务级别,0-一般 1-重要 2-紧急
      */
@@ -96,6 +103,7 @@ public class Task extends Model<Task> {
     @DateTimeFormat(pattern = "yyyy-MM-dd")
     private LocalDate endDate;
 
+
     /**
      * 项目id
      */
@@ -144,7 +152,34 @@ public class Task extends Model<Task> {
     @TableField("plan_hours")
     private Integer planHours;
 
+    /**
+     * 0-任务,1-里程碑,2-风险
+     */
+    @TableField("task_type")
+    private Integer taskType;
+
+    /**
+     * 父任务名称
+     */
+    @TableField("parent_tname")
+    private String parentTname;
+
+    /**
+     * 完成日期
+     */
+    @TableField("finish_date")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    private LocalDate finishDate;
+
+
+    @TableField(exist = false)
+    private String stagesName;
 
+    @TableField(exist = false)
+    private List<Task> subTaskList;
+    @TableField(exist = false)
+    private Integer subTaskFinishNum;
     @Override
     protected Serializable pkVal() {
         return this.id;

+ 16 - 41
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/TaskLog.java

@@ -1,6 +1,8 @@
 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;
@@ -14,7 +16,7 @@ import lombok.experimental.Accessors;
  * </p>
  *
  * @author Seyason
- * @since 2021-04-19
+ * @since 2021-05-04
  */
 @Data
 @EqualsAndHashCode(callSuper = false)
@@ -23,53 +25,20 @@ public class TaskLog extends Model<TaskLog> {
 
     private static final long serialVersionUID=1L;
 
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
     /**
      * 任务id
      */
     @TableField("task_id")
-    private String taskId;
-
-    /**
-     * 任务描述
-     */
-    @TableField("task_desc")
-    private String taskDesc;
-
-    /**
-     * 执行人姓名
-     */
-    @TableField("executor_name")
-    private String executorName;
-
-    /**
-     * 任务级别
-     */
-    @TableField("task_level")
-    private String taskLevel;
-
-    /**
-     * 任务状态
-     */
-    @TableField("task_status")
-    private String taskStatus;
-
-    /**
-     * 截止时间
-     */
-    @TableField("end_date")
-    private String endDate;
-
-    /**
-     * 阶段
-     */
-    @TableField("stages")
-    private String stages;
+    private Integer taskId;
 
     /**
      * 修改时间
      */
-    @TableField("update_date")
-    private LocalDateTime updateDate;
+    @TableField("mod_time")
+    private LocalDateTime modTime;
 
     /**
      * 修改人
@@ -83,10 +52,16 @@ public class TaskLog extends Model<TaskLog> {
     @TableField("user_name")
     private String userName;
 
+    /**
+     * 修改内容
+     */
+    @TableField("content")
+    private String content;
+
 
     @Override
     protected Serializable pkVal() {
-        return null;
+        return this.id;
     }
 
 }

+ 7 - 3
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-03-31
+ * @since 2021-04-21
  */
 @Data
 @EqualsAndHashCode(callSuper = false)
@@ -109,11 +109,15 @@ public class User extends Model<User> {
     @TableField("manage_dept_id")
     private Integer manageDeptId;
 
+    /**
+     * 头像颜色
+     */
+    @TableField("color")
+    private String color;
+
 
     @TableField(exist = false)
     private String departmentName;
-
-
     @Override
     protected Serializable pkVal() {
         return this.id;

+ 52 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/entity/UserRecentTask.java

@@ -0,0 +1,52 @@
+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 lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 
+ * </p>
+ *
+ * @author Seyason
+ * @since 2021-04-27
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class UserRecentTask extends Model<UserRecentTask> {
+
+    private static final long serialVersionUID=1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    @TableField("user_id")
+    private String userId;
+
+    @TableField("task_id")
+    private Integer taskId;
+
+    @TableField("task_name")
+    private String taskName;
+
+    @TableField("indate")
+    private LocalDateTime indate;
+
+    @TableField("project_id")
+    private Integer projectId;
+
+
+    @Override
+    protected Serializable pkVal() {
+        return this.id;
+    }
+
+}

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

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

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

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

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

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

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

@@ -2,7 +2,10 @@ package com.management.platform.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.management.platform.entity.Project;
+import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Update;
+import org.springframework.test.context.jdbc.Sql;
 
 import java.util.List;
 import java.util.Map;
@@ -21,4 +24,6 @@ public interface ProjectMapper extends BaseMapper<Project> {
     List<Map<String, Object>> getTimeCost(@Param("companyId") Integer companyId, @Param("startDate") String startDate, @Param("endDate") String endDate);
 
     List<Map<String, Object>> getProjectCost(@Param("startDate") String startDate, @Param("endDate") String endDate, @Param("projectId") Integer projectId);
+    @Update("update project set status = 1, finish_date = null where id = #{id}")
+    void restartProject(Integer id);
 }

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

@@ -3,6 +3,8 @@ package com.management.platform.mapper;
 import com.management.platform.entity.Task;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 
+import java.util.List;
+
 /**
  * <p>
  *  Mapper 接口
@@ -12,5 +14,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  * @since 2021-04-19
  */
 public interface TaskMapper extends BaseMapper<Task> {
-
+    List getExecutorPanel(Integer projectId);
+    List getStagesPanel(Integer projectId);
+    List getTopCostTask(Integer projectId);
 }

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

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

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

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

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

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

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

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

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

@@ -38,4 +38,12 @@ public interface ProjectService extends IService<Project> {
     HttpRespMsg updateProgress(Integer id, Integer progress, HttpServletRequest request);
 
     HttpRespMsg updateStatus(Integer id, Integer status, LocalDate finishDate, HttpServletRequest request);
+
+    HttpRespMsg detail(Integer id, HttpServletRequest request);
+
+    HttpRespMsg taskSum(Integer id, HttpServletRequest request);
+
+    HttpRespMsg restartProject(Integer id);
+
+    HttpRespMsg addMemb(Integer id, String[] userId);
 }

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

@@ -2,6 +2,7 @@ package com.management.platform.service;
 
 import com.management.platform.entity.Task;
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.management.platform.util.HttpRespMsg;
 
 /**
  * <p>
@@ -13,4 +14,9 @@ import com.baomidou.mybatisplus.extension.service.IService;
  */
 public interface TaskService extends IService<Task> {
 
+    HttpRespMsg getExecutorPanel(Integer projectId);
+
+    HttpRespMsg getStagesPanel(Integer projectId);
+
+    HttpRespMsg getTopCostTask(Integer projectId);
 }

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

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

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

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

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

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

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

@@ -0,0 +1,20 @@
+package com.management.platform.service.impl;
+
+import com.management.platform.entity.PdfFile;
+import com.management.platform.mapper.PdfFileMapper;
+import com.management.platform.service.PdfFileService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ *  服务实现类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2021-04-27
+ */
+@Service
+public class PdfFileServiceImpl extends ServiceImpl<PdfFileMapper, PdfFile> implements PdfFileService {
+
+}

+ 104 - 10
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/ProjectServiceImpl.java

@@ -11,6 +11,7 @@ import com.management.platform.mapper.*;
 import com.management.platform.service.ProjectService;
 import com.management.platform.util.HttpRespMsg;
 import com.management.platform.util.ExcelUtil;
+import com.management.platform.util.ListUtil;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
@@ -20,12 +21,14 @@ import org.springframework.util.StringUtils;
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.Part;
 import java.math.BigDecimal;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
 import java.time.temporal.TemporalAccessor;
 import java.util.*;
+import java.util.stream.Collectors;
 
 
 /**
@@ -49,6 +52,8 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
     @Resource
     private ProjectTimerMapper projectTimerMapper;
     @Resource
+    private TaskMapper taskMapper;
+    @Resource
     private TimeTypeMapper timeTypeMapper;
     @Resource
     private HttpServletResponse response;
@@ -81,11 +86,18 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
             //通过公司id获取该公司所有的项目列表
             User user = userMapper.selectById(request.getHeader("Token"));
             Integer companyId = user.getCompanyId();
-            //判断用户的角色,如果是管理员和负责人,查看全部的。如果是普通员工,只能是项目经理看到自己管理的
+            //判断用户的角色,如果是管理员和负责人,查看全部的。如果是普通员工,只能是看到参与的项目
             QueryWrapper<Project> queryWrapper = null;
             if (user.getRole() == 0) {
                 //普通员工
-                queryWrapper = new QueryWrapper<Project>().eq("incharger_id", user.getId());
+                List<Participation> pList = participationMapper.selectList(new QueryWrapper<Participation>().eq("user_id", user.getId()));
+                List<Integer> projectIds = new ArrayList<>();
+                if (pList.size() > 0) {
+                    projectIds = pList.stream().map(Participation::getProjectId).collect(Collectors.toList());
+                } else {
+                    projectIds.add(-1);
+                }
+                queryWrapper = new QueryWrapper<Project>().in("id", projectIds);
             } else {
                 queryWrapper = new QueryWrapper<Project>().eq("company_id", companyId);
             }
@@ -141,7 +153,8 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                                    HttpServletRequest request) {
         HttpRespMsg httpRespMsg = new HttpRespMsg();
         try {
-            Integer companyId = userMapper.selectById(request.getHeader("Token")).getCompanyId();
+            User user = userMapper.selectById(request.getHeader("Token"));
+            Integer companyId = user.getCompanyId();
             if (id == null) {
                 //新增项目
                 if (name == null) {
@@ -153,10 +166,17 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                         httpRespMsg.setError("提交失败:项目编号已存在");
                     } else {
                         Project project = new Project().setProjectName(name).setCompanyId(companyId).setProjectCode(code).setInchargerId(inchargerId)
-                                .setPlanStartDate(LocalDate.parse(planStartDate))
-                                .setPlanEndDate(LocalDate.parse(planEndDate))
                                 .setLevel(level)
+                                .setCreatorId(user.getId())
+                                .setCreatorName(user.getName())
+                                .setCreateDate(LocalDate.now())
                                 .setBudget(budget);
+                        if (!StringUtils.isEmpty(planStartDate)) {
+                            project.setPlanStartDate(LocalDate.parse(planStartDate));
+                        }
+                        if (!StringUtils.isEmpty(planEndDate)) {
+                            project.setPlanEndDate(LocalDate.parse(planEndDate));
+                        }
                         if (projectMapper.insert(project) == 0) {
                             httpRespMsg.setError("操作失败");
                         }
@@ -166,15 +186,25 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
             } else {
                 //修改项目
                 //检查项目编号不能重复
-                Integer count = projectMapper.selectCount(new QueryWrapper<Project>().eq("company_id", companyId).eq("project_code", code).ne("id", id));
+                Integer count = 0;
+                if (code != null) {
+                    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)
-                            .setPlanStartDate(LocalDate.parse(planStartDate))
-                            .setPlanEndDate(LocalDate.parse(planEndDate))
+                    Project p = new Project();
+                    p.setProjectName(name).setId(id).setCompanyId(companyId).setProjectCode(code).setInchargerId(inchargerId)
                             .setLevel(level)
-                            .setBudget(budget)) == 0) {
+                            .setBudget(budget);
+                    if (!StringUtils.isEmpty(planStartDate)) {
+                        p.setPlanStartDate(LocalDate.parse(planStartDate));
+                    }
+                    if (!StringUtils.isEmpty(planEndDate)) {
+                        p.setPlanEndDate(LocalDate.parse(planEndDate));
+                    }
+                    if (projectMapper.updateById(p) == 0) {
                         httpRespMsg.setError("操作失败");
                     } else {
                         //修改项目相关表
@@ -194,6 +224,7 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
                 }
             }
         } catch (NullPointerException e) {
+            e.printStackTrace();
             httpRespMsg.setError("验证失败");
             return httpRespMsg;
         }
@@ -358,6 +389,69 @@ public class ProjectServiceImpl extends ServiceImpl<ProjectMapper, Project> impl
         return httpRespMsg;
     }
 
+    @Override
+    public HttpRespMsg detail(Integer id, HttpServletRequest request) {
+        Project project = projectMapper.selectById(id);
+        if (project.getInchargerId() != null) {
+            User incharger = userMapper.selectById(project.getInchargerId());
+            if (incharger != null)
+                project.setInchargerName(incharger.getName());
+        }
+
+        //项目参与人
+        List<Map<String, Object>> participator = participationMapper.getParticipator(id);
+        project.setParticipationList(participator);
+        HttpRespMsg msg = new HttpRespMsg();
+        msg.data = project;
+
+        return msg;
+    }
+
+    @Override
+    public HttpRespMsg taskSum(Integer id, HttpServletRequest request) {
+        List<Task> allTask = taskMapper.selectList(new QueryWrapper<Task>().eq("project_id", id));
+        long finishCount = allTask.stream().filter(t -> t.getTaskStatus() == 1).count();
+        long unfinishCount = allTask.stream().filter(t -> t.getTaskStatus() == 0).count();
+        long timeupCount = allTask.stream().filter(t -> t.getTaskStatus() == 0 && t.getEndDate() != null && t.getEndDate().isBefore(LocalDate.now())).count();
+        long unassignCount = allTask.stream().filter(t -> t.getExecutorId() == null).count();
+        long todayTimeupCount = allTask.stream().filter(t -> t.getTaskStatus() == 0 && t.getEndDate() != null && t.getEndDate().isEqual(LocalDate.now())).count();
+        long timeupFinishCount = allTask.stream().filter(t -> t.getTaskStatus() == 1 && t.getEndDate() != null && t.getFinishDate() != null && t.getFinishDate().isAfter(t.getEndDate())).count();
+        long timeunsetCount = allTask.stream().filter(t -> t.getTaskStatus() == 0 && t.getEndDate() == null).count();
+        HashMap<String, Long> map = new HashMap<>();
+        map.put("total", (long)allTask.size());
+        map.put("finishCount", finishCount);
+        map.put("unfinishCount", unfinishCount);
+        map.put("timeupCount", timeupCount);
+        map.put("unassignCount", unassignCount);
+        map.put("todayTimeupCount", todayTimeupCount);
+        map.put("timeupFinishCount", timeupFinishCount);
+        map.put("timeunsetCount", timeunsetCount);
+        HttpRespMsg msg = new HttpRespMsg();
+        msg.data = map;
+        return msg;
+    }
+
+    @Override
+    public HttpRespMsg restartProject(Integer id) {
+        projectMapper.restartProject(id);
+        return new HttpRespMsg();
+    }
+
+    @Override
+    public HttpRespMsg addMemb(Integer id, String[] userId) {
+        List<String> userIdList = new ArrayList<>();
+        List<Participation> participationList = participationMapper.selectList(new QueryWrapper<Participation>().eq("project_id", id));
+        for (String uid: userId) {
+            if (participationList.stream().filter(p->p.getUserId().equals(uid)).count() == 0) {
+                Participation item = new Participation();
+                item.setProjectId(id);
+                item.setUserId(uid);
+                participationMapper.insert(item);
+            }
+        }
+        return new HttpRespMsg();
+    }
+
     //获取某个项目每个人分别需要的工时
     @Override
     public HttpRespMsg getProjectCost(String startDate, String endDate, Integer projectId, HttpServletRequest request) {

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

@@ -56,6 +56,12 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
     private DepartmentService departmentService;
     @Resource
     private DepartmentMapper departmentMapper;
+    @Resource
+    private SubProjectMapper subProjectMapper;
+    @Resource
+    private TaskMapper taskMapper;
+    @Resource
+    private UserRecentTaskMapper userRecentTaskMapper;
 
     @Value(value = "${upload.path}")
     private String path;
@@ -268,9 +274,20 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
             Integer companyId = userMapper.selectById(userId).getCompanyId();
             Map<String, Object> resultMap = new HashMap<>();
             //获取某日本人的所有日志
-            resultMap.put("report", reportMapper.selectList(new QueryWrapper<Report>()
+            List<Report> reports = reportMapper.selectList(new QueryWrapper<Report>()
                     .eq("creator_id", userId)
-                    .eq("create_date", LocalDate.parse(date, DateTimeFormatter.ofPattern("yyyy-MM-dd")))));
+                    .eq("create_date", LocalDate.parse(date, DateTimeFormatter.ofPattern("yyyy-MM-dd"))));
+            List<Integer> integerList = reports.stream().map(Report::getProjectId).collect(Collectors.toList());
+
+            List<SubProject> subProjectList = integerList.size() > 0?subProjectMapper.selectList(new QueryWrapper<SubProject>().in("project_id",integerList)):new ArrayList<>();
+
+            List<UserRecentTask> taskList = integerList.size() > 0?userRecentTaskMapper.selectList(new QueryWrapper<UserRecentTask>().in("project_id", integerList).orderByDesc("id")):new ArrayList<>();
+            //获取当前项目的子项目列表,任务列表
+            reports.forEach(r->{
+                r.setSubProjectList(subProjectList.stream().filter(s->s.getProjectId().equals(r.getProjectId())).collect(Collectors.toList()));
+                r.setTaskList(taskList.stream().filter(t->t.getProjectId().equals(r.getProjectId()) && t.getUserId().equals(r.getCreatorId())).collect(Collectors.toList()));
+            });
+            resultMap.put("report", reports);
             //顺便再获取一下可分配时间
             Integer totalWorkingTime = 0;
             //以下区间被认为是工作时间
@@ -287,7 +304,7 @@ public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> impleme
             }
             //把总秒数转为double后换算为小时并保留两位小数
             resultMap.put("time", new DecimalFormat("0.00").format((double) totalWorkingTime / 3600));
-            //顺便返回该公司全部的计划
+            //顺便返回该公司全部的项目
             resultMap.put("project", projectMapper.selectList(new QueryWrapper<Project>()
                     .eq("company_id", userMapper.selectById(userId).getCompanyId())));
             //顺便返回公司的工作时间设置

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

@@ -4,8 +4,11 @@ import com.management.platform.entity.Task;
 import com.management.platform.mapper.TaskMapper;
 import com.management.platform.service.TaskService;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.management.platform.util.HttpRespMsg;
 import org.springframework.stereotype.Service;
 
+import javax.annotation.Resource;
+
 /**
  * <p>
  *  服务实现类
@@ -16,5 +19,26 @@ import org.springframework.stereotype.Service;
  */
 @Service
 public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements TaskService {
+    @Resource
+    private TaskMapper taskMapper;
+    @Override
+    public HttpRespMsg getExecutorPanel(Integer projectId) {
+        HttpRespMsg msg = new HttpRespMsg();
+        msg.data = taskMapper.getExecutorPanel(projectId);
+        return msg;
+    }
+
+    @Override
+    public HttpRespMsg getStagesPanel(Integer projectId) {
+        HttpRespMsg msg = new HttpRespMsg();
+        msg.data = taskMapper.getStagesPanel(projectId);
+        return msg;
+    }
 
+    @Override
+    public HttpRespMsg getTopCostTask(Integer projectId) {
+        HttpRespMsg msg = new HttpRespMsg();
+        msg.data = taskMapper.getTopCostTask(projectId);
+        return msg;
+    }
 }

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

@@ -0,0 +1,20 @@
+package com.management.platform.service.impl;
+
+import com.management.platform.entity.UserRecentTask;
+import com.management.platform.mapper.UserRecentTaskMapper;
+import com.management.platform.service.UserRecentTaskService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ *  服务实现类
+ * </p>
+ *
+ * @author Seyason
+ * @since 2021-04-27
+ */
+@Service
+public class UserRecentTaskServiceImpl extends ServiceImpl<UserRecentTaskMapper, UserRecentTask> implements UserRecentTaskService {
+
+}

+ 5 - 4
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/UserServiceImpl.java

@@ -7,10 +7,7 @@ import com.management.platform.entity.*;
 import com.management.platform.entity.vo.UserVO;
 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 com.management.platform.util.*;
 import org.apache.poi.ss.usermodel.CellType;
 import org.apache.poi.xssf.usermodel.XSSFCell;
 import org.apache.poi.xssf.usermodel.XSSFRow;
@@ -297,7 +294,9 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
                     .setPassword(MD5Util.getPassword("000000"))
                     .setPhone(phone)
                     .setRole(1)
+                    .setColor(ColorUtil.randomColor())
                     .setCompanyId(company.getId());
+
             if (userMapper.insert(user) == 0) {
                 httpRespMsg.setError("操作失败");
             } else {
@@ -343,6 +342,7 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
                                     .setCompanyId(creator.getCompanyId())
                                     .setMonthCost(monthCostValue)
                                     .setCost(costValue)
+                                    .setColor(ColorUtil.randomColor())
                                     .setSalaryType(salaryType)
                                     .setDepartmentId(departmentId == null ? 0 : departmentId)
                                     .setDepartmentCascade(departmentId == null ?
@@ -477,6 +477,7 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
                         .setPassword(MD5Util.getPassword("000000"))
                         .setPhone(phone)
                         .setRole(0)
+                        .setColor(ColorUtil.randomColor())
                         .setCompanyId(companyId)
                         .setMonthCost(monthCost)
                         .setCost(cost)

+ 16 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/util/ColorUtil.java

@@ -0,0 +1,16 @@
+package com.management.platform.util;
+
+import java.util.Random;
+
+public class ColorUtil {
+    public static String[] COLORS = {"#1E90FF","#FF1493", "#FF7F50", "#2E8B57", "#778899"};
+
+    public static String randomColor() {
+        int rand = new Random().nextInt(COLORS.length);
+        return COLORS[rand];
+    }
+
+    public static void main(String[] args) {
+        System.out.println(randomColor());
+    }
+}

+ 41 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/util/DocumentTypeUtil.java

@@ -0,0 +1,41 @@
+package com.management.platform.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class DocumentTypeUtil {
+	/**
+	 * documentType文件类型
+	 * 0-图片文件,1-文本文件 ,2-压缩文件,3-txt,4-excle文件,5-压缩文件,6-视频文件,7-音频文件
+	 */
+
+	public static Integer DocumentType(String fileSuffix) {
+		if(".gif".equals(fileSuffix)) {
+			return 0;
+		}else if(".jpg".equals(fileSuffix)) {
+			return 0;
+		}else if(".png".equals(fileSuffix)) {
+			return 0;
+		}else if(".bmp".equals(fileSuffix)) {
+			return 0;
+		}else if(".doc".equals(fileSuffix) || ".docx".equals(fileSuffix)) {
+			return 1;
+		}else if(".txt".equals(fileSuffix)) {
+			return 2;
+		}else if(".xls".equals(fileSuffix) || ".xlsx".equals(fileSuffix)) {
+			return 3;
+		}else if(".zip".equals(fileSuffix) || ".rar".equals(fileSuffix)) {
+			return 4;
+		}else if(".avi".equals(fileSuffix) || ".rmvb".equals(fileSuffix)
+				|| ".3gp".equals(fileSuffix) || ".mp4".equals(fileSuffix)) {
+			return 5;
+		} else if(".mp3".equals(fileSuffix)) {
+			return 6;
+		} else if(".pdf".equals(fileSuffix)) {
+			return 7;
+		} else{
+			//其他文件
+			return -1;
+		}
+	}
+}

+ 19 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/util/FileUtil.java

@@ -10,6 +10,24 @@ import java.io.*;
  */
 public class FileUtil {
 
+    /**
+     * 获取容易识别的文件大小,比如KB, MB, GB
+     * @param size
+     * @return
+     */
+    public static String getReadableFileSize(long size) {
+        if (size < 1024) {//1K以内
+            return size + "byte";
+        } else if (size < 1024 * 1024) {//1M以内
+            return String.format("%.1fKB", (size*1.0f/1024));
+        } else if (size < 1024 * 1024 * 1024) {//1G以内
+            return String.format("%.1fMB", (size*1.0f/1024/1024));
+        } else {
+            return String.format("%.1fGB", (size*1.0f/1024/1024/1024));
+        }
+    }
+
+
     /**
      * 读取文件内容,作为字符串返回
      */
@@ -107,6 +125,7 @@ public class FileUtil {
         }
     }
 
+
     /**
      * 删除
      *

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

@@ -0,0 +1,133 @@
+package com.management.platform.util;
+
+import lombok.extern.slf4j.Slf4j;
+import org.artofsolving.jodconverter.OfficeDocumentConverter;
+import org.artofsolving.jodconverter.office.DefaultOfficeManagerConfiguration;
+import org.artofsolving.jodconverter.office.OfficeManager;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Random;
+import java.util.regex.Pattern;
+
+@Slf4j
+public class OpenOfficeService {
+	//64位windows系统默认安装路径
+	public static String OpenOffice_HOME_64 = "C://Program Files (x86)/OpenOffice 4/";
+	//32位windows系统默认安装路径
+	public static String OpenOffice_HOME_32 = "C://Program Files/OpenOffice 4/";
+	public static String OpenOffice_HOME_UNIX = "/opt/openoffice4/";
+
+	private static OfficeManager officeManager;
+
+	public static boolean canTransferToPdf(String suffix) {
+		if (".doc".equals(suffix) || ".docx".equals(suffix)
+		|| ".xls".equals(suffix) || ".xlsx".equals(suffix)
+		|| ".ppt".equals(suffix) || ".pptx".equals(suffix)
+		|| ".jpg".equals(suffix) || ".png".equals(suffix)
+		|| ".bmp".equals(suffix) || ".jpeg".equals(suffix)
+		|| ".txt".equals(suffix)) {
+			return true;
+		} else {
+			return false;
+		}
+	}
+	/**
+	 * 启动openoffice服务
+	 */
+	public void start() {
+		try {
+			log.info("===Openoffice实例启动中...");
+			DefaultOfficeManagerConfiguration config = new DefaultOfficeManagerConfiguration();
+	        String officeHome = getOfficeHome();
+			log.info("officeHome====="+officeHome);
+	        config.setOfficeHome(officeHome);
+	        int randomPort = new Random().nextInt(1000);
+	        randomPort += 8000;
+	        config.setPortNumber(randomPort);
+	        officeManager = config.buildOfficeManager();
+	        officeManager.start();
+			log.info("Openoffice实例启动成功!");
+		} catch (Exception e) {
+			e.printStackTrace();
+			log.info("OpenOffice启动失败:"+e.getMessage());
+		}
+	}
+
+	public static String getOfficeHome() {
+        String osName = System.getProperty("os.name");
+        if (Pattern.matches("Linux.*", osName)) {
+            return OpenOffice_HOME_UNIX;
+        } else if (Pattern.matches("Windows.*", osName)) {
+        	String arch = System.getProperty("os.arch");
+        	boolean is64bit = (System.getenv("ProgramFiles(x86)") != null);
+        	if (is64bit) {
+        		return OpenOffice_HOME_64;
+        	} else {
+        		return OpenOffice_HOME_32;
+        	}
+        } else if (Pattern.matches("Mac.*", osName)) {
+            return "/Application/OpenOffice.org.app/Contents";
+        }
+        return null;
+    }
+
+	/**
+	 * 文档转换
+	 * @param inputFilePath
+	 * @param destFile
+	 * @return 0-转换成,-1转换失败
+	 */
+	public  int office2PDF(String inputFilePath, String destFile) {
+		//txt后缀需要改成odt再进行转换
+		if (inputFilePath.endsWith(".txt")) {
+			String tempFilePath = inputFilePath.replaceAll(".txt", ".odt");
+			try {
+				org.apache.commons.io.FileUtils.copyFile(new File(inputFilePath), new File(tempFilePath));
+			} catch (IOException e) {
+				e.printStackTrace();
+			}
+			inputFilePath = tempFilePath;
+		}
+		OfficeDocumentConverter converter = new OfficeDocumentConverter(officeManager);
+		File outputFile = new File(destFile);
+		if (!outputFile.getParentFile().exists()) {
+			outputFile.getParentFile().mkdirs();
+		}
+        File inputFile = new File(inputFilePath);
+        if (inputFile.exists()) {// 找不到源文件, 则返回
+            converter.convert(inputFile, outputFile);
+        } else {
+        	System.out.println("转换失败,目标文件不存在");
+        	return -1;
+        }
+        System.out.println("转换成功");
+        return 0;
+	}
+
+	/**
+	 * 停止服务
+	 */
+	public void shutdown() {
+		if (officeManager != null) {
+			officeManager.stop();
+			System.out.println("Openoffice实例停止!");
+		}
+	}
+
+
+	public static void main(String[] args) {
+		OpenOfficeService service = new OpenOfficeService();
+		String sFile = "D:\\1.pdf";
+		String dFile = "D:\\wttxls111000000000000000.pdf";
+		service.start();
+		File testFile = new File(dFile);
+		if(!testFile .exists()){
+			System.out.println("测试文件不存在,开始转换......");
+			service.office2PDF(sFile,dFile);
+		}else{
+			System.out.println("测试文件已存在");
+		}
+		service.shutdown();
+	}
+}

二進制
fhKeeper/formulahousekeeper/management-platform/src/main/resources/lib/jodconverter-core-3.0.jar


+ 18 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/GroupTemplateMapper.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.management.platform.mapper.GroupTemplateMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.management.platform.entity.GroupTemplate">
+        <id column="id" property="id" />
+        <result column="name" property="name" />
+        <result column="is_system" property="isSystem" />
+        <result column="company_id" property="companyId" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, name, is_system, company_id
+    </sql>
+
+</mapper>

+ 18 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/resources/mapper/GroupTmpstagesMapper.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.management.platform.mapper.GroupTmpstagesMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.management.platform.entity.GroupTmpstages">
+        <id column="id" property="id" />
+        <result column="template_id" property="templateId" />
+        <result column="stages_name" property="stagesName" />
+        <result column="sequence" property="sequence" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, template_id, stages_name, sequence
+    </sql>
+
+</mapper>

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

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.management.platform.mapper.PdfFileMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.management.platform.entity.PdfFile">
+        <id column="id" property="id" />
+        <result column="pdf_url" property="pdfUrl" />
+        <result column="file_id" property="fileId" />
+        <result column="type" property="type" />
+        <result column="source_file_url" property="sourceFileUrl" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, pdf_url, file_id, type, source_file_url
+    </sql>
+
+</mapper>

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

@@ -15,12 +15,13 @@
         <result column="folder_id" property="folderId" />
         <result column="size" property="size" />
         <result column="document_type" property="documentType" />
-        <result column="flat" property="flat" />
+        <result column="is_deleted" property="isDeleted" />
+        <result column="is_folder" property="isFolder" />
     </resultMap>
 
     <!-- 通用查询结果列 -->
     <sql id="Base_Column_List">
-        id, document_name, server_name, url, creator_id, creator_name, indate, project_id, folder_id, size, document_type, flat
+        id, document_name, server_name, url, creator_id, creator_name, indate, project_id, folder_id, size, document_type, is_deleted, is_folder
     </sql>
 
 </mapper>

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

@@ -16,13 +16,17 @@
         <result column="status" property="status" />
         <result column="finish_date" property="finishDate" />
         <result column="budget" property="budget" />
+        <result column="creator_id" property="creatorId" />
+        <result column="creator_name" property="creatorName" />
+        <result column="create_date" property="createDate" />
     </resultMap>
 
     <!-- 通用查询结果列 -->
     <sql id="Base_Column_List">
-        id, project_name, company_id, project_code, incharger_id, plan_start_date, plan_end_date, progress, level, status, finish_date, budget
+        id, project_name, company_id, project_code, incharger_id, plan_start_date, plan_end_date, progress, level, status, finish_date, budget, creator_id, creator_name, create_date
     </sql>
 
+
     <!--获取查询者所在公司每个项目的工时成本-->
     <select id="getParticipatedProject" resultType="java.util.Map">
         SELECT id, project_name AS projectName

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

@@ -18,22 +18,24 @@
         <result column="end_time" property="endTime" />
         <result column="report_time_type" property="reportTimeType" />
         <result column="sub_project_id" property="subProjectId" />
+        <result column="task_id" property="taskId" />
     </resultMap>
 
     <!-- 通用查询结果列 -->
     <sql id="Base_Column_List">
-        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
+        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, task_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.report_time_type as reportTimeType, a.start_time as startTime,
-        a.end_time as endTime, d.name as subProjectName
+        a.end_time as endTime, d.name as subProjectName,a.task_id as taskId, task.name as taskName
         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
+        left join task on task.id = a.task_id
         WHERE a.state = 1
         <if test="date != null and date != ''">
             AND a.create_date = #{date}
@@ -47,13 +49,15 @@
         ORDER BY a.creator_id ASC
     </select>
 
-
     <!--根据员工id,日期获取当天全部报告信息-->
     <select id="getReportByDate" resultType="java.util.Map">
         SELECT a.id, b.project_name AS project, a.working_time AS time, a.content, a.state, a.time_type as timeType, a.cost, a.report_time_type as reportTimeType, a.start_time as startTime,
-        a.end_time as endTime, b.incharger_id as inchargerId
+        a.end_time as endTime, b.incharger_id as inchargerId,
+        a.creator_id as creatorId, d.name as subProjectName,a.task_id as taskId, task.name as taskName
         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
+        left join task on task.id = a.task_id
         WHERE 1=1
         <if test="date != null and date != ''">
             AND a.create_date=#{date}
@@ -67,10 +71,11 @@
         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
+        a.creator_id as creatorId, d.name as subProjectName,a.task_id as taskId, task.name as taskName
         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
+        left join task on task.id = a.task_id
         WHERE 1=1
         <if test="date != null and date != ''">
             AND a.create_date=#{date}
@@ -85,10 +90,11 @@
     <!-- 批量获取员工某天的报告 -->
     <select id="getUserReportByDate" 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.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
+        a.end_time as endTime, d.name as subProjectName,a.task_id as taskId, task.name as taskName
         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
+        left join task on task.id = a.task_id
         WHERE 1=1
         <if test="date != null and date != ''">
             AND a.create_date=#{date}

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

@@ -4,21 +4,17 @@
 
     <!-- 通用查询映射结果 -->
     <resultMap id="BaseResultMap" type="com.management.platform.entity.TaskLog">
+        <id column="id" property="id" />
         <result column="task_id" property="taskId" />
-        <result column="task_desc" property="taskDesc" />
-        <result column="executor_name" property="executorName" />
-        <result column="task_level" property="taskLevel" />
-        <result column="task_status" property="taskStatus" />
-        <result column="end_date" property="endDate" />
-        <result column="stages" property="stages" />
-        <result column="update_date" property="updateDate" />
+        <result column="mod_time" property="modTime" />
         <result column="user_id" property="userId" />
         <result column="user_name" property="userName" />
+        <result column="content" property="content" />
     </resultMap>
 
     <!-- 通用查询结果列 -->
     <sql id="Base_Column_List">
-        task_id, task_desc, executor_name, task_level, task_status, end_date, stages, update_date, user_id, user_name
+        id, task_id, mod_time, user_id, user_name, content
     </sql>
 
 </mapper>

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

@@ -9,8 +9,10 @@
         <result column="task_desc" property="taskDesc" />
         <result column="creater_id" property="createrId" />
         <result column="creater_name" property="createrName" />
+        <result column="creator_color" property="creatorColor" />
         <result column="executor_id" property="executorId" />
         <result column="executor_name" property="executorName" />
+        <result column="executor_color" property="executorColor" />
         <result column="task_level" property="taskLevel" />
         <result column="task_status" property="taskStatus" />
         <result column="create_date" property="createDate" />
@@ -23,11 +25,38 @@
         <result column="group_id" property="groupId" />
         <result column="seq" property="seq" />
         <result column="plan_hours" property="planHours" />
+        <result column="task_type" property="taskType" />
+        <result column="parent_tname" property="parentTname" />
+        <result column="finish_date" property="finishDate" />
     </resultMap>
 
     <!-- 通用查询结果列 -->
     <sql id="Base_Column_List">
-        id, name, task_desc, creater_id, creater_name, executor_id, executor_name, task_level, task_status, create_date, end_date, project_id, stages_id, company_id, indate, parent_tid, group_id, seq, plan_hours
+        id, name, task_desc, creater_id, creater_name, creator_color, executor_id, executor_name, executor_color, task_level, task_status, create_date, end_date, project_id, stages_id, company_id, indate, parent_tid, group_id, seq, plan_hours, task_type, parent_tname, finish_date
     </sql>
 
+    <!--计算执行人任务分布-->
+    <select id="getExecutorPanel" resultType="java.util.Map">
+        SELECT IFNULL(a.executor_id,0) as executorId,IFNULL( a.executor_name,'待认领') as executorName,  count(1) AS taskCount
+        FROM task a
+        WHERE a.project_id = #{projectId}
+        GROUP BY a.executor_id
+    </select>
+    <!--计算任务列表的任务分布-->
+    <select id="getStagesPanel" resultType="java.util.Map">
+        SELECT a.stages_id AS stagesId, stages.`stages_name` AS name,  COUNT(1) AS value
+        FROM task a
+        LEFT JOIN stages ON stages.id = a.`stages_id`
+        WHERE a.project_id = #{projectId}
+        GROUP BY a.stages_id
+        ORDER BY stages.`sequence`
+    </select>
+
+    <!--计算耗时排名前十的任务-->
+    <select id="getTopCostTask" resultType="java.util.Map">
+        SELECT task.id , task.name AS name, IFNULL(SUM(report.`working_time`),0) AS value FROM task
+        LEFT JOIN report ON report.`task_id` = task.id
+        WHERE task.project_id = #{projectId} and report.state = 1
+        GROUP BY task.id ORDER BY SUM(report.`working_time`) DESC LIMIT 10
+    </select>
 </mapper>

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

@@ -18,14 +18,14 @@
         <result column="month_cost" property="monthCost" />
         <result column="salary_type" property="salaryType" />
         <result column="manage_dept_id" property="manageDeptId" />
+        <result column="color" property="color" />
     </resultMap>
 
     <!-- 通用查询结果列 -->
     <sql id="Base_Column_List">
-        id, name, phone, password, portrait_url, create_time, role, company_id, department_id, department_cascade, cost, month_cost, salary_type, manage_dept_id
+        id, name, phone, password, portrait_url, create_time, role, company_id, department_id, department_cascade, cost, month_cost, salary_type, manage_dept_id, color
     </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,

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

@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.management.platform.mapper.UserRecentTaskMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.management.platform.entity.UserRecentTask">
+        <id column="id" property="id" />
+        <result column="user_id" property="userId" />
+        <result column="task_id" property="taskId" />
+        <result column="task_name" property="taskName" />
+        <result column="indate" property="indate" />
+        <result column="project_id" property="projectId" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, user_id, task_id, task_name, indate, project_id
+    </sql>
+
+</mapper>

+ 225 - 7
fhKeeper/formulahousekeeper/timesheet/package-lock.json

@@ -9,6 +9,11 @@
       "resolved": "https://registry.npm.taobao.org/@tinymce/tinymce-vue/download/@tinymce/tinymce-vue-4.0.0.tgz",
       "integrity": "sha1-aU4hTwcTcN+tGsGZBWNzBIV45u4="
     },
+    "@types/json-schema": {
+      "version": "7.0.7",
+      "resolved": "https://registry.npm.taobao.org/@types/json-schema/download/@types/json-schema-7.0.7.tgz?cache=0&sync_timestamp=1613378919536&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fjson-schema%2Fdownload%2F%40types%2Fjson-schema-7.0.7.tgz",
+      "integrity": "sha1-mKmTUWyFnrDVxMjwmDF6nqaNua0="
+    },
     "abbrev": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
@@ -897,8 +902,7 @@
     "babel-plugin-syntax-dynamic-import": {
       "version": "6.18.0",
       "resolved": "https://registry.npmjs.org/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz",
-      "integrity": "sha1-jWomIpyDdFqZgqRBBRVyyqF5sdo=",
-      "dev": true
+      "integrity": "sha1-jWomIpyDdFqZgqRBBRVyyqF5sdo="
     },
     "babel-plugin-syntax-exponentiation-operator": {
       "version": "6.13.0",
@@ -3355,8 +3359,7 @@
     "fast-json-stable-stringify": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
-      "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=",
-      "dev": true
+      "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I="
     },
     "fastparse": {
       "version": "1.1.2",
@@ -6286,6 +6289,11 @@
         "sha.js": "^2.4.8"
       }
     },
+    "pdfjs-dist": {
+      "version": "2.7.570",
+      "resolved": "https://registry.npm.taobao.org/pdfjs-dist/download/pdfjs-dist-2.7.570.tgz",
+      "integrity": "sha1-cjMkGiQ3rCI4dlYJm25UnQMvCzU="
+    },
     "performance-now": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
@@ -7028,8 +7036,7 @@
     "punycode": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
-      "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
-      "dev": true
+      "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
     },
     "q": {
       "version": "1.5.1",
@@ -7127,6 +7134,86 @@
         "unpipe": "1.0.0"
       }
     },
+    "raw-loader": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npm.taobao.org/raw-loader/download/raw-loader-4.0.2.tgz",
+      "integrity": "sha1-GqxrfRrRUB5m79rBUixz5ZpYTrY=",
+      "requires": {
+        "loader-utils": "^2.0.0",
+        "schema-utils": "^3.0.0"
+      },
+      "dependencies": {
+        "ajv": {
+          "version": "6.12.6",
+          "resolved": "https://registry.nlark.com/ajv/download/ajv-6.12.6.tgz?cache=0&sync_timestamp=1619537077405&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fajv%2Fdownload%2Fajv-6.12.6.tgz",
+          "integrity": "sha1-uvWmLoArB9l3A0WG+MO69a3ybfQ=",
+          "requires": {
+            "fast-deep-equal": "^3.1.1",
+            "fast-json-stable-stringify": "^2.0.0",
+            "json-schema-traverse": "^0.4.1",
+            "uri-js": "^4.2.2"
+          }
+        },
+        "ajv-keywords": {
+          "version": "3.5.2",
+          "resolved": "https://registry.npm.taobao.org/ajv-keywords/download/ajv-keywords-3.5.2.tgz?cache=0&sync_timestamp=1616882441894&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fajv-keywords%2Fdownload%2Fajv-keywords-3.5.2.tgz",
+          "integrity": "sha1-MfKdpatuANHC0yms97WSlhTVAU0="
+        },
+        "big.js": {
+          "version": "5.2.2",
+          "resolved": "https://registry.nlark.com/big.js/download/big.js-5.2.2.tgz",
+          "integrity": "sha1-ZfCvOC9Xi83HQr2cKB6cstd2gyg="
+        },
+        "emojis-list": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npm.taobao.org/emojis-list/download/emojis-list-3.0.0.tgz",
+          "integrity": "sha1-VXBmIEatKeLpFucariYKvf9Pang="
+        },
+        "fast-deep-equal": {
+          "version": "3.1.3",
+          "resolved": "https://registry.npm.taobao.org/fast-deep-equal/download/fast-deep-equal-3.1.3.tgz?cache=0&sync_timestamp=1591599675178&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffast-deep-equal%2Fdownload%2Ffast-deep-equal-3.1.3.tgz",
+          "integrity": "sha1-On1WtVnWy8PrUSMlJE5hmmXGxSU="
+        },
+        "json-schema-traverse": {
+          "version": "0.4.1",
+          "resolved": "https://registry.npm.taobao.org/json-schema-traverse/download/json-schema-traverse-0.4.1.tgz?cache=0&sync_timestamp=1608000211395&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjson-schema-traverse%2Fdownload%2Fjson-schema-traverse-0.4.1.tgz",
+          "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA="
+        },
+        "json5": {
+          "version": "2.2.0",
+          "resolved": "https://registry.npm.taobao.org/json5/download/json5-2.2.0.tgz",
+          "integrity": "sha1-Lf7+cgxrpSXZ69kJlQ8FFTFsiaM=",
+          "requires": {
+            "minimist": "^1.2.5"
+          }
+        },
+        "loader-utils": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npm.taobao.org/loader-utils/download/loader-utils-2.0.0.tgz",
+          "integrity": "sha1-5MrOW4FtQloWa18JfhDNErNgZLA=",
+          "requires": {
+            "big.js": "^5.2.2",
+            "emojis-list": "^3.0.0",
+            "json5": "^2.1.2"
+          }
+        },
+        "minimist": {
+          "version": "1.2.5",
+          "resolved": "https://registry.npm.taobao.org/minimist/download/minimist-1.2.5.tgz",
+          "integrity": "sha1-Z9ZgFLZqaoqqDAg8X9WN9OTpdgI="
+        },
+        "schema-utils": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npm.taobao.org/schema-utils/download/schema-utils-3.0.0.tgz",
+          "integrity": "sha1-Z1AvaqK2ai1AMrQnmilEl4oJE+8=",
+          "requires": {
+            "@types/json-schema": "^7.0.6",
+            "ajv": "^6.12.5",
+            "ajv-keywords": "^3.5.2"
+          }
+        }
+      }
+    },
     "read-pkg": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
@@ -8812,7 +8899,6 @@
       "version": "4.2.2",
       "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
       "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
-      "dev": true,
       "requires": {
         "punycode": "^2.1.0"
       }
@@ -9050,6 +9136,59 @@
         }
       }
     },
+    "vue-pdf": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npm.taobao.org/vue-pdf/download/vue-pdf-4.2.0.tgz",
+      "integrity": "sha1-1VPipGcE+azRVHnYzzLHPpCYm3c=",
+      "requires": {
+        "babel-plugin-syntax-dynamic-import": "^6.18.0",
+        "loader-utils": "^1.4.0",
+        "pdfjs-dist": "^2.5.207",
+        "raw-loader": "^4.0.1",
+        "vue-resize-sensor": "^2.0.0",
+        "worker-loader": "^2.0.0"
+      },
+      "dependencies": {
+        "big.js": {
+          "version": "5.2.2",
+          "resolved": "https://registry.nlark.com/big.js/download/big.js-5.2.2.tgz",
+          "integrity": "sha1-ZfCvOC9Xi83HQr2cKB6cstd2gyg="
+        },
+        "emojis-list": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npm.taobao.org/emojis-list/download/emojis-list-3.0.0.tgz",
+          "integrity": "sha1-VXBmIEatKeLpFucariYKvf9Pang="
+        },
+        "json5": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npm.taobao.org/json5/download/json5-1.0.1.tgz",
+          "integrity": "sha1-d5+wAYYE+oVOrL9iUhgNg1Q+Pb4=",
+          "requires": {
+            "minimist": "^1.2.0"
+          }
+        },
+        "loader-utils": {
+          "version": "1.4.0",
+          "resolved": "https://registry.npm.taobao.org/loader-utils/download/loader-utils-1.4.0.tgz",
+          "integrity": "sha1-xXm140yzSxp07cbB+za/o3HVphM=",
+          "requires": {
+            "big.js": "^5.2.2",
+            "emojis-list": "^3.0.0",
+            "json5": "^1.0.1"
+          }
+        },
+        "minimist": {
+          "version": "1.2.5",
+          "resolved": "https://registry.npm.taobao.org/minimist/download/minimist-1.2.5.tgz",
+          "integrity": "sha1-Z9ZgFLZqaoqqDAg8X9WN9OTpdgI="
+        }
+      }
+    },
+    "vue-resize-sensor": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npm.taobao.org/vue-resize-sensor/download/vue-resize-sensor-2.0.0.tgz",
+      "integrity": "sha1-Olh/1oAuFohwnPLFqtrnoAdZUr8="
+    },
     "vue-router": {
       "version": "2.8.1",
       "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-2.8.1.tgz",
@@ -9462,6 +9601,85 @@
       "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=",
       "dev": true
     },
+    "worker-loader": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npm.taobao.org/worker-loader/download/worker-loader-2.0.0.tgz",
+      "integrity": "sha1-Rf2j73asqBV3GokQc5nuQRm0MKw=",
+      "requires": {
+        "loader-utils": "^1.0.0",
+        "schema-utils": "^0.4.0"
+      },
+      "dependencies": {
+        "ajv": {
+          "version": "6.12.6",
+          "resolved": "https://registry.nlark.com/ajv/download/ajv-6.12.6.tgz?cache=0&sync_timestamp=1619537077405&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fajv%2Fdownload%2Fajv-6.12.6.tgz",
+          "integrity": "sha1-uvWmLoArB9l3A0WG+MO69a3ybfQ=",
+          "requires": {
+            "fast-deep-equal": "^3.1.1",
+            "fast-json-stable-stringify": "^2.0.0",
+            "json-schema-traverse": "^0.4.1",
+            "uri-js": "^4.2.2"
+          }
+        },
+        "ajv-keywords": {
+          "version": "3.5.2",
+          "resolved": "https://registry.npm.taobao.org/ajv-keywords/download/ajv-keywords-3.5.2.tgz?cache=0&sync_timestamp=1616882441894&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fajv-keywords%2Fdownload%2Fajv-keywords-3.5.2.tgz",
+          "integrity": "sha1-MfKdpatuANHC0yms97WSlhTVAU0="
+        },
+        "big.js": {
+          "version": "5.2.2",
+          "resolved": "https://registry.nlark.com/big.js/download/big.js-5.2.2.tgz",
+          "integrity": "sha1-ZfCvOC9Xi83HQr2cKB6cstd2gyg="
+        },
+        "emojis-list": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npm.taobao.org/emojis-list/download/emojis-list-3.0.0.tgz",
+          "integrity": "sha1-VXBmIEatKeLpFucariYKvf9Pang="
+        },
+        "fast-deep-equal": {
+          "version": "3.1.3",
+          "resolved": "https://registry.npm.taobao.org/fast-deep-equal/download/fast-deep-equal-3.1.3.tgz?cache=0&sync_timestamp=1591599675178&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffast-deep-equal%2Fdownload%2Ffast-deep-equal-3.1.3.tgz",
+          "integrity": "sha1-On1WtVnWy8PrUSMlJE5hmmXGxSU="
+        },
+        "json-schema-traverse": {
+          "version": "0.4.1",
+          "resolved": "https://registry.npm.taobao.org/json-schema-traverse/download/json-schema-traverse-0.4.1.tgz?cache=0&sync_timestamp=1608000211395&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fjson-schema-traverse%2Fdownload%2Fjson-schema-traverse-0.4.1.tgz",
+          "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA="
+        },
+        "json5": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npm.taobao.org/json5/download/json5-1.0.1.tgz",
+          "integrity": "sha1-d5+wAYYE+oVOrL9iUhgNg1Q+Pb4=",
+          "requires": {
+            "minimist": "^1.2.0"
+          }
+        },
+        "loader-utils": {
+          "version": "1.4.0",
+          "resolved": "https://registry.npm.taobao.org/loader-utils/download/loader-utils-1.4.0.tgz",
+          "integrity": "sha1-xXm140yzSxp07cbB+za/o3HVphM=",
+          "requires": {
+            "big.js": "^5.2.2",
+            "emojis-list": "^3.0.0",
+            "json5": "^1.0.1"
+          }
+        },
+        "minimist": {
+          "version": "1.2.5",
+          "resolved": "https://registry.npm.taobao.org/minimist/download/minimist-1.2.5.tgz",
+          "integrity": "sha1-Z9ZgFLZqaoqqDAg8X9WN9OTpdgI="
+        },
+        "schema-utils": {
+          "version": "0.4.7",
+          "resolved": "https://registry.npm.taobao.org/schema-utils/download/schema-utils-0.4.7.tgz",
+          "integrity": "sha1-unT1l9K+LqiAExdG7hfQoJPGgYc=",
+          "requires": {
+            "ajv": "^6.1.0",
+            "ajv-keywords": "^3.1.0"
+          }
+        }
+      }
+    },
     "wrap-ansi": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",

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

@@ -20,6 +20,7 @@
     "tinymce": "^5.7.1",
     "vue": "^2.6.10",
     "vue-clipboard2": "^0.3.0",
+    "vue-pdf": "^4.2.0",
     "vue-router": "^2.3.0",
     "vuedraggable": "^2.24.3",
     "vuex": "^2.0.0-rc.6"

+ 561 - 14
fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/demo_index.html

@@ -2,8 +2,9 @@
 <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"/>
+  <title>iconfont Demo</title>
+  <link rel="shortcut icon" href="//img.alicdn.com/imgextra/i2/O1CN01ZyAlrn1MwaMhqz36G_!!6000000001499-73-tps-64-64.ico" type="image/x-icon"/>
+  <link rel="icon" type="image/svg+xml" href="//img.alicdn.com/imgextra/i4/O1CN01EYTRnJ297D6vehehJ_!!6000000008020-55-tps-64-64.svg"/>
   <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">
@@ -12,10 +13,33 @@
   <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>
+  <style>
+    .main .logo {
+      margin-top: 0;
+      height: auto;
+    }
+
+    .main .logo a {
+      display: flex;
+      align-items: center;
+    }
+
+    .main .logo .sub-title {
+      margin-left: 0.5em;
+      font-size: 22px;
+      color: #fff;
+      background: linear-gradient(-45deg, #3967FF, #B500FE);
+      -webkit-background-clip: text;
+      -webkit-text-fill-color: transparent;
+    }
+  </style>
 </head>
 <body>
   <div class="main">
-    <h1 class="logo"><a href="https://www.iconfont.cn/" title="iconfont 首页" target="_blank">&#xe86b;</a></h1>
+    <h1 class="logo"><a href="https://www.iconfont.cn/" title="iconfont 首页" target="_blank">
+      <img width="200" src="https://img.alicdn.com/imgextra/i3/O1CN01Mn65HV1FfSEzR6DKv_!!6000000000514-55-tps-228-59.svg">
+      
+    </a></h1>
     <div class="nav-tabs">
       <ul id="tabs" class="dib-box">
         <li class="dib active"><span>Unicode</span></li>
@@ -30,6 +54,144 @@
       <div class="content unicode" style="display: block;">
           <ul class="icon_lists dib-box">
           
+            <li class="dib">
+              <span class="icon iconfont">&#xe63c;</span>
+                <div class="name">启动</div>
+                <div class="code-name">&amp;#xe63c;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe610;</span>
+                <div class="name">完 成 </div>
+                <div class="code-name">&amp;#xe610;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe6b7;</span>
+                <div class="name">菜单</div>
+                <div class="code-name">&amp;#xe6b7;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe604;</span>
+                <div class="name">审核</div>
+                <div class="code-name">&amp;#xe604;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe6ad;</span>
+                <div class="name">里程碑</div>
+                <div class="code-name">&amp;#xe6ad;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe64c;</span>
+                <div class="name">任务</div>
+                <div class="code-name">&amp;#xe64c;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe6a2;</span>
+                <div class="name">风险</div>
+                <div class="code-name">&amp;#xe6a2;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe70f;</span>
+                <div class="name">ok</div>
+                <div class="code-name">&amp;#xe70f;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe603;</span>
+                <div class="name">棱形</div>
+                <div class="code-name">&amp;#xe603;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe60c;</span>
+                <div class="name">file</div>
+                <div class="code-name">&amp;#xe60c;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe65c;</span>
+                <div class="name">excel</div>
+                <div class="code-name">&amp;#xe65c;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe9ec;</span>
+                <div class="name">Zip</div>
+                <div class="code-name">&amp;#xe9ec;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe6ed;</span>
+                <div class="name">JPG</div>
+                <div class="code-name">&amp;#xe6ed;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe602;</span>
+                <div class="name">audio</div>
+                <div class="code-name">&amp;#xe602;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe741;</span>
+                <div class="name">txt</div>
+                <div class="code-name">&amp;#xe741;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe771;</span>
+                <div class="name">video</div>
+                <div class="code-name">&amp;#xe771;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe61a;</span>
+                <div class="name">PDF</div>
+                <div class="code-name">&amp;#xe61a;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xeecf;</span>
+                <div class="name">word</div>
+                <div class="code-name">&amp;#xeecf;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe6fd;</span>
+                <div class="name">上 传</div>
+                <div class="code-name">&amp;#xe6fd;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xecfa;</span>
+                <div class="name">秒表</div>
+                <div class="code-name">&amp;#xecfa;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe600;</span>
+                <div class="name">task</div>
+                <div class="code-name">&amp;#xe600;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe601;</span>
+                <div class="name">time</div>
+                <div class="code-name">&amp;#xe601;</div>
+              </li>
+          
+            <li class="dib">
+              <span class="icon iconfont">&#xe691;</span>
+                <div class="name">tree</div>
+                <div class="code-name">&amp;#xe691;</div>
+              </li>
+          
             <li class="dib">
               <span class="icon iconfont">&#xe631;</span>
                 <div class="name">统计</div>
@@ -61,24 +223,20 @@
 
           <p>Unicode 是字体在网页端最原始的应用方式,特点是:</p>
           <ul>
-            <li>兼容性最好,支持 IE6+,及所有现代浏览器。</li>
             <li>支持按字体的方式去动态调整图标大小,颜色等等。</li>
-            <li>但是因为是字体,所以不支持多色。只能使用平台里单色的图标,就算项目里有多色图标也会自动去色。</li>
+            <li>默认情况下不支持多色,直接添加多色图标会自动去色。</li>
           </ul>
           <blockquote>
-            <p>注意:新版 iconfont 支持多色图标,这些多色图标在 Unicode 模式下将不能使用,如果有需求建议使用symbol 的引用方式</p>
+            <p>注意:新版 iconfont 支持两种方式引用多色图标:SVG 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');
+  src: url('iconfont.woff2?t=1620099021268') format('woff2'),
+       url('iconfont.woff?t=1620099021268') format('woff'),
+       url('iconfont.ttf?t=1620099021268') format('truetype');
 }
 </code></pre>
           <h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
@@ -104,6 +262,213 @@
       <div class="content font-class">
         <ul class="icon_lists dib-box">
           
+          <li class="dib">
+            <span class="icon iconfont firerock-iconqidong"></span>
+            <div class="name">
+              启动
+            </div>
+            <div class="code-name">.firerock-iconqidong
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont firerock-iconwancheng"></span>
+            <div class="name">
+              完 成 
+            </div>
+            <div class="code-name">.firerock-iconwancheng
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont firerock-iconcaidan"></span>
+            <div class="name">
+              菜单
+            </div>
+            <div class="code-name">.firerock-iconcaidan
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont firerock-iconshenhe"></span>
+            <div class="name">
+              审核
+            </div>
+            <div class="code-name">.firerock-iconshenhe
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont firerock-iconicon-"></span>
+            <div class="name">
+              里程碑
+            </div>
+            <div class="code-name">.firerock-iconicon-
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont firerock-iconrenwu"></span>
+            <div class="name">
+              任务
+            </div>
+            <div class="code-name">.firerock-iconrenwu
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont firerock-iconfengxian"></span>
+            <div class="name">
+              风险
+            </div>
+            <div class="code-name">.firerock-iconfengxian
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont firerock-iconnormal-ico-ok"></span>
+            <div class="name">
+              ok
+            </div>
+            <div class="code-name">.firerock-iconnormal-ico-ok
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont firerock-iconicon2"></span>
+            <div class="name">
+              棱形
+            </div>
+            <div class="code-name">.firerock-iconicon2
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont firerock-iconfile"></span>
+            <div class="name">
+              file
+            </div>
+            <div class="code-name">.firerock-iconfile
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont firerock-iconex"></span>
+            <div class="name">
+              excel
+            </div>
+            <div class="code-name">.firerock-iconex
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont firerock-iconZip"></span>
+            <div class="name">
+              Zip
+            </div>
+            <div class="code-name">.firerock-iconZip
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont firerock-iconJPG"></span>
+            <div class="name">
+              JPG
+            </div>
+            <div class="code-name">.firerock-iconJPG
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont firerock-iconaudio"></span>
+            <div class="name">
+              audio
+            </div>
+            <div class="code-name">.firerock-iconaudio
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont firerock-icontxt"></span>
+            <div class="name">
+              txt
+            </div>
+            <div class="code-name">.firerock-icontxt
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont firerock-iconvideo"></span>
+            <div class="name">
+              video
+            </div>
+            <div class="code-name">.firerock-iconvideo
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont firerock-iconPDF"></span>
+            <div class="name">
+              PDF
+            </div>
+            <div class="code-name">.firerock-iconPDF
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont firerock-iconword"></span>
+            <div class="name">
+              word
+            </div>
+            <div class="code-name">.firerock-iconword
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont firerock-iconshangchuan"></span>
+            <div class="name">
+              上 传
+            </div>
+            <div class="code-name">.firerock-iconshangchuan
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont firerock-iconmiaobiao"></span>
+            <div class="name">
+              秒表
+            </div>
+            <div class="code-name">.firerock-iconmiaobiao
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont firerock-icontask"></span>
+            <div class="name">
+              task
+            </div>
+            <div class="code-name">.firerock-icontask
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont firerock-iconmeditor-time"></span>
+            <div class="name">
+              time
+            </div>
+            <div class="code-name">.firerock-iconmeditor-time
+            </div>
+          </li>
+          
+          <li class="dib">
+            <span class="icon iconfont firerock-icontree"></span>
+            <div class="name">
+              tree
+            </div>
+            <div class="code-name">.firerock-icontree
+            </div>
+          </li>
+          
           <li class="dib">
             <span class="icon iconfont firerock-icontongji"></span>
             <div class="name">
@@ -148,10 +513,8 @@
         <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>
@@ -169,6 +532,190 @@
       <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-iconqidong"></use>
+                </svg>
+                <div class="name">启动</div>
+                <div class="code-name">#firerock-iconqidong</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#firerock-iconwancheng"></use>
+                </svg>
+                <div class="name">完 成 </div>
+                <div class="code-name">#firerock-iconwancheng</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#firerock-iconcaidan"></use>
+                </svg>
+                <div class="name">菜单</div>
+                <div class="code-name">#firerock-iconcaidan</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#firerock-iconshenhe"></use>
+                </svg>
+                <div class="name">审核</div>
+                <div class="code-name">#firerock-iconshenhe</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#firerock-iconicon-"></use>
+                </svg>
+                <div class="name">里程碑</div>
+                <div class="code-name">#firerock-iconicon-</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#firerock-iconrenwu"></use>
+                </svg>
+                <div class="name">任务</div>
+                <div class="code-name">#firerock-iconrenwu</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#firerock-iconfengxian"></use>
+                </svg>
+                <div class="name">风险</div>
+                <div class="code-name">#firerock-iconfengxian</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#firerock-iconnormal-ico-ok"></use>
+                </svg>
+                <div class="name">ok</div>
+                <div class="code-name">#firerock-iconnormal-ico-ok</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#firerock-iconicon2"></use>
+                </svg>
+                <div class="name">棱形</div>
+                <div class="code-name">#firerock-iconicon2</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#firerock-iconfile"></use>
+                </svg>
+                <div class="name">file</div>
+                <div class="code-name">#firerock-iconfile</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#firerock-iconex"></use>
+                </svg>
+                <div class="name">excel</div>
+                <div class="code-name">#firerock-iconex</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#firerock-iconZip"></use>
+                </svg>
+                <div class="name">Zip</div>
+                <div class="code-name">#firerock-iconZip</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#firerock-iconJPG"></use>
+                </svg>
+                <div class="name">JPG</div>
+                <div class="code-name">#firerock-iconJPG</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#firerock-iconaudio"></use>
+                </svg>
+                <div class="name">audio</div>
+                <div class="code-name">#firerock-iconaudio</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#firerock-icontxt"></use>
+                </svg>
+                <div class="name">txt</div>
+                <div class="code-name">#firerock-icontxt</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#firerock-iconvideo"></use>
+                </svg>
+                <div class="name">video</div>
+                <div class="code-name">#firerock-iconvideo</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#firerock-iconPDF"></use>
+                </svg>
+                <div class="name">PDF</div>
+                <div class="code-name">#firerock-iconPDF</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#firerock-iconword"></use>
+                </svg>
+                <div class="name">word</div>
+                <div class="code-name">#firerock-iconword</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#firerock-iconshangchuan"></use>
+                </svg>
+                <div class="name">上 传</div>
+                <div class="code-name">#firerock-iconshangchuan</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#firerock-iconmiaobiao"></use>
+                </svg>
+                <div class="name">秒表</div>
+                <div class="code-name">#firerock-iconmiaobiao</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#firerock-icontask"></use>
+                </svg>
+                <div class="name">task</div>
+                <div class="code-name">#firerock-icontask</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#firerock-iconmeditor-time"></use>
+                </svg>
+                <div class="name">time</div>
+                <div class="code-name">#firerock-iconmeditor-time</div>
+            </li>
+          
+            <li class="dib">
+                <svg class="icon svg-icon" aria-hidden="true">
+                  <use xlink:href="#firerock-icontree"></use>
+                </svg>
+                <div class="name">tree</div>
+                <div class="code-name">#firerock-icontree</div>
+            </li>
+          
             <li class="dib">
                 <svg class="icon svg-icon" aria-hidden="true">
                   <use xlink:href="#firerock-icontongji"></use>

文件差異過大導致無法顯示
+ 97 - 7
fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.css


二進制
fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.eot


文件差異過大導致無法顯示
+ 1 - 1
fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.js


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

@@ -5,6 +5,167 @@
   "css_prefix_text": "firerock-icon",
   "description": "",
   "glyphs": [
+    {
+      "icon_id": "8796451",
+      "name": "启动",
+      "font_class": "qidong",
+      "unicode": "e63c",
+      "unicode_decimal": 58940
+    },
+    {
+      "icon_id": "19037188",
+      "name": "完 成 ",
+      "font_class": "wancheng",
+      "unicode": "e610",
+      "unicode_decimal": 58896
+    },
+    {
+      "icon_id": "20134686",
+      "name": "菜单",
+      "font_class": "caidan",
+      "unicode": "e6b7",
+      "unicode_decimal": 59063
+    },
+    {
+      "icon_id": "8524192",
+      "name": "审核",
+      "font_class": "shenhe",
+      "unicode": "e604",
+      "unicode_decimal": 58884
+    },
+    {
+      "icon_id": "3590688",
+      "name": "里程碑",
+      "font_class": "icon-",
+      "unicode": "e6ad",
+      "unicode_decimal": 59053
+    },
+    {
+      "icon_id": "5112963",
+      "name": "任务",
+      "font_class": "renwu",
+      "unicode": "e64c",
+      "unicode_decimal": 58956
+    },
+    {
+      "icon_id": "10368440",
+      "name": "风险",
+      "font_class": "fengxian",
+      "unicode": "e6a2",
+      "unicode_decimal": 59042
+    },
+    {
+      "icon_id": "17156568",
+      "name": "ok",
+      "font_class": "normal-ico-ok",
+      "unicode": "e70f",
+      "unicode_decimal": 59151
+    },
+    {
+      "icon_id": "1161198",
+      "name": "棱形",
+      "font_class": "icon2",
+      "unicode": "e603",
+      "unicode_decimal": 58883
+    },
+    {
+      "icon_id": "10202911",
+      "name": "file",
+      "font_class": "file",
+      "unicode": "e60c",
+      "unicode_decimal": 58892
+    },
+    {
+      "icon_id": "2078615",
+      "name": "excel",
+      "font_class": "ex",
+      "unicode": "e65c",
+      "unicode_decimal": 58972
+    },
+    {
+      "icon_id": "4073514",
+      "name": "Zip",
+      "font_class": "Zip",
+      "unicode": "e9ec",
+      "unicode_decimal": 59884
+    },
+    {
+      "icon_id": "4863362",
+      "name": "JPG",
+      "font_class": "JPG",
+      "unicode": "e6ed",
+      "unicode_decimal": 59117
+    },
+    {
+      "icon_id": "5173010",
+      "name": "audio",
+      "font_class": "audio",
+      "unicode": "e602",
+      "unicode_decimal": 58882
+    },
+    {
+      "icon_id": "8469709",
+      "name": "txt",
+      "font_class": "txt",
+      "unicode": "e741",
+      "unicode_decimal": 59201
+    },
+    {
+      "icon_id": "19705514",
+      "name": "video",
+      "font_class": "video",
+      "unicode": "e771",
+      "unicode_decimal": 59249
+    },
+    {
+      "icon_id": "20213818",
+      "name": "PDF",
+      "font_class": "PDF",
+      "unicode": "e61a",
+      "unicode_decimal": 58906
+    },
+    {
+      "icon_id": "20651005",
+      "name": "word",
+      "font_class": "word",
+      "unicode": "eecf",
+      "unicode_decimal": 61135
+    },
+    {
+      "icon_id": "17781647",
+      "name": "上 传",
+      "font_class": "shangchuan",
+      "unicode": "e6fd",
+      "unicode_decimal": 59133
+    },
+    {
+      "icon_id": "7337849",
+      "name": "秒表",
+      "font_class": "miaobiao",
+      "unicode": "ecfa",
+      "unicode_decimal": 60666
+    },
+    {
+      "icon_id": "8659928",
+      "name": "task",
+      "font_class": "task",
+      "unicode": "e600",
+      "unicode_decimal": 58880
+    },
+    {
+      "icon_id": "13530978",
+      "name": "time",
+      "font_class": "meditor-time",
+      "unicode": "e601",
+      "unicode_decimal": 58881
+    },
+    {
+      "icon_id": "9339879",
+      "name": "tree",
+      "font_class": "tree",
+      "unicode": "e691",
+      "unicode_decimal": 59025
+    },
     {
       "icon_id": "807967",
       "name": "统计",

文件差異過大導致無法顯示
+ 42 - 0
fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.svg


二進制
fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.ttf


二進制
fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.woff


二進制
fhKeeper/formulahousekeeper/timesheet/src/assets/myfont/iconfont.woff2


+ 29 - 1
fhKeeper/formulahousekeeper/timesheet/src/common/js/util.js

@@ -5,7 +5,35 @@ function padding(s, len) {
     for (var i = 0; i < len; i++) { s = '0' + s; }
     return s;
 };
-
+/**
+ * @description 格式化金额
+ * @param number:要格式化的数字
+ * @param decimals:保留几位小数 默认0位
+ * @param decPoint:小数点符号 默认.
+ * @param thousandsSep:千分位符号 默认为,
+ */
+ export const formatMoney = (number, decimals = 0, decPoint = '.', thousandsSep = ',') => {
+    number = (number + '').replace(/[^0-9+-Ee.]/g, '')
+    let n = !isFinite(+number) ? 0 : +number
+    let prec = !isFinite(+decimals) ? 0 : Math.abs(decimals)
+    let sep = (typeof thousandsSep === 'undefined') ? ',' : thousandsSep
+    let dec = (typeof decPoint === 'undefined') ? '.' : decPoint
+    let s = ''
+    let toFixedFix = function (n, prec) {
+      let k = Math.pow(10, prec)
+      return '' + Math.ceil(n * k) / k
+    }
+    s = (prec ? toFixedFix(n, prec) : '' + Math.round(n)).split('.')
+    let re = /(-?\d+)(\d{3})/
+    while (re.test(s[0])) {
+      s[0] = s[0].replace(re, '$1' + sep + '$2')
+    }
+    if ((s[1] || '').length < prec) {
+      s[1] = s[1] || ''
+      s[1] += new Array(prec - s[1].length + 1).join('0')
+    }
+    return s.join(dec)
+  }
 export default {
     getQueryStringByName: function (name) {
         var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");

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

@@ -24,8 +24,9 @@ Vue.prototype.echarts = echarts
 
 import VueClipboard from 'vue-clipboard2'
 Vue.use(VueClipboard)
-
-
+// collapse 展开折叠
+import CollapseTransition from 'element-ui/lib/transitions/collapse-transition';
+Vue.component(CollapseTransition.name, CollapseTransition)
 
 import 'font-awesome/css/font-awesome.min.css'
 import './assets/iconfont/iconfont.css'
@@ -34,7 +35,7 @@ import './assets/myfont/iconfont.css'
 // const router = new VueRouter({
 //     routes
 // })
-import { staffRouter, manageRouter, fixedRouter,leaderRouter } from './routes'
+import { staffRouter, manageRouter, fixedRouter,leaderRouter, projectManageRouter } from './routes'
 import router from './routes'
 
 import NProgress from 'nprogress'
@@ -66,6 +67,9 @@ router.beforeEach((to, from, next) => {
                 addRouFlag = true
                 if(user.role == 0) {
                     var getRoutes = baseRoleGetRouters(user.leader?leaderRouter:staffRouter, user);
+                    if (user.company.packageProject == 1 && !user.leader) {
+                        getRoutes = getRoutes.concat(projectManageRouter);
+                    }
                     global.antRouter = fixedRouter.concat(getRoutes);
                     router.addRoutes(fixedRouter.concat(getRoutes));
                     router.options.routes = fixedRouter.concat(getRoutes);

+ 46 - 19
fhKeeper/formulahousekeeper/timesheet/src/routes.js

@@ -24,6 +24,7 @@ import proDetail from './views/project/detail.vue'
 import depDetail from './views/project/detailDep.vue'
 import task from './views/task/list.vue'
 import projectInside from  './views/project/projectInside.vue'
+import info from './views/project/info.vue'
 
 // 团队管理
 import team from './views/team/index.vue'
@@ -33,6 +34,7 @@ import timetype from './views/settings/timetype.vue';
 
 import finance from './views/project/finance';
 import Market from './views/market/list';
+import PdfView from './views/pdf/pdfview';
 Vue.use(Router)
 
 export const fixedRouter = [
@@ -53,9 +55,44 @@ export const fixedRouter = [
         component: Market,
         name: '',
         hidden: true
+    },
+    //tab页签切换
+    {
+        path: '/',
+        component: Home,
+        name: '项目管理',
+        iconCls: 'fa fa-sticky-note',
+        hidden:true,
+        leaf: true,
+        children: [
+            { path: '/projectInside/:id', component: projectInside, name: '任务看板' },
+            { path: '/files/:id', component: projectInside, name: '任务看板' },
+            { path: '/info/:id', component: projectInside, name: '项目概览' },
+            { path: '/summary/:id', component: projectInside, name: '数据统计' },
+        ]
+    },
+    {
+        path: '/viewonline',
+        component: PdfView,
+        name: '',
+        hidden: true
+    },
+    
+];
+export const projectManageRouter = [
+    //项目管理
+    {
+        path: '/',
+        component: Home,
+        name: '项目管理',
+        iconCls: 'iconfont firerock-iconxiangmu',
+        leaf: true,
+        children: [
+            { path: '/list', component: list, name: '项目管理' },
+            { path: '/projectInside/:id', component: projectInside, name: '项目查看' },
+        ]
     }
-]
-
+];
 export const manageRouter = [
     
     //工时报告
@@ -73,7 +110,7 @@ export const manageRouter = [
         path: '/',
         component: Home,
         name: '自动计时',
-        iconCls: 'fa fa-sticky-note',
+        iconCls: 'iconfont firerock-iconmiaobiao',
         leaf: true,
         children: [
             { path: '/timer', component: timer, name: '自动计时' },
@@ -84,7 +121,7 @@ export const manageRouter = [
         path: '/',
         component: Home,
         name: '报告审核',
-        iconCls: 'fa fa-check-square-o',
+        iconCls: 'iconfont firerock-iconshenhe',
         leaf: true,
         children: [
             { path: '/review', component: review, name: '报告审核' },
@@ -114,18 +151,7 @@ export const manageRouter = [
             { path: '/finance', component: finance, name: '财务核算成本' },
         ]
     },
-    //任务列表
-    {
-        path: '/',
-        component: Home,
-        name: '任务列表',
-        iconCls: 'iconfont firerock-iconxiangmu',
-        leaf: false,
-        group:'packageProject',
-        children: [
-            { path: '/task', component: task, name: '任务列表' },
-        ]
-    },
+    
 
     //项目管理
     {
@@ -204,12 +230,13 @@ export const staffRouter = [
         path: '/',
         component: Home,
         name: '自动计时',
-        iconCls: 'fa fa-sticky-note',
+        iconCls: 'iconfont firerock-iconmiaobiao',
         leaf: true,
         children: [
             { path: '/timer', component: timer, name: '自动计时' },
         ]
     },
+    
     {
         path: '/404',
         component: NotFound,
@@ -239,7 +266,7 @@ export const leaderRouter = [
         path: '/',
         component: Home,
         name: '自动计时',
-        iconCls: 'fa fa-sticky-note',
+        iconCls: 'iconfont firerock-iconmiaobiao',
         leaf: true,
         children: [
             { path: '/timer', component: timer, name: '自动计时' },
@@ -250,7 +277,7 @@ export const leaderRouter = [
         path: '/',
         component: Home,
         name: '报告审核',
-        iconCls: 'fa fa-check-square-o',
+        iconCls: 'iconfont firerock-iconshenhe',
         leaf: true,
         children: [
             { path: '/review', component: review, name: '报告审核' },

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

@@ -163,7 +163,6 @@
             return {
                 helpImg: '../assets/image/userHead.png',
                 user: sessionStorage.getItem("user"),
-
                 sysName: "工时管家",
                 collapsed: sessionStorage.collapsed!=null?(sessionStorage.collapsed=='true'?true:false):false,
                 sysUserName: "",
@@ -548,7 +547,6 @@
             .content-container {
                 flex: 1;
                 width: 80%;
-                padding: 10px;
                 overflow-y: auto;
                 .breadcrumb-container {
                     .title {

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

@@ -1,6 +1,6 @@
 <template>
     <section>
-        <el-col :span="24" style="padding-bottom: 0px;text-align:center;">
+        <el-col :span="24" style="padding-bottom: 0px;text-align:center;margin-top:10px;">
             <!-- <el-date-picker
                 v-model="dateRange"
                 type="monthrange"

+ 7 - 6
fhKeeper/formulahousekeeper/timesheet/src/views/project/finance.vue

@@ -341,17 +341,18 @@
 
         },
         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() {
+            let height = window.innerHeight;
+            this.tableHeight = height - 245;
+            const that = this;
+            window.onresize = function temp() {
+                that.tableHeight = window.innerHeight - 245;
+            };
             this.getList();
         },
         updated() {

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

@@ -19,7 +19,7 @@
                 </el-form-item>
 
                 <el-form-item v-if="user.company.packageProject==1">
-                    <span style="margin-left:10px;margin-right:10px;">状态</span>
+                    <span style="margin-left:10px;margin-right:10px;color:#606266;">状态</span>
                     <el-select v-model="status" style="width:120px;"  placeholder="请选择" @change="searchList">
                             <el-option label="全部" value=0 ></el-option>
                             <el-option label="进行中" value=1 ></el-option>
@@ -43,7 +43,8 @@
             <el-table-column prop="projectCode" label="项目编码" sortable width="150"></el-table-column>
             <el-table-column prop="projectName" label="项目名称" sortable>
                  <template slot-scope="scope">
-                    <el-link type="primary" :href="'#/projectInside/'+scope.row.id">{{scope.row.projectName}}</el-link>
+                    <el-link type="primary" v-if="user.company.packageProject==1" :href="'#/projectInside/'+scope.row.id">{{scope.row.projectName}}</el-link>
+                    <span v-if="user.company.packageProject==0" >{{scope.row.projectName}}</span>
                 </template>
             </el-table-column>
             <el-table-column prop="inchargerName" label="负责人" sortable width="150">
@@ -71,9 +72,9 @@
             </el-table-column>
             <el-table-column label="操作" width="290">
                 <template slot-scope="scope">
-                    <el-button v-if="user.role>0" 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 v-if="user.role>0" size="small" type="danger" @click="deletePro(scope.$index, scope.row)">删除</el-button>
+                    <el-button v-if="user.role>0" size="mini"  @click="subProject(scope.row)">子项目</el-button>
+                    <el-button size="mini" v-if="user.role>0 || user.id==scope.row.inchargerId" type="primary" @click="handleAdd(scope.$index, scope.row)">编辑</el-button>
+                    <el-button v-if="user.role>0" size="mini"  @click="deletePro(scope.$index, scope.row)">删除</el-button>
                 </template>
             </el-table-column>
         </el-table>
@@ -106,29 +107,29 @@
                     </el-select>
                 </el-form-item>
                 <el-form-item label="主要负责人" >
-                    <el-select v-model="addForm.inchargerId" :disabled="addForm.userId.length==0 ||  user.role==0" filterable placeholder="请选择负责人" style="width:100%;" @change="changeIncharger">
+                    <el-select v-model="addForm.inchargerId" :disabled="addForm.userId.length==0 ||  user.role==0" filterable placeholder="请选择负责人" style="width:100%;" >
                         <el-option v-for="item in participator" :key="item.id" :label="item.name" :value="item.id"></el-option>
                     </el-select>
                 </el-form-item>
                 <!--专业项目协作版本功能 -->
-                <el-form-item label="级别" >
-                    <el-select v-model="addForm.level" v-if="user.company.packageProject==1" placeholder="请选择负责人" style="width:32%;" >
+                <el-form-item label="级别" v-if="user.company.packageProject==1">
+                    <el-select v-model="addForm.level"  placeholder="请选择级别" style="width:32%;" >
                         <el-option v-for="item in importanceList" :key="item.id" :label="item.label" :value="item.id"></el-option>
                     </el-select>
-                    <span style="margin-left:50px;margin-right:10px;">项目预算</span>
-                    <el-input v-model="addForm.budget"  v-if="user.company.packageProject==1"  style="width:32%;"
+                    <span style="margin-left:50px;margin-right:10px;" v-if="user.company.packageProject==1">项目预算</span>
+                    <el-input v-model="addForm.budget"    style="width:32%;"
                     placeholder="整数" clearable @keyup.native="number"></el-input><span style="margin-left:10px;">元</span>
                 </el-form-item>
-                <el-form-item label="开始日期" prop="planStartDate">
-                    <el-date-picker v-model="addForm.planStartDate" v-if="user.company.packageProject==1" 
+                <el-form-item label="开始日期" prop="planStartDate" v-if="user.company.packageProject==1" >
+                    <el-date-picker v-model="addForm.planStartDate" 
                      :editable="false" 
                      format="yyyy-MM-dd" 
                      value-format="yyyy-MM-dd"
                      :clearable="false" type="date" 
                      placeholder="选择日期"></el-date-picker>
                 </el-form-item>
-                <el-form-item label="截止日期" prop="planEndDate">
-                    <el-date-picker v-model="addForm.planEndDate" v-if="user.company.packageProject==1" 
+                <el-form-item label="截止日期" prop="planEndDate" v-if="user.company.packageProject==1" >
+                    <el-date-picker v-model="addForm.planEndDate" 
                      :editable="false" 
                      format="yyyy-MM-dd" 
                      value-format="yyyy-MM-dd"
@@ -148,7 +149,7 @@
             <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 class="line" v-if="user.role>0"><span>成本</span><span>{{userDetail.cost}}元/小时</span></div>
             <div slot="footer" class="dialog-footer">
                 <el-button type="primary" @click="userDetailVisible = false" >确定</el-button>
             </div>
@@ -199,7 +200,7 @@
     padding:10px;
 }
 .line span{
-    font-size:18px;
+    font-size:15px;
 }
 .line span:nth-child(even){
     float:right;

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

@@ -1,8 +1,8 @@
 <template>
-    <section>
+    <section >
         <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 label="系统基础设置">
                 </el-form-item>
                 <el-form-item  style="float:right">
                     <el-button  type="primary" @click="submitInsert" :loading="addLoading">保存</el-button>

+ 15 - 7
fhKeeper/formulahousekeeper/timesheet/src/views/team/index.vue

@@ -5,9 +5,10 @@
                 <span>部门</span>
                 <div v-on:click="createDepartment(-1)">
                     <i class="fa fa-plus-circle"></i>
-                    创建部门
+                    创建
                 </div>
             </div>
+            <el-divider style="margin: 0px 0px !important;height:0.5px;"></el-divider>
             <div class="tree" :style="'height:'+ (tableHeight + 83) + 'px'">
                 <el-tree :data="data" :props="defaultProps" @node-click="handleNodeClick" accordion></el-tree>
             </div>
@@ -862,14 +863,16 @@
 
 <style lang="scss" scoped>
     .left {
-        border: 1px solid #f2f2f2;
+        
+        border-right: 1px solid #f2f2f2;
         overflow: hidden;
         .department {
-            color: #8f8f8f;
-            margin: 15px 0 10px;
-            line-height: 30px;
-            padding: 0 10px;
-            font-size: 16px;
+            background:#f2f2f2;
+            line-height: 60px;
+            color:#666;
+            padding:0 10px;
+            height:60px;
+            font-size: 15px;
             div {
                 float: right;
                 color: #20a0ff;
@@ -901,6 +904,11 @@
             overflow-x: hidden;
             white-space: nowrap;
             text-overflow: ellipsis;
+            
         }
     }
+    .el-divider--horizontal {
+        margin: 0px;
+        background:#f3f3f3;
+    }
 </style>

+ 44 - 8
fhKeeper/formulahousekeeper/timesheet/src/views/workReport/daily.vue

@@ -108,6 +108,8 @@
                                             <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 v-if="item2.taskId != null">任务:{{item2.taskName}}
+                                            </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>
@@ -200,12 +202,18 @@
                         :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[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 + '.taskId'" v-if="user.company.packageProject==1">
+                        <el-select v-model="domain.taskId" placeholder="请选择" style="width:100%;" 
+                        :disabled="workForm.domains.length==0?true:(workForm.domains[index].state>=2?false:true)">
+                            <el-option v-for="item in domain.taskList" :key="item.taskId" :label="item.taskName" :value="item.taskId"></el-option>
+                        </el-select>
+                    </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[index].state>=2?false:true)"></el-input>
@@ -318,24 +326,43 @@
             //项目选中了, 加载子项目
             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.$message({
+                        message: error,
+                        type: "error"
+                    });
+                    }
+                );
+                //项目相关的近期任务
+                if (this.user.company.packageProject == 1) {
+                    this.http.post('/task/getRecentTask',{ 
                         projectId: domain.projectId
                     },
                     res => {
                         if (res.code == "ok") {
-                            this.workForm.domains[index].subProjectList = res.data;
-                            // domain.subProjectList = res.data;
-                            // console.log(domain.subProjectList);
+                            this.workForm.domains[index].taskList = res.data;
                             this.$forceUpdate();
                         } 
                     },
                     error => {
-                        this.listLoading = false;
                         this.$message({
                             message: error,
                             type: "error"
                         });
                         }
                     );
+                }
+                
             },
             //删除自己的日报
            deleteReport() {
@@ -854,7 +881,11 @@
                                     workingTime: list.report[i].workingTime,
                                     content: list.report[i].content,
                                     state: list.report[i].state,
-                                    timeType: list.report[i].timeType
+                                    timeType: list.report[i].timeType,
+                                    subProjectList: list.report[i].subProjectList,
+                                    taskList: list.report[i].taskList,
+                                    subProjectId: list.report[i].subProjectId,
+                                    taskId: list.report[i].taskId,
                                 })
                                 if (list.report[i].state >= 2) {
                                     this.canEdit = true;
@@ -1006,6 +1037,11 @@
                             } else {
                                 formData.append("subProjectId", 0);
                             }
+                            if (this.workForm.domains[i].taskId != null) {
+                                formData.append("taskId", this.workForm.domains[i].taskId);
+                            } else {
+                                formData.append("taskId", 0);
+                            }
                             
                             formData.append("reportTimeType", this.reportTimeType.type);
                             if (this.reportTimeType.type == 0) {
@@ -1173,10 +1209,10 @@
         created() {
             let height = window.innerHeight;
             console.log('window inner height=='+height)
-            this.tableHeight = height - 153;
+            this.tableHeight = height - 178;
             const that = this;
             window.onresize = function temp() {
-                that.tableHeight = window.innerHeight - 153;
+                that.tableHeight = window.innerHeight - 178;
             };
 
         },

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

@@ -346,10 +346,10 @@
         },
         created() {
             let height = window.innerHeight;
-            this.tableHeight = height - 85;
+            this.tableHeight = height - 125;
             const that = this;
             window.onresize = function temp() {
-                that.tableHeight = window.innerHeight - 85;
+                that.tableHeight = window.innerHeight - 125;
             };
         },