BarAndLine.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. <template>
  2. <div v-if="spinning" class="spinning">
  3. <a-spin :spinning="true" />
  4. </div>
  5. <div v-if="!spinning" ref="chartRef" :style="{ height, width }"></div>
  6. </template>
  7. <script lang="ts">
  8. import { defineComponent, PropType, ref, Ref, reactive, watchEffect, watch, nextTick } from 'vue';
  9. import { useECharts } from '/@/hooks/web/useECharts';
  10. import { getTableHeaderColumns } from '/@/hooks/web/useWebColumns';
  11. import EchartsUtil from '/@/utils/echartsUtil';
  12. import { merge } from 'lodash-es';
  13. type ChartColumn = {
  14. legend: string;
  15. seriesName: string;
  16. ymax: number;
  17. yname: string;
  18. linetype: string;
  19. yaxispos: string;
  20. color: string;
  21. sort: number;
  22. xRotate: number;
  23. dataIndex: string;
  24. };
  25. export default defineComponent({
  26. name: 'BarAndLine',
  27. props: {
  28. chartsColumns: {
  29. type: Array as PropType<ChartColumn[]>,
  30. default: () => [],
  31. },
  32. chartsColumnsType: {
  33. type: String,
  34. },
  35. chartsType: {
  36. type: String,
  37. default: '',
  38. },
  39. dataSource: {
  40. type: Array,
  41. default: () => [],
  42. },
  43. option: {
  44. type: Object,
  45. default: () => ({}),
  46. },
  47. xAxisPropType: {
  48. type: String,
  49. required: true,
  50. },
  51. width: {
  52. type: String as PropType<string>,
  53. default: '100%',
  54. },
  55. height: {
  56. type: String as PropType<string>,
  57. default: 'calc(100vh - 78px)',
  58. },
  59. },
  60. emits: ['refresh'],
  61. setup(props, { emit }) {
  62. const spinning = ref<boolean>(true);
  63. const chartRef = ref<HTMLDivElement | null>(null);
  64. const { setOptions, echarts } = useECharts(chartRef as Ref<HTMLDivElement>);
  65. const chartData = props.chartsColumnsType ? getTableHeaderColumns(props.chartsColumnsType) : [];
  66. let chartsColumns = (props.chartsColumns.length > 0 ? props.chartsColumns : chartData) as ChartColumn[];
  67. let tempYmax: number[] = [];
  68. let tempYmin: number[] = [];
  69. // let groupedByColumns = {};
  70. const option = reactive({
  71. name: '',
  72. color: ['#7B68EE', '#0000CD', '#6495ED', '#00BFFF', '#AFEEEE', '#008080', '#00FA9A', '#2E8B57', '#FAFAD2', '#DAA520'],
  73. tooltip: {},
  74. grid: {},
  75. toolbox: {
  76. feature: {
  77. saveAsImage: {
  78. iconStyle: {
  79. borderColor: '#ffffff',
  80. },
  81. show: false,
  82. },
  83. },
  84. },
  85. dataZoom: {},
  86. legend: {
  87. textStyle: {
  88. color: '#ffffff', // 字体颜色
  89. },
  90. top: '20',
  91. },
  92. timeline: null,
  93. xAxis: {},
  94. yAxis: null,
  95. series: null,
  96. });
  97. let optionUtil;
  98. watchEffect(() => {
  99. props.dataSource && props.xAxisPropType && option.series && initCharts();
  100. });
  101. watch([() => props.chartsType, () => props.chartsColumns], ([newChartsType, newChartsColumns]) => {
  102. spinning.value = true;
  103. chartsColumns = newChartsColumns;
  104. optionUtil.initChartOption(newChartsType, newChartsColumns);
  105. spinning.value = false;
  106. initCharts(true);
  107. emit('refresh');
  108. });
  109. function initChartsOption() {
  110. // debugger;
  111. optionUtil = new EchartsUtil(merge(option, props.option));
  112. optionUtil.initChartOption(props.chartsType, chartsColumns);
  113. }
  114. initChartsOption();
  115. function initCharts(isRefresh = false) {
  116. if (props.dataSource.length < 1) return;
  117. //轴数据
  118. let isFresh = false;
  119. if (option.series && option.series.length === chartsColumns.length) {
  120. let xAxisData = props.dataSource.map((item) => item[props.xAxisPropType]);
  121. chartsColumns = [...chartsColumns].filter((propType: any, index) => {
  122. if (!propType) return;
  123. if (props.chartsType == 'listMonitor') {
  124. option.series[index].type = 'bar';
  125. }
  126. console.log(option.series[index], '000===');
  127. option.series[index].data = props.dataSource.map((item) => Number(item[propType.dataIndex]) || 0);
  128. debugger;
  129. // console.log('nnn', option.series[index].data);
  130. // 这里动态计算echarts y轴最大值
  131. const max = Math.max(...option.series[index].data);
  132. const min = Math.min(...option.series[index].data);
  133. const digitCount = Math.ceil(Number(max));
  134. const minDigitCount = Math.floor(Number(min));
  135. // if (props.chartsType === 'history') {
  136. // const disLen = Math.abs(max - min);
  137. // propType.ymax = digitCount + disLen / 3;
  138. // propType.ymin = minDigitCount - disLen / 3 > 0 || minDigitCount < 0 ? minDigitCount - disLen / 3 : 0;
  139. // } else {
  140. // let yMax = 0,
  141. // yMin = 0;
  142. // if (digitCount < 2) {
  143. // if (max < 0.5) {
  144. // yMax = 1;
  145. // } else if (max < 0.9) {
  146. // yMax = 1.5;
  147. // } else if (max < 5) {
  148. // yMax = 5;
  149. // } else if (max < 10) {
  150. // yMax = 10;
  151. // }
  152. // } else if (digitCount < 3) {
  153. // const n = Number((Number(max.toFixed(0)) / 10).toFixed(0));
  154. // if (max < n * 10 + 5) {
  155. // yMax = (n + 1) * 10;
  156. // } else {
  157. // yMax = (n + 2) * 10;
  158. // }
  159. // } else if (digitCount < 4) {
  160. // const n = Number((Number(max.toFixed(0)) / 100).toFixed(0));
  161. // if (max < n * 100 + 50) {
  162. // yMax = (n + 1) * 100;
  163. // } else {
  164. // yMax = (n + 2) * 100;
  165. // }
  166. // } else if (digitCount < 5) {
  167. // const n = Number((Number(max.toFixed(0)) / 1000).toFixed(0));
  168. // if (max < n * 1000 + 500) {
  169. // yMax = (n + 1) * 1000;
  170. // } else {
  171. // yMax = (n + 1) * 1000 + 500;
  172. // }
  173. // } else if (digitCount < 6) {
  174. // const n = Number((Number(max.toFixed(0)) / 10000).toFixed(0));
  175. // if (max < n * 10000 + 5000) {
  176. // yMax = (n + 1) * 10000;
  177. // } else {
  178. // yMax = (n + 1) * 10000 + 5000;
  179. // }
  180. // }
  181. // if (minDigitCount < 2) {
  182. // if (min > 1.5) {
  183. // yMin = 1.0;
  184. // } else if (min > 5) {
  185. // yMin = 5;
  186. // } else {
  187. // yMin = 0;
  188. // }
  189. // } else if (minDigitCount < 3) {
  190. // const n = Number((Number(min.toFixed(0)) / 10).toFixed(0));
  191. // if (n > 1) {
  192. // yMin = (n - 1) * 10;
  193. // } else {
  194. // yMin = 10;
  195. // }
  196. // } else if (digitCount < 4) {
  197. // const n = Number((Number(min.toFixed(0)) / 100).toFixed(0));
  198. // if (n > 1) {
  199. // yMin = (n - 1) * 100;
  200. // } else {
  201. // yMin = 100;
  202. // }
  203. // } else if (digitCount < 5) {
  204. // const n = Number((Number(min.toFixed(0)) / 1000).toFixed(0));
  205. // if (n > 1) {
  206. // yMin = (n - 1) * 1000;
  207. // } else {
  208. // yMin = 1000;
  209. // }
  210. // } else if (digitCount < 6) {
  211. // const n = Number((Number(min.toFixed(0)) / 10000).toFixed(0));
  212. // if (n > 1) {
  213. // yMin = (n - 1) * 10000;
  214. // } else {
  215. // yMin = 10000;
  216. // }
  217. // }
  218. // propType.ymax = yMax;
  219. // propType.ymin = yMin;
  220. // }
  221. const disLen = Math.abs(max - min);
  222. if (propType.ymax && propType.ymin >= 0) {
  223. if (max > propType.ymax || min < propType.ymin) {
  224. propType.ymax = digitCount + disLen / 3;
  225. propType.ymin = minDigitCount - disLen / 3 > 0 || minDigitCount < 0 ? minDigitCount - disLen / 3 : 0;
  226. } else {
  227. propType.ymax = digitCount + digitCount / 4;
  228. propType.ymin = minDigitCount - digitCount / 4;
  229. }
  230. } else {
  231. propType.ymax = digitCount + disLen / 3;
  232. propType.ymin = minDigitCount - disLen / 3 > 0 || minDigitCount < 0 ? minDigitCount - disLen / 3 : 0;
  233. }
  234. if (propType.ymax == propType.ymin && propType.ymin == 0) {
  235. propType.ymax = 10;
  236. }
  237. return true;
  238. });
  239. // debugger;
  240. // 根据sort分组
  241. const groupedBy = {};
  242. for (const item of chartsColumns) {
  243. if (groupedBy[item.sort]) {
  244. groupedBy[item.sort].push(item);
  245. } else {
  246. groupedBy[item.sort] = [item];
  247. }
  248. }
  249. // 根据分组找ymax最大值
  250. const newChartsColumns: ChartColumn[] = [];
  251. let index = 0;
  252. for (let sortId in groupedBy) {
  253. const group = groupedBy[sortId];
  254. let ymax = group[0].ymax;
  255. let ymin = group[0].ymin;
  256. for (let i = 1; i < group.length; i++) {
  257. if (group[i].ymax > ymax) {
  258. ymax = group[i].ymax;
  259. }
  260. }
  261. for (let i = 1; i < group.length; i++) {
  262. if (group[i].ymin < ymin) {
  263. ymin = group[i].ymin;
  264. }
  265. }
  266. if (!tempYmax[index] || tempYmax[index] != ymax) {
  267. tempYmax[index] = ymax;
  268. isFresh = true;
  269. }
  270. if (tempYmin[index] != ymin) {
  271. tempYmin[index] = ymin;
  272. isFresh = true;
  273. }
  274. for (let i = 0; i < group.length; i++) {
  275. group[i].ymax = ymax;
  276. group[i].ymin = ymin;
  277. newChartsColumns.push(group[i]);
  278. }
  279. ++index;
  280. }
  281. chartsColumns = newChartsColumns;
  282. option.xAxis[0].data = xAxisData;
  283. if (isFresh) {
  284. spinning.value = true;
  285. optionUtil.initChartOption(props.chartsType, chartsColumns);
  286. spinning.value = false;
  287. initCharts(true);
  288. nextTick(() => {
  289. setOptions(option, true);
  290. emit('refresh');
  291. });
  292. } else {
  293. // console.log('echarts监测列表数据', option.xAxis[0].data);
  294. setOptions(option, isRefresh);
  295. }
  296. setOptions(option, isRefresh);
  297. }
  298. }
  299. setTimeout(() => {
  300. spinning.value = false;
  301. initCharts(true);
  302. }, 1000);
  303. return { chartRef, spinning };
  304. },
  305. });
  306. </script>
  307. <style lang="less" scoped>
  308. .spinning {
  309. display: flex;
  310. width: 100%;
  311. height: 100%;
  312. justify-content: center;
  313. align-items: center;
  314. }
  315. </style>