From 46df470bbba226da5224d9adc1c47ecfadf11e1d Mon Sep 17 00:00:00 2001 From: wujingjing <gersonwu@qq.com> Date: 星期四, 18 七月 2024 14:21:01 +0800 Subject: [PATCH] chart resize --- src/directive/customDirective.ts | 34 ++++++++ src/components/chat/Chat.vue | 63 ++++++++------- src/components/chat/chatComponents/recordSetCom/RecordSetCom.vue | 26 +++++- src/hooks/usePageDisplay.ts | 23 +++++ src/directive/index.ts | 4 src/components/chat/chatComponents/summaryCom/SummaryCom.vue | 40 ++++++++-- 6 files changed, 145 insertions(+), 45 deletions(-) diff --git a/src/components/chat/Chat.vue b/src/components/chat/Chat.vue index 8783ac6..7088f2e 100644 --- a/src/components/chat/Chat.vue +++ b/src/components/chat/Chat.vue @@ -9,48 +9,49 @@ :key="index" > <img - class="rounded-full size-12 mr-4" + class="rounded-full size-12 flex-0" :class="{ 'mr-4': item.role === RoleEnum.assistant, 'ml-4': item.role === RoleEnum.user }" :src="roleImageMap[item.role]" alt="" srcset="" /> - - <div class="inline-flex flex-col" :class="{ 'w-full': item.role === RoleEnum.assistant }"> - <div class="relative w-full" v-if="item.content?.values"> - <div - class="text-sm rounded-[6px] p-4 leading-relaxed" - :style="{ backgroundColor: item.role === RoleEnum.user ? 'rgb(197 224 255)' : 'white' }" - > - <div v-if="item.content.errCode === ErrorCode.Message" class="text-red-500 w-full">{{ item.content.msg }}</div> - <component v-else :is="answerTypeMapCom[item.content.type]" :data="item.content.values" /> - </div> - - <div v-if="item.role === RoleEnum.assistant" class="absolute flex items-center right-0 mr-2 mt-2 space-x-2"> + <div class="flex-auto flex" :class="{'justify-end':item.role===RoleEnum.user}"> + <div class="inline-flex flex-col" :class="{ 'w-full': item.role === RoleEnum.assistant }"> + <div class="relative w-full" v-if="item.content?.values"> <div - class="flex items-center justify-center size-[15px]" - v-if="item.content?.type === AnswerType.Text || item.content?.type === AnswerType.Knowledge" + class="text-sm rounded-[6px] p-4 leading-relaxed" + :style="{ backgroundColor: item.role === RoleEnum.user ? 'rgb(197 224 255)' : 'white' }" > - <i class="p-2 ywicon icon-copy cursor-pointer hover:text-[#0284ff] hover:!text-[18px]" @click="copyClick(item)" /> + <div v-if="item.content.errCode === ErrorCode.Message" class="text-red-500 w-full">{{ item.content.msg }}</div> + <component v-else :is="answerTypeMapCom[item.content.type]" :data="item.content.values" /> </div> - <div class="flex items-center justify-center size-[15px]"> - <i - :class="{ 'text-[#0284ff]': item.state === AnswerState.Like }" - class="p-2 ywicon icon-dianzan cursor-pointer hover:text-[#0284ff] font-medium hover:!text-[18px]" - @click="likeClick(item)" - /> - </div> - <div class="flex items-center justify-center size-[15px]"> - <i - :class="{ 'text-[#0284ff]': item.state === AnswerState.Unlike }" - class="p-2 ywicon icon-buzan cursor-pointer hover:text-[#0284ff] !text-[13px] hover:!text-[15px]" - @click="unLikeClick(item)" - /> + + <div v-if="item.role === RoleEnum.assistant" class="absolute flex items-center right-0 mr-2 mt-2 space-x-2"> + <div + class="flex items-center justify-center size-[15px]" + v-if="item.content?.type === AnswerType.Text || item.content?.type === AnswerType.Knowledge" + > + <i class="p-2 ywicon icon-copy cursor-pointer hover:text-[#0284ff] hover:!text-[18px]" @click="copyClick(item)" /> + </div> + <div class="flex items-center justify-center size-[15px]"> + <i + :class="{ 'text-[#0284ff]': item.state === AnswerState.Like }" + class="p-2 ywicon icon-dianzan cursor-pointer hover:text-[#0284ff] font-medium hover:!text-[18px]" + @click="likeClick(item)" + /> + </div> + <div class="flex items-center justify-center size-[15px]"> + <i + :class="{ 'text-[#0284ff]': item.state === AnswerState.Unlike }" + class="p-2 ywicon icon-buzan cursor-pointer hover:text-[#0284ff] !text-[13px] hover:!text-[15px]" + @click="unLikeClick(item)" + /> + </div> </div> </div> - </div> - <Loding v-else class="w-fit" :process="process" /> + <Loding v-else class="w-fit" :process="process" /> + </div> </div> </div> <div v-if="showAskMore" class="ml-4 mt-5 text-sm"> diff --git a/src/components/chat/chatComponents/recordSetCom/RecordSetCom.vue b/src/components/chat/chatComponents/recordSetCom/RecordSetCom.vue index fc29950..a0f3c60 100644 --- a/src/components/chat/chatComponents/recordSetCom/RecordSetCom.vue +++ b/src/components/chat/chatComponents/recordSetCom/RecordSetCom.vue @@ -33,12 +33,13 @@ import type { RecordSetValues } from '/@/api/ai/chat'; import { dateRegex } from '/@/utils/toolsValidate'; import { PATH_ICON, SCATTER_SYMBOL_SIZE, chatComProps, timeDataOptionToContent } from '../common'; +import { usePageDisplay } from '/@/hooks/usePageDisplay'; +import { debounce } from '/@/utils/util'; const activeName = ref('first'); const chartRef = ref<HTMLDivElement>(null); const selectChartType = ref<ChartTypeEnum>(ChartTypeEnum.Line); const props = defineProps(chatComProps); - const selectChartTypeChange = () => { drawChart(); @@ -66,8 +67,8 @@ const xType = getXType(xData); chartInstance.setOption({ grid: { - // bottom: 120, - right: '15%', + left: 35, + right: 45, bottom: '5%', }, tooltip: { @@ -155,6 +156,15 @@ }); }; +const showEvent = () => { + window.addEventListener('resize', resizeChart); +}; + +const hideEvent = () => { + window.removeEventListener('resize', resizeChart); +}; +let resizeChart = null; +const { haveExecutedMounted } = usePageDisplay(showEvent, hideEvent); onMounted(() => { setTimeout(() => { const parent = chartRef.value.parentElement; @@ -165,7 +175,15 @@ width: parentBound.width, height: parentBound.height, }); - + resizeChart = debounce(() => { + const parentBound = parent.getBoundingClientRect(); + chartInstance.resize({ + width: parentBound.width, + height: parentBound.height, + }); + }); + showEvent(); + haveExecutedMounted.value = true; drawChart(); }, 300); }); diff --git a/src/components/chat/chatComponents/summaryCom/SummaryCom.vue b/src/components/chat/chatComponents/summaryCom/SummaryCom.vue index ab0a51f..eaf963f 100644 --- a/src/components/chat/chatComponents/summaryCom/SummaryCom.vue +++ b/src/components/chat/chatComponents/summaryCom/SummaryCom.vue @@ -20,7 +20,7 @@ v-if="recordSetList && recordSetList.length > 0" > <div class="h-[20rem] flex-auto w-full"> - <div ref="chartRefList" v-for="(item, index) in recordSetList" :key="index"></div> + <div ref="chartRef" v-for="(item, index) in recordSetList" :key="index"></div> </div> </div> <div v-if="urlList && urlList.length > 0" class="w-full"> @@ -35,12 +35,15 @@ import * as echarts from 'echarts'; import type { TableInstance } from 'element-plus'; import _ from 'lodash'; -import { computed, onMounted, ref } from 'vue'; +import type { ShallowRef } from 'vue'; +import { computed, onMounted, ref, shallowRef } from 'vue'; import { AnswerType } from '../../model/types'; import { PATH_ICON, SCATTER_SYMBOL_SIZE, chatComProps, timeDataOptionToContent } from '../common'; import HTMLCom from '../htmlCom/HTMLCom.vue'; import { ChartTypeEnum, chartTypeMapEchart } from '../types'; import { axisLabelFormatter } from '/@/utils/chart'; +import { usePageDisplay } from '/@/hooks/usePageDisplay'; +import { debounce } from '/@/utils/util'; const props = defineProps(chatComProps); const selectChartType = ref<ChartTypeEnum>(ChartTypeEnum.Line); @@ -85,7 +88,7 @@ const urlList = computed(() => props.data.filter((item) => item.type === AnswerType.Url)); const drawAllChart = () => { - chartInstanceList.map((item, index) => { + chartInstanceList.value.map((item, index) => { drawChart(item, recordSetList.value[index]); }); }; @@ -145,9 +148,9 @@ grid: { // bottom: 120, // right: '15%', - left: '5%', - right: '5%', - bottom: '8%', + left: 35, + right: 45, + bottom: 20, }, toolbox: { show: true, @@ -240,7 +243,17 @@ item.doLayout(); }); }; -let chartInstanceList: echarts.ECharts[] = null; +let chartInstanceList: ShallowRef<echarts.ECharts[]> = shallowRef(null); + +const showEvent = () => { + window.addEventListener('resize', resizeChart); +}; + +const hideEvent = () => { + window.removeEventListener('resize', resizeChart); +}; +let resizeChart = null; +const { haveExecutedMounted } = usePageDisplay(showEvent, hideEvent); onMounted(() => { setTimeout(() => { const parent = chartRefList.value[0]?.parentElement; @@ -257,12 +270,23 @@ let divideCount = 1; const width = parentBound.width / divideCount; - chartInstanceList = chartRefList.value.map((item) => { + chartInstanceList.value = chartRefList.value.map((item) => { return echarts.init(item, undefined, { width: width, height: parentBound.height, }); }); + resizeChart = debounce(() => { + const parentBound = parent.getBoundingClientRect(); + chartInstanceList.value.map((item) => + item.resize({ + width: parentBound.width, + height: parentBound.height, + }) + ); + }); + showEvent(); + haveExecutedMounted.value = true; drawAllChart(); }, 1000); }); diff --git a/src/directive/customDirective.ts b/src/directive/customDirective.ts index b6eb85d..5a13bdd 100644 --- a/src/directive/customDirective.ts +++ b/src/directive/customDirective.ts @@ -184,3 +184,37 @@ }, }); } + +//#region ====================== v-resize ====================== +const resizeMap = new WeakMap(); +const ob = new ResizeObserver((entries) => { + for (const entry of entries) { + // 鑾峰彇dom鍏冪礌鐨勫洖璋� + const handler = resizeMap.get(entry.target); + //瀛樺湪鍥炶皟鍑芥暟 + if (handler) { + // 灏嗙洃鍚殑鍊肩粰鍥炶皟鍑芥暟 + handler({ + width: entry.borderBoxSize[0].inlineSize, + height: entry.borderBoxSize[0].blockSize, + }); + } + } +}); + +export const elementResizeDirective = (app: App) => { + app.directive('resize', { + mounted(el: any, binding: any) { + //灏哾om涓庡洖璋冪殑鍏崇郴濉炲叆map + resizeMap.set(el, binding.value); + //鐩戝惉el鍏冪礌鐨勫彉鍖� + ob.observe(el); + }, + unmounted(el: any) { + //鍙栨秷鐩戝惉 + ob.unobserve(el); + }, + }); +}; + +//#endregion diff --git a/src/directive/index.ts b/src/directive/index.ts index 926f0be..d0ced37 100644 --- a/src/directive/index.ts +++ b/src/directive/index.ts @@ -1,6 +1,6 @@ import type { App } from 'vue'; import { authDirective } from '/@/directive/authDirective'; -import { wavesDirective, dragDirective,eleFocusDirective } from '/@/directive/customDirective'; +import { wavesDirective, dragDirective, eleFocusDirective, elementResizeDirective } from '/@/directive/customDirective'; import { inputLimit } from '/@/directive/inputLimit'; /** @@ -19,5 +19,5 @@ // 杈撳叆闄愬埗鎸囦护 inputLimit(app); eleFocusDirective(app); - + elementResizeDirective(app); } diff --git a/src/hooks/usePageDisplay.ts b/src/hooks/usePageDisplay.ts new file mode 100644 index 0000000..e9cb5f1 --- /dev/null +++ b/src/hooks/usePageDisplay.ts @@ -0,0 +1,23 @@ +import { onActivated, onDeactivated, ref } from 'vue'; + +/** + * 寮�鍚矾鐢辩紦瀛橀〉闈紝绂诲紑鏃讹紝鍜岃繘鍏ユ椂鍙栨秷/寮�鍚闃呬簨浠� + * @returns + */ +export const usePageDisplay = (pageShow?: () => void, pageHide?: () => void) => { + const haveExecutedMounted = ref(false); + onActivated(() => { + if (!haveExecutedMounted.value) { + return; + } + pageShow?.(); + }); + + onDeactivated(() => { + pageHide?.(); + }); + + return { + haveExecutedMounted + }; +}; -- Gitblit v1.9.3