ReportIndicatorChartWidget.vue 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. <script setup lang="ts">
  2. import type { ReportIndicatorModel } from '@/model';
  3. import type { LineSeriesOption } from 'echarts/charts';
  4. import { LineChart } from 'echarts/charts';
  5. import type {
  6. GridComponentOption,
  7. LegendComponentOption,
  8. MarkLineComponentOption,
  9. TitleComponentOption,
  10. TooltipComponentOption,
  11. } from 'echarts/components';
  12. import {
  13. GridComponent,
  14. LegendComponent,
  15. MarkLineComponent,
  16. TitleComponent,
  17. TooltipComponent,
  18. VisualMapComponent,
  19. } from 'echarts/components';
  20. import { use } from 'echarts/core';
  21. import { CanvasRenderer } from 'echarts/renderers';
  22. import VChart from 'vue-echarts';
  23. use([
  24. CanvasRenderer,
  25. LineChart, MarkLineComponent,
  26. GridComponent, VisualMapComponent,
  27. TitleComponent, TooltipComponent, LegendComponent,
  28. ]);
  29. const props = defineProps<{
  30. dataset: ReportIndicatorModel;
  31. loading?: boolean;
  32. }>();
  33. const emits = defineEmits<{
  34. destroy: []
  35. }>();
  36. const option = ref({
  37. title: { text: '', top: 12, left: 'center' } as TitleComponentOption,
  38. tooltip: { trigger: 'axis' } as TooltipComponentOption,
  39. legend: { show: false, top: 12, right: 24 } as LegendComponentOption,
  40. grid: { top: 60, bottom: 24, left: 40, right: 60, containLabel: true } as GridComponentOption,
  41. xAxis: { type: 'category' } as any,
  42. yAxis: { type: 'value', scale: true, splitNumber: 10 } as any,
  43. visualMap: {
  44. pieces: [],
  45. show: false,
  46. type: 'piecewise',
  47. } as any,
  48. series: [] as ( LineSeriesOption & MarkLineComponentOption )[],
  49. });
  50. watchEffect(() => update(props.dataset));
  51. function update(data: ReportIndicatorModel) {
  52. const range = data.range.map(t => +t);
  53. let min = range[ 0 ], max = range[ 1 ], source = [];
  54. const records = [ ...data.records ].reverse();
  55. for ( const { time, value } of records ) {
  56. source.push(time.format('YYYY/MM/DD'), value);
  57. min = Math.min(min, value);
  58. max = Math.max(max, value);
  59. }
  60. option.value.title.text = data.name;
  61. option.value.yAxis.name = data.unit;
  62. option.value.yAxis.min = Math.max(data.editor.min, Math.floor(min * 0.75));
  63. option.value.yAxis.max = Math.min(data.editor.max, Math.floor(max * 1.25));
  64. option.value.yAxis.minInterval = data.editor.step ?? 1;
  65. option.value.visualMap.pieces = [
  66. { gt: range[ 1 ], color: '#fc97af' },
  67. { gte: range[ 0 ], lte: range[ 1 ], color: '#72ccff' },
  68. { lt: range[ 0 ], color: '#fc97af' },
  69. ];
  70. option.value.series = [
  71. {
  72. name: data.name, smooth: true, type: 'line',
  73. data: records.map((record) => [ record.time.format('YYYY/MM/DD'), record.value ]),
  74. markLine: {
  75. data: data.range.map(value => (
  76. { yAxis: value }
  77. )),
  78. },
  79. },
  80. ];
  81. }
  82. </script>
  83. <template>
  84. <v-chart class="chart-container" :option="option" :autoresize="true" />
  85. </template>
  86. <style scoped lang="scss">
  87. .chart-container {
  88. width: 100%;
  89. height: 100%;
  90. }
  91. </style>