view_overview.html 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. <table class="layui-table layui-table-form">
  2. <tr>
  3. <td class="layui-td-gray">项目状态</td>
  4. <td><span class="check-status-color-{$detail.status}">『{$detail.status_name}』</span></td>
  5. <td class="layui-td-gray">项目类别</td>
  6. <td>{$detail.cate}</td>
  7. <td class="layui-td-gray">始止日期</td>
  8. <td>{$detail.start_time|date='Y-m-d'} 到 {$detail.end_time|date='Y-m-d'}</td>
  9. <td class="layui-td-gray">所属部门</td>
  10. <td>{$detail.department|default='-'}</td>
  11. </tr>
  12. <tr>
  13. <td class="layui-td-gray">项目经理</td>
  14. <td>{$detail.director_name}</td>
  15. <td class="layui-td-gray">项目成员</td>
  16. <td colspan="5">{$detail.team_admin_names|default='-'}</td>
  17. </tr>
  18. {gt name="$detail.contract_id" value="0"}
  19. <tr>
  20. <td class="layui-td-gray">关联合同</td>
  21. <td colspan="7">{$detail.contract_name}</td>
  22. </tr>
  23. {/gt}
  24. {notempty name="$detail.content"}
  25. <tr>
  26. <td class="layui-td-gray">项目简介</td>
  27. <td colspan="7">{$detail.content}</td>
  28. </tr>
  29. {/notempty}
  30. </table>
  31. <div class="layui-card border" style="margin-top:16px;">
  32. <div class="layui-card-header" style="height:43px; line-height:43px;">
  33. <strong>项目阶段</strong>
  34. </div>
  35. <div class="px-3 py-1 border-b">
  36. <div class="flow-flexbox check-items flow-flex-row">
  37. {volist name="$detail.step_array" id="vo"}
  38. <div class='flow-flexbox flow-flex-row check-item {eq name="$vo.is_current" value="1"} blue{/eq} {notempty name="$step"}{lt name="$vo.sort" value="$step.sort"} gray{/lt}{else/} gray{/notempty}'>
  39. <div class="check-item-icon">
  40. <strong class="iconfont icon-bianji blue"></strong>
  41. <strong class="iconfont icon-kaoheguanli gray"></strong>
  42. <strong class="iconfont icon-genjinjilu black"></strong>
  43. </div>
  44. <div>
  45. <div class="check-item-name"><strong class="f16">{$vo.title}</strong> {$vo.director_name|default=''}</div>
  46. <div class="check-item-time">{$vo.start_time|date='Y-m-d'} 到 {$vo.end_time|date='Y-m-d'}</div>
  47. </div>
  48. <div class="layui-icon layui-icon-right"></div>
  49. </div>
  50. {/volist}
  51. </div>
  52. </div>
  53. {notempty name="$step"}
  54. <div class="p-3 border-b">
  55. <div>
  56. <span class="gray">当前阶段:</span>{$step.title}
  57. <span class="gray" style="margin-left:20px">阶段周期:</span>{$step.start_time|date='Y-m-d'} 到 {$step.end_time|date='Y-m-d'}
  58. <span class="gray" style="margin-left:20px">负责人:</span>{$step.director_name}
  59. {eq name="$step.director_uid" value="$login_admin.id"}
  60. <span class="layui-btn layui-btn-normal layui-btn-xs" data-event="step" data-check="1">确认完成</span>
  61. <span class="layui-btn layui-btn-danger layui-btn-xs" data-event="step" data-check="2">退回上一阶段</span>
  62. {/eq}
  63. </div>
  64. {notempty name="$step.unames"}
  65. <div class="pt-2">
  66. <span class="gray">阶段成员:</span>{$step.unames|default=''}
  67. </div>
  68. {/notempty}
  69. {notempty name="$step.remark"}
  70. <div class="pt-2">
  71. <span class="gray">阶段说明:</span>{$step.remark|default=''}
  72. </div>
  73. {/notempty}
  74. </div>
  75. {/notempty}
  76. <div class="p-3">
  77. <p><strong>阶段流转记录</strong></p>
  78. {notempty name="$step_record"}
  79. <ul class="layui-timeline pt-2">
  80. {volist name="$step_record" id="vo"}
  81. <li class="layui-timeline-item delete_{$vo.delete_time}">
  82. <i class="layui-icon layui-timeline-axis">&#xe63f;</i>
  83. {if ($vo.status == 1)}
  84. <p style="padding-left:24px">{$vo.check_time_str}<span class="black mx-1">{$vo.check_name}</span><span class="mr-1 green">{$vo.status_str}</span>了『{$vo.title}』的工作。操作意见:<span class="green">{$vo.content|default='-'}</span></p>
  85. {else /}
  86. <p style="padding-left:24px">{$vo.check_time_str}<span class="black mx-1">{$vo.check_name}</span>在阶段『{$vo.title}』执行了<span class="mx-1 red">{$vo.status_str}</span>操作。操作意见:<span class="red">{$vo.content|default='-'}</span></p>
  87. {/if}
  88. </li>
  89. {/volist}
  90. </ul>
  91. {else/}
  92. <div class="layui-data-none">暂无阶段流转记录</div>
  93. {/notempty}
  94. </div>
  95. </div>
  96. <div class="layui-card border">
  97. <div class="layui-card-header" style="height:45px; line-height:45px;">
  98. <strong>项目附件</strong>
  99. <button type="button" class="layui-btn layui-btn-xs" id="uploadBtn">上传附件</button>
  100. </div>
  101. <div class="layui-row p-2" id="uploadBox">
  102. {volist name="file_array" id="vo"}
  103. <div class="layui-col-md4" id="fileItem{$vo.id}">{:file_card($vo)}</div>
  104. {/volist}
  105. {empty name="$file_array" }
  106. <div class="layui-data-none">暂无项目附件</div>
  107. {/empty}
  108. </div>
  109. </div>
  110. <div class="layui-row mb-4 border">
  111. <div class="layui-col-xs6 layui-col-md3">
  112. <div class="layui-card">
  113. <div class="layui-card-header" style="height:45px; line-height:45px;">
  114. <strong>项目概况</strong>
  115. </div>
  116. <div class="p-3">
  117. <dl>
  118. <dt>任务 <span class="gray">(已完成/全部)</span></dt>
  119. <dd class="layui-card-value" title="已完成/总任务">{$detail.tasks_finish} / {$detail.tasks}</dd>
  120. </dl>
  121. </div>
  122. <div class="pt-2 px-3">
  123. <dl>
  124. <dt>项目工时 <span class="gray">(实际/计划)</span></dt>
  125. <dd class="layui-card-value" title="实际工时/计划工时">{$detail.hours} / {$detail.plan_hours}</dd>
  126. </dl>
  127. </div>
  128. <div class="pt-2 px-3">
  129. <dl>
  130. <dt>工作记录</dt>
  131. <dd class="layui-card-value" title="工作记录数">{$detail.schedules}</dd>
  132. </dl>
  133. </div>
  134. </div>
  135. </div>
  136. <div class="layui-col-xs6 layui-col-md9">
  137. <div class="layui-card border-l">
  138. <div class="layui-card-header" style="height:45px; line-height:45px;">
  139. <strong>项目进度</strong>
  140. </div>
  141. <div class="layui-card-body">
  142. <div class="layui-row">
  143. <div class="layui-col-md6">
  144. <div id="progress" class="gougu-data-none" style="width:100%; height:200px;"></div>
  145. </div>
  146. <div class="layui-col-md6">
  147. <div id="delay" class="gougu-data-none" style="width:100%; height:200px;"></div>
  148. </div>
  149. </div>
  150. </div>
  151. </div>
  152. </div>
  153. </div>
  154. <div class="layui-card border">
  155. <div class="layui-card-header" style="height:45px; line-height:45px;">
  156. <strong>项目燃尽图</strong>
  157. </div>
  158. <div class="layui-card-body">
  159. <div id="cross" class="gougu-data-none" style="width:100%; height:360px;"
  160. data-tips="任务数:{$detail.tasks},已完成:{$detail.tasks_finish},未完成:{$detail.tasks_unfinish}">
  161. </div>
  162. </div>
  163. </div>
  164. <div class="layui-row border">
  165. <div class="layui-col-xs6 layui-col-md6">
  166. <div class="layui-card border-r">
  167. <div class="layui-card-header" style="height:45px; line-height:45px;">
  168. <strong>任务分配情况</strong>
  169. </div>
  170. <div class="layui-card-body">
  171. <div id="plan" class="gougu-data-none" style="width:100%; height:150px;"></div>
  172. </div>
  173. </div>
  174. </div>
  175. <div class="layui-col-xs6 layui-col-md6">
  176. <div class="layui-card">
  177. <div class="layui-card-header" style="height:45px; line-height:45px;">
  178. <strong>工时登记情况</strong>
  179. </div>
  180. <div class="layui-card-body">
  181. <div id="work" class="gougu-data-none" style="width:100%; height:150px;"></div>
  182. </div>
  183. </div>
  184. </div>
  185. </div>
  186. <script>
  187. function overview(){
  188. let form = layui.form,tool = layui.tool,uploadPlus = layui.uploadPlus;
  189. $('body').on('click','[data-event="step"]',function(){
  190. let check = $(this).data('check');
  191. let callback = function (e) {
  192. layer.msg(e.msg);
  193. if(e.code==0){
  194. setTimeout(function(){
  195. location.reload();
  196. },2000)
  197. parent.layui.pageTable.reload();
  198. }
  199. }
  200. if(check == 2){
  201. $(parent.$('.express-close')).addClass('parent-colse');
  202. layer.open({
  203. type: 1,
  204. title: '请输入退回的原因或理由',
  205. area: ['500px', '252px'],
  206. content: '<div style="padding:5px;"><textarea class="layui-textarea" id="remarkTextarea" style="width: 100%; height:132px;"></textarea></div>',
  207. btnAlign: 'c',
  208. btn: ['确认回退'],
  209. end: function(){
  210. $(parent.$('.express-close')).removeClass('parent-colse');
  211. },
  212. yes: function () {
  213. let remark = $("#remarkTextarea").val();
  214. if (remark != '') {
  215. tool.post("/project/api/step_check", {id: project_id,check:check,content:remark}, callback);
  216. } else {
  217. layer.msg('请输入原因或理由');
  218. }
  219. }
  220. })
  221. }
  222. else{
  223. $(parent.$('.express-close')).addClass('parent-colse');
  224. layer.open({
  225. type: 1,
  226. title: '请输入操作意见',
  227. area: ['500px', '252px'],
  228. content: '<div style="padding:5px;"><textarea class="layui-textarea" id="remarkTextarea" style="width: 100%; height:132px;"></textarea></div>',
  229. btnAlign: 'c',
  230. btn: ['确认完成'],
  231. end: function(){
  232. $(parent.$('.express-close')).removeClass('parent-colse');
  233. },
  234. yes: function () {
  235. let remark = $("#remarkTextarea").val();
  236. if (remark != '') {
  237. tool.post("/project/api/step_check", {id: project_id,check:check,content:remark}, callback);
  238. } else {
  239. layer.msg('请输入操作意见');
  240. }
  241. }
  242. })
  243. }
  244. });
  245. var attachment = new uploadPlus({
  246. "target":'uploadBtn',
  247. "targetBox":'uploadBox',
  248. "attachment":{
  249. "type":1,//0ajax多文件模式,1ajax单文件单记录模式
  250. "uidDelete":true,//是否开启只有上传人自己才能删除自己的附件
  251. "ajaxSave":function(res){
  252. let callback = function (e) {
  253. layer.msg('上传成功');
  254. setTimeout(function(){
  255. location.reload();
  256. },2000)
  257. }
  258. tool.post("/project/api/add_file", { 'topic_id': project_id, 'file_id': res.data.id, 'file_name': res.data.name, 'module': 'project' }, callback);
  259. },
  260. "ajaxDelete":function(file_id){
  261. let callback = function (e) {
  262. layer.msg(e.msg);
  263. if (e.code == 0) {
  264. $('#fileItem' + file_id).remove();
  265. }
  266. }
  267. tool.delete("/project/api/delete_file", {id: file_id}, callback);
  268. }
  269. }
  270. });
  271. let callback = function (res) {
  272. if (res.data.date_tasks instanceof Array == false) {
  273. optionA.title.text = res.data.task_pie.ok_lv + '%';
  274. optionA.series = [
  275. {
  276. type: 'pie',
  277. radius: ['60%', '80%'],
  278. center: ['50%', '50%'],
  279. avoidLabelOverlap: false,
  280. label: {
  281. show: false
  282. },
  283. data: [
  284. { value: res.data.task_pie.count - res.data.task_pie.count_ok, name: '待处理' },
  285. { value: res.data.task_pie.count_ok, name: '已完成' }
  286. ]
  287. }
  288. ];
  289. optionA && progressChart.setOption(optionA);
  290. optionB.title.text = res.data.task_pie.delay_lv + '%';
  291. optionB.series = [
  292. {
  293. type: 'pie',
  294. radius: ['60%', '80%'],
  295. center: ['50%', '50%'],
  296. avoidLabelOverlap: false,
  297. label: {
  298. show: false
  299. },
  300. data: [{
  301. value: res.data.task_pie.delay,
  302. name: '延迟',
  303. itemStyle: {
  304. color: "#ED6666",
  305. }
  306. },
  307. {
  308. value: (res.data.task_pie.count - res.data.task_pie.delay),
  309. name: '未延迟',
  310. itemStyle: {
  311. color: "#91CC75",
  312. }
  313. }
  314. ]
  315. }
  316. ];
  317. optionB && delayChart.setOption(optionB);
  318. var dataD = cross_count(res.data.date_tasks, res.data.date_tasks_ok);
  319. var tips = $('#cross').data('tips');
  320. optionD.title = {
  321. text: '',
  322. subtext: tips,
  323. top: -10,
  324. },
  325. optionD.xAxis = {
  326. type: 'category',
  327. boundaryGap: false,
  328. splitLine: {
  329. show: true,
  330. lineStyle: {
  331. type: 'dashed'
  332. }
  333. },
  334. data: dataD.x,
  335. axisLabel: {
  336. rotate: 30,
  337. formatter: function (value, index) {
  338. return value.slice(5);
  339. }
  340. }
  341. };
  342. optionD.series = [
  343. {
  344. name: '任务计划剩余',
  345. type: 'line',
  346. showSymbol: false,
  347. markLine: {
  348. data: [{ type: 'average', name: 'Avg' }],
  349. },
  350. lineStyle: {
  351. width: 2
  352. },
  353. data: dataD.y
  354. },
  355. {
  356. name: '任务实际剩余',
  357. type: 'line',
  358. showSymbol: false,
  359. areaStyle: {
  360. opacity: 0.1
  361. },
  362. markLine: {
  363. data: [{ type: 'average', name: 'Avg' }],
  364. },
  365. lineStyle: {
  366. width: 2
  367. },
  368. data: dataD.y2
  369. }
  370. ]
  371. optionD && crossChart.setOption(optionD)
  372. var dataE = getCalendarData(res.data.date_tasks);
  373. optionE.calendar.range = dataE.range,
  374. optionE.series = {
  375. type: 'heatmap',
  376. coordinateSystem: 'calendar',
  377. data: dataE.data
  378. }
  379. optionE && planChart.setOption(optionE);
  380. if (res.data.date_schedules instanceof Array == false) {
  381. var dataF = getCalendarData(res.data.date_schedules);
  382. optionF.calendar.range = dataF.range,
  383. optionF.series = {
  384. type: 'heatmap',
  385. coordinateSystem: 'calendar',
  386. data: dataF.data
  387. }
  388. optionF && workChart.setOption(optionF);
  389. }
  390. }
  391. }
  392. tool.get('/project/api/get_chart_data', { 'project_id': project_id }, callback);
  393. window.onresize = function () {
  394. progressChart.resize();
  395. delayChart.resize();
  396. crossChart.resize();
  397. planChart.resize();
  398. workChart.resize();
  399. }
  400. }
  401. </script>