Commit 4d78bfbdaa59e2f37ef4faa36aab0dc543f43c46

Authored by fengwotao
1 parent 4b3a9162

perf(src/packages): 优化封装ws数据格式hook

  1 +/**
  2 + * 此hook的作用是 ws 组装图表需要的数据格式
  3 + * @param data {'wendu':[[xxxxxx,xxxx]]}
  4 + * @returns keys:[xx,xx,xx] record:{'x':'xx'}
  5 + */
  6 +import dayjs from 'dayjs'
  7 +
  8 +export const useAssembleDataHooks = (data: Record<string, string | [number, string]>) => {
  9 + const formatValueToNumber = (value: string | number, defaultValue = 0) =>
  10 + isNaN(value as number) ? defaultValue : Number(value)
  11 +
  12 + const keys = Object.keys(data)
  13 +
  14 + const record = keys.reduce((prev, next) => {
  15 + const [latest] = data[next] || []
  16 + const [ts, value] = latest as unknown as string[]
  17 + //把值转为number类型 wendu:"23" 转为 wendu:23
  18 + return { ...prev, ts: dayjs(ts).format('YYYY-MM-DD HH:mm:ss'), [next]: formatValueToNumber(value) }
  19 + }, {})
  20 +
  21 + return {
  22 + keys,
  23 + record
  24 + }
  25 +}
... ...
1 1 <template>
2 2 <v-chart
3   - ref="vChartRef"
4   - :init-options="initOptions"
5   - :theme="themeColor"
6   - :option="option"
7   - :manual-update="isPreview()"
8   - :update-options="{
  3 + ref="vChartRef"
  4 + :init-options="initOptions"
  5 + :theme="themeColor"
  6 + :option="option"
  7 + :manual-update="isPreview()"
  8 + :update-options="{
9 9 replaceMerge: replaceMergeArr
10 10 }"
11   - autoresize
12   - @mouseover="handleHighlight"
13   - @mouseout="handleDownplay"
  11 + autoresize
  12 + @mouseover="handleHighlight"
  13 + @mouseout="handleDownplay"
14 14 >
15 15 </v-chart>
16 16 </template>
17 17
18 18 <script setup lang="ts">
19   -import {ref, nextTick, computed, watch, PropType, onMounted} from 'vue'
  19 +import { ref, nextTick, computed, watch, PropType, onMounted } from 'vue'
20 20 import VChart from 'vue-echarts'
21   -import {useCanvasInitOptions} from '@/hooks/useCanvasInitOptions.hook'
22   -import {use} from 'echarts/core'
23   -import {CanvasRenderer} from 'echarts/renderers'
24   -import {BarChart} from 'echarts/charts'
25   -import config, {includes, seriesItem} from './config'
26   -import {mergeTheme} from '@/packages/public/chart'
27   -import {useChartDataFetch} from '@/hooks'
28   -import {CreateComponentType} from '@/packages/index.d'
29   -import {useChartEditStore} from '@/store/modules/chartEditStore/chartEditStore'
30   -import {isPreview} from '@/utils'
31   -import {DatasetComponent, GridComponent, TooltipComponent, LegendComponent} from 'echarts/components'
  21 +import { useCanvasInitOptions } from '@/hooks/useCanvasInitOptions.hook'
  22 +import { use } from 'echarts/core'
  23 +import { CanvasRenderer } from 'echarts/renderers'
  24 +import { BarChart } from 'echarts/charts'
  25 +import config, { includes, seriesItem } from './config'
  26 +import { mergeTheme } from '@/packages/public/chart'
  27 +import { useChartDataFetch } from '@/hooks'
  28 +import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
  29 +import { isPreview } from '@/utils'
  30 +import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent } from 'echarts/components'
32 31 import isObject from 'lodash/isObject'
33 32 import dataJson from './data.json'
34   -import {useFullScreen} from '../../utls/fullScreen'
  33 +import { useFullScreen } from '../../utls/fullScreen'
  34 +import cloneDeep from 'lodash/cloneDeep'
  35 +import { useAssembleDataHooks } from '@/hooks/external/useAssembleData.hook'
  36 +import { SocketReceiveMessageType } from '@/store/external/modules/socketStore.d'
