Commit 4d78bfbdaa59e2f37ef4faa36aab0dc543f43c46
1 parent
4b3a9162
perf(src/packages): 优化封装ws数据格式hook
Showing
3 changed files
with
122 additions
and
70 deletions
src/hooks/external/useAssembleData.hook.ts
0 → 100644
| 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 | <template> | 1 | <template> |
| 2 | <v-chart | 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 | replaceMerge: replaceMergeArr | 9 | replaceMerge: replaceMergeArr |
| 10 | }" | 10 | }" |
| 11 | - autoresize | ||
| 12 | - @mouseover="handleHighlight" | ||
| 13 | - @mouseout="handleDownplay" | 11 | + autoresize |
| 12 | + @mouseover="handleHighlight" | ||
| 13 | + @mouseout="handleDownplay" | ||
| 14 | > | 14 | > |
| 15 | </v-chart> | 15 | </v-chart> |
| 16 | </template> | 16 | </template> |
| 17 | 17 | ||
| 18 | <script setup lang="ts"> | 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 | import VChart from 'vue-echarts' | 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 | import isObject from 'lodash/isObject' | 31 | import isObject from 'lodash/isObject' |
| 33 | import dataJson from './data.json' | 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 | const props = defineProps({ | 38 | const props = defineProps({ |
| 37 | themeSetting: { | 39 | themeSetting: { |
| @@ -77,33 +79,46 @@ const toolBoxOption = { | @@ -77,33 +79,46 @@ const toolBoxOption = { | ||
| 77 | } | 79 | } |
| 78 | props.chartConfig.option = { | 80 | props.chartConfig.option = { |
| 79 | ...props.chartConfig.option, | 81 | ...props.chartConfig.option, |
| 80 | - ...{toolbox: toolBoxOption} | 82 | + ...{ toolbox: toolBoxOption } |
| 81 | } | 83 | } |
| 82 | 84 | ||
| 83 | // dataset 无法变更条数的补丁 | 85 | // dataset 无法变更条数的补丁 |
| 84 | watch( | 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 | let seriesDataNum = -1 | 124 | let seriesDataNum = -1 |
| @@ -167,30 +182,51 @@ const handleDownplay = () => { | @@ -167,30 +182,51 @@ const handleDownplay = () => { | ||
| 167 | } | 182 | } |
| 168 | 183 | ||
| 169 | watch( | 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 | //fix 修复v-chart图表绑定联动组件视图不更新问题 | 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 | updateVChart(newData) | 230 | updateVChart(newData) |
| 195 | }) | 231 | }) |
| 196 | 232 |
| @@ -31,7 +31,7 @@ import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent } fr | @@ -31,7 +31,7 @@ import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent } fr | ||
| 31 | import dataJson from './data.json' | 31 | import dataJson from './data.json' |
| 32 | import { useFullScreen } from '../../utls/fullScreen' | 32 | import { useFullScreen } from '../../utls/fullScreen' |
| 33 | import { SocketReceiveMessageType } from '@/store/external/modules/socketStore.d' | 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 | const props = defineProps({ | 36 | const props = defineProps({ |
| 37 | themeSetting: { | 37 | themeSetting: { |
| @@ -161,20 +161,11 @@ watch( | @@ -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 | //fix 修复v-chart图表绑定联动组件视图不更新问题 | 164 | //fix 修复v-chart图表绑定联动组件视图不更新问题 |
| 168 | const updateVChart = (newData: SocketReceiveMessageType) => { | 165 | const updateVChart = (newData: SocketReceiveMessageType) => { |
| 169 | if (!newData) return | 166 | if (!newData) return |
| 170 | const { data } = newData | 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 | if (unref(realTimeList).length >= chartMaxDataPoint.value) { | 169 | if (unref(realTimeList).length >= chartMaxDataPoint.value) { |
| 179 | unref(realTimeList).splice(0, 1) | 170 | unref(realTimeList).splice(0, 1) |
| 180 | } | 171 | } |