qastatisticblock.html.php 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. <?php
  2. /**
  3. * The qa statistic block view file of block module of ZenTaoPMS.
  4. * @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
  5. * @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
  6. * @author Yuting Wang <wangyuting@easycorp.ltd>
  7. * @package block
  8. * @link https://www.zentao.net
  9. */
  10. namespace zin;
  11. $active = isset($params['active']) ? $params['active'] : key($products); // 当前产品 ID。
  12. $product = null; // 当前产品。 Current active product.
  13. $items = array(); // 产品导航列表。 Product nav list.
  14. /* 生成左侧菜单项列表。 */
  15. foreach($products as $productItem)
  16. {
  17. $projectID = isset($params['projectID']) ? $params['projectID'] : 0;
  18. $params = helper::safe64Encode("module={$block->module}&projectID={$projectID}&active={$productItem->id}");
  19. $items[] = array
  20. (
  21. 'id' => $productItem->id,
  22. 'text' => $productItem->name,
  23. 'url' => createLink('bug', 'browse', "productID=$productItem->id"),
  24. 'activeUrl' => createLink('block', 'printBlock', "blockID=$block->id&params=$params")
  25. );
  26. if($productItem->id == $active) $product = $productItem;
  27. }
  28. /**
  29. * 构建进度条。
  30. *
  31. * @param object $product 产品。
  32. * @param bool $longBlock 是否为长块。
  33. */
  34. $buildProgressBars = function($product, bool $longBlock): node
  35. {
  36. global $lang;
  37. $progressMax = max($product->addYesterday, $product->addToday, $product->resolvedYesterday, $product->resolvedToday, $product->closedYesterday, $product->closedToday);
  38. $labels = array();
  39. $bars = array();
  40. $fields = array('addYesterday', 'addToday', 'resolvedYesterday', 'resolvedToday', 'closedYesterday', 'closedToday');
  41. foreach($fields as $index => $field)
  42. {
  43. $isEven = $index % 2 === 0;
  44. $labels[] = row
  45. (
  46. setClass('clip items-center', $isEven ? 'mt-3' : 'text-gray', $longBlock ? 'h-6' : 'h-5'),
  47. span($lang->block->qastatistic->{$field}),
  48. span
  49. (
  50. setClass('ml-1.5 inline-block text-left', $isEven ? 'font-bold' : ''),
  51. setStyle('min-width', '1.5em'),
  52. $product->{$field}
  53. )
  54. );
  55. $bars[] = row
  56. (
  57. setClass('items-center ml-1 border-l', $isEven ? 'mt-3' : '', $longBlock ? 'h-6' : 'h-5'),
  58. progressBar
  59. (
  60. setClass('progress flex-auto'),
  61. set::height(8),
  62. set::percent(($progressMax ? $product->{$field} / $progressMax : 0) * 100),
  63. set::color($isEven ? 'var(--color-secondary-200)' : 'var(--color-primary-300)'),
  64. set::background('rgba(0,0,0,0.02)')
  65. )
  66. );
  67. }
  68. return row
  69. (
  70. cell
  71. (
  72. setClass('text-right flex-none'),
  73. $labels
  74. ),
  75. cell
  76. (
  77. setClass('flex-auto'),
  78. $bars
  79. )
  80. );
  81. };
  82. /**
  83. * 构建测试任务列表。
  84. *
  85. * @param object $product 产品。
  86. * @param bool $longBlock 是否为长块。
  87. */
  88. $buildTesttasks = function($product, bool $longBlock): ?\zin\node
  89. {
  90. global $lang;
  91. $unclosedTesttasks = array();
  92. if(!empty($product->unclosedTesttasks))
  93. {
  94. foreach($product->unclosedTesttasks as $waitTesttask)
  95. {
  96. $unclosedTesttasks[] = div
  97. (
  98. setClass('clip', $longBlock ? 'py-1' : 'py-0.5'),
  99. hasPriv('testtask', 'cases') ? a(set('href', createLink('testtask', 'cases', "taskID={$waitTesttask->id}")), set('title', $waitTesttask->name), $waitTesttask->name) : span(set('title', $waitTesttask->name), $waitTesttask->name)
  100. );
  101. if(count($unclosedTesttasks) >= 6) break;
  102. }
  103. }
  104. return $unclosedTesttasks ? col(setClass('min-w-0 flex-1 gap-1.5 px-3 pt-2 border-l'), div(setClass('font-bold'), $lang->block->qastatistic->unclosedTesttasks), div
  105. (
  106. setClass($longBlock ? 'py-2' : 'pt-2'),
  107. $unclosedTesttasks
  108. )) : null;
  109. };
  110. $testTasksView = !empty($product) ? $buildTesttasks($product, $longBlock) : null;
  111. statisticBlock
  112. (
  113. to::titleSuffix
  114. (
  115. icon
  116. (
  117. setClass('text-light text-sm cursor-pointer'),
  118. toggle::tooltip
  119. (
  120. array
  121. (
  122. 'title' => sprintf($lang->block->tooltips['metricTime'], $metricTime),
  123. 'placement' => $app->getClientLang() == 'en' ? 'bottom-end' : 'bottom',
  124. 'type' => 'white',
  125. 'className' => 'text-dark border border-light leading-5'
  126. )
  127. ),
  128. 'help'
  129. )
  130. ),
  131. set::block($block),
  132. set::active($active),
  133. set::items($items),
  134. $product ? div
  135. (
  136. setClass('h-full overflow-hidden items-stretch px-2', $longBlock ? 'row py-3' : 'col gap-2 pt-1'),
  137. center
  138. (
  139. setClass('gap-2 px-5 justify-start ', $testTasksView ? 'flex-none' : 'flex-1', $longBlock ? ' py-2' : ''),
  140. div
  141. (
  142. setClass('w-full font-bold'),
  143. $lang->block->qastatistic->fixBugRate
  144. ),
  145. progressCircle
  146. (
  147. set::percent($product->fixedBugRate),
  148. set::size(112),
  149. set::text(false),
  150. set::circleWidth(0.06),
  151. div(span(setClass('text-2xl font-bold'), $product->fixedBugRate), '%')
  152. ),
  153. row
  154. (
  155. setClass('justify-center items-center gap-4'),
  156. center
  157. (
  158. div(span(!empty($product->totalBug) ? $product->totalBug : 0)),
  159. div
  160. (
  161. setClass('text-sm text-gray'),
  162. $lang->block->bugstatistic->effective
  163. )
  164. ),
  165. center
  166. (
  167. div(span(!empty($product->fixedBug) ? $product->fixedBug : 0)),
  168. div
  169. (
  170. setClass('text-sm text-gray'),
  171. $lang->block->bugstatistic->fixed
  172. )
  173. ),
  174. center
  175. (
  176. div(span(!empty($product->activatedBug) ? $product->activatedBug : 0)),
  177. div
  178. (
  179. setClass('text-sm text-gray'),
  180. $lang->bug->statusList['active']
  181. )
  182. )
  183. )
  184. ),
  185. row
  186. (
  187. setClass($testTasksView ? 'flex-auto' : 'flex-1'),
  188. col
  189. (
  190. setClass('flex-1 gap-1.5 px-3 py-2'),
  191. div(setClass('font-bold'), $lang->block->qastatistic->bugStatistics),
  192. !empty($product) ? $buildProgressBars($product, $longBlock) : null
  193. ),
  194. $testTasksView
  195. )
  196. ) : null
  197. );