35 37
36 38 const props = defineProps({
37 39 themeSetting: {
... ... @@ -77,33 +79,46 @@ const toolBoxOption = {
77 79 }
78 80 props.chartConfig.option = {
79 81 ...props.chartConfig.option,
80   - ...{toolbox: toolBoxOption}
  82 + ...{ toolbox: toolBoxOption }
81 83 }
82 84
83 85 // dataset 无法变更条数的补丁
84 86 watch(
85   - () => props.chartConfig.option.dataset,
86   - (newData: { dimensions: any }, oldData) => {
87   - try {
88   - if (!isObject(newData) || !('dimensions' in newData)) return
89   - if (Array.isArray(newData?.dimensions)) {
90   - const seriesArr = []
91   - for (let i = 0; i < newData.dimensions.length - 1; i++) {
92   - seriesArr.push(seriesItem)
  87 + () => props.chartConfig.option.dataset,
  88 + (newData: { dimensions: any }, oldData) => {
  89 + try {
  90 + if (!isObject(newData) || !('dimensions' in newData)) return
  91 + if (Array.isArray(newData?.dimensions)) {
  92 + const seriesArr = []
  93 + // 对oldData进行判断,防止传入错误数据之后对旧维度判断产生干扰
  94 + // 此处计算的是dimensions的Y轴维度,若是dimensions.length为0或1,则默认为1,排除X轴维度干扰
  95 + const oldDimensions =
  96 + Array.isArray(oldData?.dimensions) && oldData.dimensions.length >= 1 ? oldData.dimensions.length : 1
  97 + const newDimensions = newData.dimensions.length >= 1 ? newData.dimensions.length : 1
  98 + const dimensionsGap = newDimensions - oldDimensions
  99 + if (dimensionsGap < 0) {
  100 + props.chartConfig.option.series.splice(newDimensions - 1)
  101 + } else if (dimensionsGap > 0) {
  102 + if (!oldData || !oldData?.dimensions || !Array.isArray(oldData?.dimensions) || !oldData?.dimensions.length) {
  103 + props.chartConfig.option.series = []
93 104 }
94   - replaceMergeArr.value = ['series']
95   - props.chartConfig.option.series = seriesArr
96   - nextTick(() => {
97   - replaceMergeArr.value = []
98   - })
  105 + for (let i = 0; i < dimensionsGap; i++) {
  106 + seriesArr.push(cloneDeep(seriesItem))
  107 + }
  108 + props.chartConfig.option.series.push(...seriesArr)
99 109 }
100   - } catch (error) {
101   - console.log(error)
  110 + replaceMergeArr.value = ['series']
  111 + nextTick(() => {
  112 + replaceMergeArr.value = []
  113 + })
102 114 }
103   - },
104   - {
105   - deep: false
  115 + } catch (error) {
  116 + console.log(error)
106 117 }
  118 + },
  119 + {
  120 + deep: false
  121 + }
107 122 )
108 123
109 124 let seriesDataNum = -1
... ... @@ -167,30 +182,51 @@ const handleDownplay = () => {
167 182 }
168 183
169 184 watch(
170   - () => props.chartConfig.option.isCarousel,
171   - newData => {
172   - if (newData) {
173   - addPieInterval(undefined, true)
174   - props.chartConfig.option.legend.show = false
175   - } else {
176   - props.chartConfig.option.legend.show = true
177   - clearPieInterval()
178   - }
  185 + () => props.chartConfig.option.isCarousel,
  186 + newData => {
  187 + if (newData) {
  188 + addPieInterval(undefined, true)
  189 + props.chartConfig.option.legend.show = false
  190 + } else {
  191 + props.chartConfig.option.legend.show = true
  192 + clearPieInterval()
179 193 }
  194 + }
180 195 )
181 196
182 197 //fix 修复v-chart图表绑定联动组件视图不更新问题
183   -const updateVChart = (newData: any) => {
184   - if (!newData) return
185   - vChartRef.value?.clear()
186   - vChartRef.value?.setOption({
187   - ...option.value,
188   - dataset: newData
189   - })
  198 +const updateVChart = (newData:SocketReceiveMessageType) => {
  199 + //区分是普通请求还是ws请求
  200 + if (!isObject(newData) || !('dimensions' in newData)) {
  201 + const { data } = newData
  202 + const { keys, record } = useAssembleDataHooks(data)
  203 + vChartRef.value?.setOption({
  204 + dataset: {
  205 + dimensions: ['ts', ...keys],
  206 + source: [record]
  207 + }
  208 + })
  209 + } else {
  210 + //异步更新,同步更新会造成联动组件控制,图表不及时更新
  211 + new Promise((resolve) => {
  212 + setTimeout(() => {
  213 + resolve(
  214 + vChartRef.value?.setOption(
  215 + {
  216 + ...option.value,
  217 + dataset: newData
  218 + },
  219 + {
  220 + notMerge: true
  221 + }
  222 + )
  223 + )
  224 + }, 100)
  225 + })
  226 + }
190 227 }
191 228
192   -const {vChartRef} = useChartDataFetch(props.chartConfig, useChartEditStore, (newData) => {
193   - // addPieInterval(newData)
  229 +const { vChartRef } = useChartDataFetch(props.chartConfig, useChartEditStore, newData => {
194 230 updateVChart(newData)
195 231 })
196 232
... ...
... ... @@ -31,7 +31,7 @@ import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent } fr
31 31 import dataJson from './data.json'
32 32 import { useFullScreen } from '../../utls/fullScreen'
33 33 import { SocketReceiveMessageType } from '@/store/external/modules/socketStore.d'
34   -import dayjs from 'dayjs'
  34 +import { useAssembleDataHooks } from '@/hooks/external/useAssembleData.hook'
35 35
36 36 const props = defineProps({
37 37 themeSetting: {
... ... @@ -161,20 +161,11 @@ watch(
161 161 }
162 162 )
163 163
164   -const formatValueToNumber = (value: string | number, defaultValue = 0) =>
165   - isNaN(value as number) ? defaultValue : Number(value)
166   -
167 164 //fix 修复v-chart图表绑定联动组件视图不更新问题
168 165 const updateVChart = (newData: SocketReceiveMessageType) => {
169 166 if (!newData) return
170 167 const { data } = newData
171   - const keys = Object.keys(data)
172   - const record = keys.reduce((prev, next) => {
173   - const [latest] = data[next] || []
174   - const [ts, value] = latest as unknown as string[]
175   - return { ...prev, ts: dayjs(ts).format('YYYY-MM-DD HH:mm:ss'), [next]: formatValueToNumber(value) }
176   - // return { ...prev, ts, [next]: formatValueToNumber(value) }
177   - }, {})
  168 + const {keys,record}= useAssembleDataHooks(data)
178 169 if (unref(realTimeList).length >= chartMaxDataPoint.value) {
179 170 unref(realTimeList).splice(0, 1)
180 171 }
... ...