ModuleTwo.vue 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. <template>
  2. <module-container title="查堵人员分析">
  3. <div class="module-two-content">
  4. <div class="top-row">
  5. <div class="table-card">
  6. <div class="card-title">查堵-主管分管榜</div>
  7. <div class="rank-table">
  8. <div v-for="(item, index) in rankData1" :key="index" class="rank-row">
  9. <span class="rank-number" :class="'rank-' + (index + 1)">NO.{{ index + 1 }}</span>
  10. <span class="rank-name">{{ item.name }}</span>
  11. <span class="rank-value">{{ item.value }}</span>
  12. </div>
  13. </div>
  14. </div>
  15. <div class="table-card">
  16. <div class="card-title">查堵-班组排行</div>
  17. <div class="rank-table">
  18. <div v-for="(item, index) in rankData2" :key="index" class="rank-row">
  19. <span class="rank-number" :class="'rank-' + (index + 1)">NO.{{ index + 1 }}</span>
  20. <span class="rank-name">{{ item.name }}</span>
  21. <span class="rank-value">{{ item.value }}</span>
  22. </div>
  23. </div>
  24. </div>
  25. <div class="table-card">
  26. <div class="card-title">查堵-人员榜</div>
  27. <div class="rank-table">
  28. <div v-for="(item, index) in rankData3" :key="index" class="rank-row">
  29. <span class="rank-number" :class="'rank-' + (index + 1)">NO.{{ index + 1 }}</span>
  30. <span class="rank-name">{{ item.name }}</span>
  31. <span class="rank-value">{{ item.value }}</span>
  32. </div>
  33. </div>
  34. </div>
  35. </div>
  36. <div class="middle-row">
  37. <div class="chart-card">
  38. <div class="card-title">查堵-物品位置分布</div>
  39. <div ref="chart1" class="echarts"></div>
  40. </div>
  41. <div class="chart-card">
  42. <div class="card-title">查堵-原因分类</div>
  43. <div ref="chart2" class="echarts"></div>
  44. </div>
  45. </div>
  46. <div class="bottom-row">
  47. <div class="chart-card">
  48. <div class="card-title">查堵-开机人员年限分布</div>
  49. <div ref="chart3" class="echarts"></div>
  50. </div>
  51. <div class="chart-card">
  52. <div class="card-title">查堵-开机人员性别比例</div>
  53. <div ref="chart4" class="echarts"></div>
  54. </div>
  55. <div class="chart-card">
  56. <div class="card-title">查堵-图像难易程度比例</div>
  57. <div ref="chart5" class="echarts"></div>
  58. </div>
  59. </div>
  60. <div class="extra-row">
  61. <div class="chart-card">
  62. <div class="card-title">大队开机人员查堵分布</div>
  63. <div ref="chart6" class="echarts"></div>
  64. </div>
  65. <div class="chart-card">
  66. <div class="card-title">大队开机人员查堵分布</div>
  67. <div ref="chart7" class="echarts"></div>
  68. </div>
  69. </div>
  70. </div>
  71. </module-container>
  72. </template>
  73. <script setup>
  74. import { ref, onMounted, reactive } from 'vue'
  75. import * as echarts from 'echarts'
  76. import ModuleContainer from './ModuleContainer.vue'
  77. import { useEcharts } from '@/hooks/chart.js'
  78. const chart1 = ref(null)
  79. const chart2 = ref(null)
  80. const chart3 = ref(null)
  81. const chart4 = ref(null)
  82. const chart5 = ref(null)
  83. const chart6 = ref(null)
  84. const chart7 = ref(null)
  85. const { setOption: setOption1 } = useEcharts(chart1)
  86. const { setOption: setOption2 } = useEcharts(chart2)
  87. const { setOption: setOption3 } = useEcharts(chart3)
  88. const { setOption: setOption4 } = useEcharts(chart4)
  89. const { setOption: setOption5 } = useEcharts(chart5)
  90. const { setOption: setOption6 } = useEcharts(chart6)
  91. const { setOption: setOption7 } = useEcharts(chart7)
  92. const rankData1 = reactive([
  93. { name: '李主管', value: 110 },
  94. { name: '李海峰', value: 102 },
  95. { name: '李华波', value: 94 },
  96. { name: '方星星', value: 80 },
  97. { name: '郭仁昌', value: 69 },
  98. { name: '陈晓明', value: 67 },
  99. { name: '万国', value: 62 },
  100. { name: '杨高星', value: 60 },
  101. { name: '符昌国', value: 59 },
  102. { name: '李星国', value: 57 },
  103. { name: '周良志', value: 56 },
  104. { name: '杨旭', value: 53 }
  105. ])
  106. const rankData2 = reactive([
  107. { name: '李智辉', value: 44 },
  108. { name: '林明玉', value: 42 },
  109. { name: '吴帮文', value: 40 },
  110. { name: '杨玉艳', value: 37 },
  111. { name: '符玉玲', value: 37 },
  112. { name: '黄登', value: 36 },
  113. { name: '梁品俊', value: 35 },
  114. { name: '陈勤丽', value: 35 },
  115. { name: '潘政生', value: 34 },
  116. { name: '周民伦', value: 34 },
  117. { name: '王明星', value: 33 },
  118. { name: '林文海', value: 33 }
  119. ])
  120. const rankData3 = reactive([
  121. { name: '梁翠兰', value: 21 },
  122. { name: '陈秀强', value: 20 },
  123. { name: '李国', value: 19 },
  124. { name: '梁其佐', value: 18 },
  125. { name: '王名标', value: 18 },
  126. { name: '李书帆', value: 17 },
  127. { name: '李亚峰', value: 17 },
  128. { name: '杨燕钰', value: 16 },
  129. { name: '刘燕萍', value: 16 },
  130. { name: '庄伟', value: 16 },
  131. { name: '黄富伦', value: 15 },
  132. { name: '唐甸宇', value: 15 }
  133. ])
  134. const pieOption = (data, colors, isRing = false) => ({
  135. color: colors,
  136. series: [{
  137. type: 'pie',
  138. radius: isRing ? ['50%', '70%'] : '60%',
  139. center: ['50%', '55%'],
  140. data: data,
  141. label: {
  142. show: true,
  143. formatter: '{b}\n{c}%',
  144. fontSize: 10
  145. }
  146. }]
  147. })
  148. const barOption = (data, colors) => ({
  149. grid: { left: '15%', top: '10%', right: '5%', bottom: '10%', containLabel: true },
  150. xAxis: { type: 'value', axisLabel: { fontSize: 9 } },
  151. yAxis: { type: 'category', data: data.map(d => d.name), axisLabel: { fontSize: 9 } },
  152. series: [{
  153. type: 'bar',
  154. data: data.map(d => d.value),
  155. itemStyle: {
  156. color: (params) => colors[params.dataIndex % colors.length]
  157. },
  158. barWidth: 15
  159. }]
  160. })
  161. const stackBarOption = (data, colors) => ({
  162. grid: { left: '15%', top: '10%', right: '5%', bottom: '15%', containLabel: true },
  163. xAxis: { type: 'category', data: ['安检二大队', '安检三大队', '安检一大队'], axisLabel: { fontSize: 9 } },
  164. yAxis: { type: 'value', axisLabel: { fontSize: 9 } },
  165. legend: { top: 0, right: 10, textStyle: { fontSize: 9 } },
  166. series: data.map((d, i) => ({
  167. name: d.name,
  168. type: 'bar',
  169. stack: 'total',
  170. data: d.data,
  171. itemStyle: { color: colors[i] },
  172. barWidth: 25
  173. }))
  174. })
  175. onMounted(() => {
  176. setOption1(pieOption([
  177. { name: '包上', value: 10 },
  178. { name: '包中', value: 15 },
  179. { name: '包下', value: 12 },
  180. { name: '左上', value: 18 },
  181. { name: '左中', value: 20 },
  182. { name: '左下', value: 15 },
  183. { name: '右下', value: 10 }
  184. ], ['#3b82f6', '#22c55e', '#f97316', '#ec4899', '#8b5cf6', '#14b8a6', '#64748b']))
  185. setOption2(pieOption([
  186. { name: '未注意到部位以及未仔细判图', value: 25 },
  187. { name: '图像特征难以发现', value: 20 },
  188. { name: '判图难度较大', value: 18 },
  189. { name: '图像中判清物品', value: 15 },
  190. { name: '判图不清,未能有效识别物品', value: 12 },
  191. { name: '其他', value: 10 }
  192. ], ['#ef4444', '#f97316', '#eab308', '#22c55e', '#3b82f6', '#64748b'], true))
  193. setOption3(barOption([
  194. { name: '6年及以上', value: 77 },
  195. { name: '4-6年', value: 25 },
  196. { name: '3年', value: 18 },
  197. { name: '2年', value: 30 },
  198. { name: '1年', value: 69 },
  199. { name: '1年以下', value: 12 }
  200. ], ['#3b82f6', '#60a5fa', '#93c5fd', '#bfdbfe', '#dbeafe', '#eff6ff']))
  201. setOption4(pieOption([
  202. { name: '男', value: 63 },
  203. { name: '女', value: 37 }
  204. ], ['#3b82f6', '#ec4899']))
  205. setOption5(pieOption([
  206. { name: '简单', value: 52 },
  207. { name: '难', value: 30 },
  208. { name: '未评判', value: 12 },
  209. { name: '空白', value: 6 }
  210. ], ['#93c5fd', '#3b82f6', '#64748b', '#e2e8f0']))
  211. setOption6(stackBarOption([
  212. { name: '6年及以上人数', data: [30, 25, 22] },
  213. { name: '4-6年人数', data: [15, 20, 18] },
  214. { name: '3年人数', data: [10, 12, 15] },
  215. { name: '2年人数', data: [12, 15, 13] },
  216. { name: '1年人数', data: [25, 30, 28] },
  217. { name: '不足1年人数', data: [5, 8, 10] }
  218. ], ['#3b82f6', '#22c55e', '#f97316', '#ec4899', '#8b5cf6', '#14b8a6']))
  219. setOption7(stackBarOption([
  220. { name: '安检一大队', data: [135, 120] },
  221. { name: '安检二大队', data: [90, 110] },
  222. { name: '安检三大队', data: [70, 130] }
  223. ], ['#3b82f6', '#22c55e', '#f97316']))
  224. })
  225. </script>
  226. <style lang="less" scoped>
  227. .module-two-content {
  228. height: 100%;
  229. display: flex;
  230. flex-direction: column;
  231. gap: 8px;
  232. overflow-y: auto;
  233. }
  234. .top-row,
  235. .middle-row,
  236. .bottom-row,
  237. .extra-row {
  238. display: flex;
  239. gap: 8px;
  240. flex-shrink: 0;
  241. }
  242. .table-card {
  243. flex: 1;
  244. background: #fff;
  245. border-radius: 6px;
  246. padding: 8px;
  247. box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
  248. display: flex;
  249. flex-direction: column;
  250. min-height: 200px;
  251. }
  252. .chart-card {
  253. flex: 1;
  254. background: #fff;
  255. border-radius: 6px;
  256. padding: 8px;
  257. box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
  258. display: flex;
  259. flex-direction: column;
  260. min-height: 120px;
  261. }
  262. .card-title {
  263. font-size: 11px;
  264. color: #333;
  265. margin-bottom: 5px;
  266. text-align: center;
  267. font-weight: 500;
  268. }
  269. .rank-table {
  270. flex: 1;
  271. overflow-y: auto;
  272. }
  273. .rank-row {
  274. display: flex;
  275. align-items: center;
  276. padding: 4px 6px;
  277. border-bottom: 1px solid #f0f0f0;
  278. font-size: 11px;
  279. }
  280. .rank-row:last-child {
  281. border-bottom: none;
  282. }
  283. .rank-number {
  284. width: 45px;
  285. font-weight: bold;
  286. margin-right: 8px;
  287. }
  288. .rank-1 {
  289. color: #eab308;
  290. }
  291. .rank-2 {
  292. color: #94a3b8;
  293. }
  294. .rank-3 {
  295. color: #f97316;
  296. }
  297. .rank-name {
  298. flex: 1;
  299. color: #333;
  300. }
  301. .rank-value {
  302. color: #666;
  303. }
  304. .echarts {
  305. flex: 1;
  306. width: 100%;
  307. min-height: 100px;
  308. }
  309. </style>