Score.vue 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. <template>
  2. <div class="score-layout">
  3. <div class="score-left">
  4. <div class="score-header">
  5. <span class="score-title">综合评分</span>
  6. <el-radio-group v-model="timeSelect" class="score-select" @change="changeTime">
  7. <el-radio-button v-for="item in ScoreTimeList" :label="item.label" :value="item.value" />
  8. </el-radio-group>
  9. </div>
  10. <el-divider />
  11. <div class="score-show">
  12. <VChart
  13. v-if="scoreInfoList.length > 0"
  14. class="pic-show"
  15. :option="options"
  16. :style="{ height: updateChartHeight }"
  17. />
  18. <div v-else class="pic-none">暂无数据</div>
  19. </div>
  20. </div>
  21. <div class="score-divider" :style="{ height: updateLineHeight }"></div>
  22. <div class="score-right">
  23. <div class="concern-title">重点关注车间</div>
  24. <ul v-if="workshopList.length > 0" class="concern-workspace">
  25. <li v-for="workshop in workshopList">{{ workshop }}</li>
  26. </ul>
  27. <div class="score-tip">
  28. <el-icon><Warning /></el-icon>
  29. <div class="tip-content">动态显示当前安全评分最低的三个车间</div>
  30. </div>
  31. </div>
  32. </div>
  33. </template>
  34. <script setup lang="ts">
  35. import { ref, onMounted } from 'vue';
  36. import { ScoreTimeList, TimeEnum } from '../types';
  37. import { computed } from 'vue';
  38. import VChart from 'vue-echarts';
  39. import { use } from 'echarts/core';
  40. import { CanvasRenderer } from 'echarts/renderers';
  41. import { BarChart } from 'echarts/charts';
  42. import { Warning } from '@element-plus/icons-vue';
  43. import {
  44. TooltipComponent,
  45. LegendComponent,
  46. GridComponent,
  47. DataZoomComponent,
  48. } from 'echarts/components';
  49. import useScore from '../hooks/useScoreInfo';
  50. import useWorkshopTop from '../hooks/useWorkshopTop';
  51. const useTop = useWorkshopTop();
  52. const { openTopWs, workshopList } = useTop;
  53. onMounted(() => {
  54. openTopWs();
  55. console.log('workshopList', workshopList.value);
  56. const contentDom = document.querySelector('.content') as HTMLDivElement;
  57. if (contentDom) {
  58. updateChartHeight.value = contentDom.offsetHeight - 454 + 'px';
  59. updateLineHeight.value = contentDom.offsetHeight - 404 + 'px';
  60. } else {
  61. console.error('@@@@');
  62. }
  63. });
  64. const useHomeScore = useScore();
  65. const {
  66. scoreInfoList,
  67. getDailyScoreList,
  68. getWeeklyScoreList,
  69. getMonthlyScoreList,
  70. getQuarterlyScoreList,
  71. } = useHomeScore;
  72. use([
  73. CanvasRenderer,
  74. BarChart,
  75. TooltipComponent,
  76. LegendComponent,
  77. GridComponent,
  78. DataZoomComponent,
  79. ]);
  80. const timeSelect = ref<TimeEnum>(TimeEnum.DAY);
  81. //const workspaceList = ['车间1', '车间2', '车间3'];
  82. // const updateChartHeight = computed(() => window.innerHeight - 670 + 'px');
  83. // const updateLineHeight = computed(() => window.innerHeight - 618 + 'px');
  84. const updateChartHeight = ref('');
  85. const updateLineHeight = ref('');
  86. const dataZoomConfig = computed(() => [
  87. {
  88. type: 'slider',
  89. show: true,
  90. showDetail: false,
  91. showDataShadow: false,
  92. xAxisIndex: [0],
  93. start: 0,
  94. end: Number(9 / scoreInfoList.value.length) * 100,
  95. handleSize: 1,
  96. height: 7,
  97. bottom: 2,
  98. brushSelect: false,
  99. handleStyle: {
  100. opacity: 0,
  101. },
  102. },
  103. {
  104. // 没有下面这块的话,只能拖动滚动条,
  105. // 鼠标滚轮在区域内不能控制外部滚动条
  106. type: 'inside',
  107. // 控制哪个轴,如果是number表示控制一个轴,
  108. // 如果是Array表示控制多个轴。此处控制第二根轴
  109. xAxisIndex: [0, 1],
  110. // 滚轮是否触发缩放
  111. zoomOnMouseWheel: false,
  112. // 鼠标移动能否触发平移
  113. moveOnMouseMove: true,
  114. // 鼠标滚轮能否触发平移
  115. moveOnMouseWheel: true,
  116. },
  117. ]);
  118. const options = computed(() => {
  119. return {
  120. tooltip: {
  121. trigger: 'axis',
  122. axisPointer: {
  123. type: 'none',
  124. },
  125. formatter: (v) => {
  126. let [a] = v;
  127. const workshopList = scoreInfoList.value.find(
  128. (item) => item.date === a.name,
  129. )?.workshopList;
  130. return `
  131. <div class='u-p-2'>
  132. <div>评分最低的三个车间</div>
  133. ${workshopList?.map((t) => `<span style="color: blue;">•</span> ${t}`).join('<br>')}
  134. </div>
  135. `;
  136. },
  137. },
  138. grid: {
  139. left: '3%',
  140. right: '4%',
  141. bottom: '4%',
  142. top: '10%',
  143. containLabel: true,
  144. },
  145. xAxis: {
  146. type: 'category',
  147. data: scoreInfoList.value.map((item) => item.date),
  148. axisLabel: {
  149. interval: 0, // 强制显示所有标签
  150. //rotate: dataChart.value.map((item) => item.name).length > 10 ? 45 : 0, // 旋转角度
  151. margin: 20, // 调整标签与轴线的距离,避免标签被遮挡
  152. },
  153. },
  154. yAxis: {
  155. type: 'value',
  156. },
  157. series: [
  158. {
  159. data: scoreInfoList.value.map((item) => item.score),
  160. type: 'bar',
  161. },
  162. ],
  163. dataZoom: scoreInfoList.value.length > 9 ? dataZoomConfig.value : null,
  164. // 启用数据区域缩放
  165. };
  166. });
  167. const changeTime = () => {
  168. switch (timeSelect.value) {
  169. case TimeEnum.DAY:
  170. getDailyScoreList();
  171. break;
  172. case TimeEnum.WEEK:
  173. getWeeklyScoreList();
  174. break;
  175. case TimeEnum.MONTH:
  176. getMonthlyScoreList();
  177. break;
  178. case TimeEnum.QUARTER:
  179. getQuarterlyScoreList();
  180. break;
  181. }
  182. };
  183. </script>
  184. <style scoped>
  185. .score-layout {
  186. display: flex;
  187. }
  188. .score-left {
  189. display: flex;
  190. /* width: 965px; */
  191. flex-grow: 1;
  192. flex-direction: column;
  193. }
  194. .score-right {
  195. width: 158px;
  196. flex-shrink: 0;
  197. }
  198. .score-header {
  199. display: flex;
  200. justify-content: space-between;
  201. height: 50px;
  202. }
  203. .score-show {
  204. flex-grow: 1;
  205. /* width: calc(100% - 660px); */
  206. width: 100%;
  207. min-width: 500px;
  208. overflow-x: auto;
  209. }
  210. .score-title {
  211. font-size: 16px;
  212. margin-top: 17px;
  213. margin-left: 18px;
  214. }
  215. .score-select {
  216. /* flex-grow: 1; */
  217. margin-right: 10px;
  218. }
  219. .score-divider {
  220. width: 1px;
  221. background: #e9e9e9;
  222. }
  223. .el-divider--horizontal {
  224. margin: 0px;
  225. }
  226. .pic-show {
  227. flex-grow: 1;
  228. }
  229. .concern-title {
  230. margin-left: 20px;
  231. margin-top: 51px;
  232. font-size: 14px;
  233. }
  234. .concern-workspace {
  235. margin-left: 23px;
  236. margin-top: 24px;
  237. font-size: 14px;
  238. color: rgba(0, 0, 0, 0.65);
  239. }
  240. li {
  241. margin-bottom: 16px;
  242. }
  243. li:before {
  244. content: '•';
  245. color: red;
  246. display: inline-block;
  247. margin-right: 20px;
  248. width: 8px;
  249. height: 8px;
  250. font-size: 16px;
  251. line-height: 1;
  252. }
  253. .score-tip {
  254. display: flex;
  255. margin-top: 20px;
  256. margin-left: 14px;
  257. }
  258. .tip-content {
  259. margin-left: 16px;
  260. margin-right: 14px;
  261. color: rgba(0, 0, 0, 0.45);
  262. font-size: 10px;
  263. }
  264. .pic-none {
  265. display: flex;
  266. justify-content: center;
  267. align-items: center;
  268. height: 100%;
  269. font-size: 20px;
  270. }
  271. </style>