chart.vue 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. <template>
  2. <div class="system-edit-dic-container">
  3. <el-dialog v-model="isShowDialog" title="数据记录" width="850px">
  4. <!-- 这里是 echarts 线图 -->
  5. <div id="lineChart" ref="chartRef" class="chart-container"></div>
  6. </el-dialog>
  7. </div>
  8. </template>
  9. <script lang="ts" setup>
  10. import { ref, onMounted, watch, nextTick } from 'vue'
  11. import api from '/@/api/device'
  12. import * as echarts from 'echarts'
  13. const loading = ref(false)
  14. const isShowDialog = ref(false)
  15. const chartRef = ref<HTMLElement | null>(null)
  16. let chartInstance: echarts.ECharts | null = null
  17. const lineData = ref([])
  18. // 初始化图表
  19. const initChart = () => {
  20. if (chartRef.value) {
  21. // 如果已有实例先销毁
  22. if (chartInstance) {
  23. chartInstance.dispose()
  24. }
  25. // 创建图表实例
  26. chartInstance = echarts.init(chartRef.value)
  27. // 设置加载状态
  28. if (loading.value) {
  29. chartInstance.showLoading()
  30. } else {
  31. chartInstance.hideLoading()
  32. }
  33. // 更新图表
  34. updateChart()
  35. }
  36. }
  37. // 更新图表数据
  38. const updateChart = () => {
  39. if (!chartInstance) return
  40. // 从 lineData 中提取数据
  41. const xData = lineData.value.map((item: any) => item.ts?.slice(5)).reverse()
  42. const yData = lineData.value.map((item: any) => item.value).reverse()
  43. // 配置图表选项
  44. const option = {
  45. tooltip: {
  46. trigger: 'axis',
  47. formatter: '{b}<br />{a}: {c}',
  48. },
  49. grid: {
  50. top: 15,
  51. left: 40,
  52. right: 30,
  53. bottom: 50, // 增加底部空间,为 dataZoom 留出位置
  54. containLabel: true,
  55. },
  56. dataZoom: [
  57. {
  58. type: 'slider', // 滑动条型数据区域缩放组件
  59. show: true,
  60. start: 0,
  61. end: 100,
  62. height: 20,
  63. bottom: 10,
  64. borderColor: 'transparent',
  65. backgroundColor: '#f5f5f5',
  66. fillerColor: 'rgba(167, 183, 204, 0.4)',
  67. handleIcon:
  68. 'M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z',
  69. handleSize: '80%',
  70. handleStyle: {
  71. color: '#fff',
  72. shadowBlur: 3,
  73. shadowColor: 'rgba(0, 0, 0, 0.6)',
  74. shadowOffsetX: 2,
  75. shadowOffsetY: 2,
  76. },
  77. },
  78. {
  79. type: 'inside', // 内置型数据区域缩放组件,允许鼠标滚轮或触摸板缩放
  80. start: 0,
  81. end: 100,
  82. },
  83. ],
  84. xAxis: {
  85. type: 'category',
  86. data: xData,
  87. axisLabel: {
  88. rotate: 0,
  89. },
  90. },
  91. yAxis: {
  92. type: 'value',
  93. },
  94. series: [
  95. {
  96. name: '数值',
  97. type: 'line',
  98. data: yData,
  99. smooth: true,
  100. lineStyle: {
  101. width: 2,
  102. },
  103. symbolSize: 6,
  104. },
  105. ],
  106. }
  107. // 设置图表配置
  108. chartInstance.setOption(option)
  109. }
  110. // 监听数据变化,更新图表
  111. watch(
  112. () => lineData.value,
  113. () => {
  114. nextTick(() => {
  115. updateChart()
  116. })
  117. },
  118. { deep: true }
  119. )
  120. // 监听 loading 状态变化
  121. watch(
  122. () => loading.value,
  123. (newVal) => {
  124. if (chartInstance) {
  125. if (newVal) {
  126. chartInstance.showLoading()
  127. } else {
  128. chartInstance.hideLoading()
  129. }
  130. }
  131. }
  132. )
  133. // 监听弹窗显示状态
  134. watch(
  135. () => isShowDialog.value,
  136. (val) => {
  137. if (val) {
  138. nextTick(() => {
  139. initChart()
  140. })
  141. }
  142. }
  143. )
  144. // 打开弹窗
  145. const openDialog = (row: any, deviceKey: string) => {
  146. isShowDialog.value = true
  147. loading.value = true
  148. api.instance
  149. .getLogDetail({
  150. deviceKey: deviceKey,
  151. propertyKey: row.key,
  152. pageSize: 100,
  153. })
  154. .then((res: any) => {
  155. lineData.value = res.List
  156. console.log(res.List)
  157. })
  158. .finally(() => (loading.value = false))
  159. }
  160. defineExpose({ openDialog })
  161. </script>
  162. <style scoped>
  163. .chart-container {
  164. width: 100%;
  165. height: 400px;
  166. }
  167. </style>