From 345370831431a07d4680d0109cd1761e1e913ae9 Mon Sep 17 00:00:00 2001 From: wujingjing <gersonwu@qq.com> Date: 星期三, 09 十月 2024 13:43:13 +0800 Subject: [PATCH] bug;remove log --- src/components/chat/chatComponents/summaryCom/components/recordSet/RecordSet.vue | 501 +++++++++++++++++++++++++++++++++++++++++++------------ 1 files changed, 393 insertions(+), 108 deletions(-) diff --git a/src/components/chat/chatComponents/summaryCom/components/recordSet/RecordSet.vue b/src/components/chat/chatComponents/summaryCom/components/recordSet/RecordSet.vue index 27b2e89..022707c 100644 --- a/src/components/chat/chatComponents/summaryCom/components/recordSet/RecordSet.vue +++ b/src/components/chat/chatComponents/summaryCom/components/recordSet/RecordSet.vue @@ -1,19 +1,28 @@ +<!-- 鏄ㄦ棩渚涙按绠$綉姒傚喌 --> <template> <div class="w-full"> - <div class="flex space-x-2 mb-4" v-if="data?.params && data?.params.length > 0"> - <component - v-model="paramsValueList[index].value" - v-for="(item, index) in data?.params" - :key="item.id" - :id="item.id" - :is="recordSetMapCom[item.type]" - :data="item" - :originData="originData" - @change="(val) => handleQueryChange(val, item)" - :disabled="chartLoading" - ></component> + <div class="flex mb-4 flex-wrap"> + <!-- TimeRange v-model 璺� @change 涓殑鍊间細涓嶄竴鏍凤紝浠change 涓负鍑� --> + <template v-if="visibleParams && visibleParams.length > 0"> + <component + class="flex-0 m-1" + v-model="paramsValueList[index].value" + v-for="(item, index) in visibleParams as any" + :key="item.id" + :id="item.id" + :is="recordSetMapCom[item.type]" + :data="item" + :originData="originData" + @change="(val) => handleQueryChange(val, item)" + :disabled="chartLoading" + ></component> + </template> + <slot> </slot> + + <YRange v-model="yRange" @input="yRangeInput" /> + <el-checkbox class="m-1" v-model="isMultiCompare" label="澶氭棩瀵规瘮" @change="multiCompareChange"></el-checkbox> </div> - <div class="h-[20rem]" v-resize="chartContainerResize" v-loading="chartLoading"> + <div :style="{ height: chartHeight }" v-resize="chartContainerResize" v-loading="chartLoading"> <div ref="chartRef"></div> </div> </div> @@ -22,17 +31,25 @@ <script setup lang="ts"> import type * as echarts from 'echarts'; import _ from 'lodash'; +import moment from 'moment'; import type { PropType } from 'vue'; -import { ref, watch } from 'vue'; -import { SCATTER_SYMBOL_SIZE, chatComProps, getChatChartOption } from '../../../common'; +import { computed, ref } from 'vue'; +import { SCATTER_SYMBOL_SIZE, getChatChartOption } from '../../../common'; import { useDrawChatChart } from '../../../hooks/useDrawChatChart'; +import { ChartTypeEnum } from '../../../types'; +import YRange from './components/YRange.vue'; import type { RecordSet, RecordSetParamsItem } from './types'; -import { recordSetMapCom } from './types'; +import { RecordSetParamsType, recordSetMapCom, scoreMap } from './types'; import { filterQuery } from '/@/api/ai/chat'; +import { deepClone } from '/@/utils/other'; +import { debounce } from '/@/utils/util'; +import { axisLabelFormatter } from '/@/utils/chart'; const chartRef = ref<HTMLDivElement>(null); -const defaultDisplayType = 'line'; - +const yRange = ref({ + min: null as number, + max: null as number, +}); // const props = defineProps({ // data: { // type: Object as PropType<RecordSet>, @@ -49,34 +66,236 @@ summaryIndex: { type: Number, }, + chartHeight: { + type: String, + default: '20rem', + }, }) as { data: RecordSet; }; const chartLoading = ref(false); -const paramsValueList = ref(props.data?.params); +const visibleParams = computed(() => { + const visibleList = props.data?.params?.filter((item) => !item?.hide) ?? []; + + const newList: RecordSetParamsItem[] = []; + let nextMatchIndex = null; + for (let index = 0; index < visibleList.length; index++) { + if (nextMatchIndex === index) continue; + const current = visibleList[index]; + const currentAny = current as any; + if (index !== visibleList.length - 1 && currentAny.type === RecordSetParamsType.StartTime) { + const next = visibleList[index + 1]; + const nextAny = next as any; + + if (nextAny.group === currentAny.group && nextAny.type === RecordSetParamsType.EndTime) { + newList.push({ + type: RecordSetParamsType.TimeRange, + value: [currentAny.value, nextAny.value], + group: currentAny.group, + range: [currentAny, nextAny], + } as any); + nextMatchIndex = index + 1; + } else { + newList.push(current); + } + } else { + newList.push(current); + } + } + + return newList; +}); +const paramsValueList = ref(deepClone(visibleParams.value)); let groupedValues = null; let timeIndex = undefined; let valueIndex = undefined; -const drawChart = () => { +let nameIndex = undefined; + +let timeCol = null; +let valueCol = null; + +let preData = null; + + +let activeChartType: ChartTypeEnum = props.data?.chart_type ?? ChartTypeEnum.Line; +const originChartType = activeChartType; + +const getChartTypeSeriesOption = (type: ChartTypeEnum) => { + let result = {}; + switch (type) { + case ChartTypeEnum.Bar: + result = { + type: 'bar', + symbol: 'none', + }; + + break; + case ChartTypeEnum.Line: + result = { + type: 'line', + symbol: 'none', + smooth: true, + }; + + break; + + case ChartTypeEnum.Scatter: + result = { + type: 'scatter', + symbol: 'circle', + symbolSize: SCATTER_SYMBOL_SIZE, + }; + + break; + case ChartTypeEnum.Score: + result = { + type: 'bar', + symbol: 'none', + }; + + break; + + default: + break; + } + + return result; +}; + +const setNewOption = (series?: any[], extraOption: echarts.EChartsOption = {}) => { + const isEmpty = !series || series.length === 0; + if (isEmpty) { + series = Object.keys(groupedValues).map((item) => { + const values = groupedValues[item]; + return { + name: item === 'default' ? '' : item, + data: values.map((item) => [item[timeIndex], item[valueIndex]]), + ...getChartTypeSeriesOption(activeChartType), + }; + }); + } + const yAxisFormatter = + originChartType === ChartTypeEnum.Score + ? (value) => { + return scoreMap[value]; + } + : axisLabelFormatter; + + const tooltipValueFormatter = + originChartType === ChartTypeEnum.Score + ? (value) => { + return scoreMap[value]; + } + : undefined; + + const scoreYAxisOption: echarts.YAXisComponentOption = { + min: 0, + max: 4, + interval: 1, + axisLabel: { + formatter: yAxisFormatter, + }, + }; + const combineOption = _.defaultsDeep( + { + grid: { + bottom: 20, + }, + legend: { + top: 19, + show: true, + type: 'scroll', + }, + tooltip: { + valueFormatter: tooltipValueFormatter, + }, + toolbox: { + show: true, + feature: { + myBar: { + onclick: () => { + activeChartType = originChartType === ChartTypeEnum.Score ? ChartTypeEnum.Score : ChartTypeEnum.Bar; + chartInstance.value.setOption({ + series: series.map((item) => ({ + ...item, + ...getChartTypeSeriesOption(activeChartType), + })), + }); + }, + }, + + myScatter: { + onclick: () => { + activeChartType = ChartTypeEnum.Scatter; + + chartInstance.value.setOption({ + series: series.map((item) => ({ + ...item, + ...getChartTypeSeriesOption(activeChartType), + })), + }); + }, + }, + myLine: { + onclick: () => { + activeChartType = ChartTypeEnum.Line; + chartInstance.value.setOption({ + series: series.map((item) => ({ + ...item, + ...getChartTypeSeriesOption(activeChartType), + })), + }); + }, + }, + }, + }, + + title: { + text: preData?.title, + }, + xAxis: { + name: timeCol?.title, + }, + yAxis: { + name: valueCol?.title, + /** @description 涓嶅己鍒朵繚鐣� */ + scale: true, + ...(originChartType === ChartTypeEnum.Score ? scoreYAxisOption : {}), + }, + series: series, + } as echarts.EChartsOption, + extraOption, + getChatChartOption() + ); + chartInstance.value.setOption(combineOption, { + notMerge: true, + }); +}; + +const handleData = () => { const data = props.data; + if (!data || !data.cols || !data.values) { + return; + } + preData = data; const xType = 'time'; timeIndex = data.cols.findIndex((item) => item.type === 'time'); if (timeIndex === -1) { timeIndex = 0; } - const timeCol = data.cols[timeIndex]; + timeCol = data.cols[timeIndex]; valueIndex = data.cols.findIndex((item) => item.type === 'value'); if (valueIndex === -1) { valueIndex = 2; } - const valueCol = data.cols[valueIndex]; + valueCol = data.cols[valueIndex]; let nameCol = null; groupedValues = null; if (data.chart === 'muli_line') { - let nameIndex = data.cols.findIndex((item) => item.type === 'name'); + nameIndex = data.cols.findIndex((item) => item.type === 'name'); if (nameIndex === -1) { nameIndex = 1; } @@ -95,92 +314,36 @@ nameCol = data.cols[nameIndex]; groupedValues = _.groupBy(data.values, (item) => item[nameIndex]); } +}; - const seriesData = Object.keys(groupedValues).map((item) => { - const values = groupedValues[item]; - return { - name: item === 'default' ? '' : item, - data: values.map((item) => [item[timeIndex], item[valueIndex]]), - type: defaultDisplayType, - symbol: 'none', - smooth: true, - }; - }); - const combineOption = _.defaultsDeep(getChatChartOption(), { - grid: { - bottom: 20, - }, - toolbox: { - show: true, - feature: { - myBar: { - onclick: () => { - chartInstance.value.setOption({ - series: seriesData.map((item) => ({ - ...item, - type: 'bar', - symbol: 'none', - })), - }); - }, - }, - - myScatter: { - onclick: () => { - chartInstance.value.setOption({ - series: seriesData.map((item) => ({ - ...item, - type: 'scatter', - symbol: 'circle', - symbolSize: SCATTER_SYMBOL_SIZE, - })), - }); - }, - }, - myLine: { - onclick: () => { - chartInstance.value.setOption({ - series: seriesData.map((item) => ({ - ...item, - type: 'line', - symbol: 'none', - smooth: true, - })), - }); - }, - }, - }, - }, - - title: { - text: data?.title, - }, - xAxis: { - name: timeCol?.title, - }, - yAxis: { - name: valueCol?.title, - }, - series: seriesData, - } as echarts.EChartsOption); - chartInstance.value.setOption(combineOption); +const drawChart = () => { + const data = props.data; + if (!data || !data.cols || !data.values) { + return; + } + handleData(); + setNewOption(); }; const { chartContainerResize, chartInstance } = useDrawChatChart({ chartRef, drawChart }); // 鏇存崲鍒楄〃 -const changeMap = new Map<string,string>(null); +const changeMap = new Map<string, string>(null); -const handleQueryChange = async (val: string, item: RecordSetParamsItem) => { +const handleQueryChange = async (val: any, item: RecordSetParamsItem) => { if (!val) return; + const historyId = (props as any).originData.historyId; const summaryIndex = (props as any).summaryIndex; let res = null; try { - - changeMap.set(item.id,val); + if (item.type === RecordSetParamsType.TimeRange) { + changeMap.set(item.range[0].id, val[0]), changeMap.set(item.range[1].id, val[1]); + } else { + changeMap.set(item.id, val); + } const paramsObj = {}; - for (const [key,value] of changeMap) { + for (const [key, value] of changeMap) { paramsObj[key] = value; } const params = { @@ -196,18 +359,140 @@ const title = res?.values?.title; const values = res?.values?.values ?? []; - chartInstance.value.setOption({ - title: { - text: title, - }, - series: - groupedValues && - Object.keys(groupedValues).map(() => { - return { - data: values.map((item) => [item[timeIndex], item[valueIndex]]), - }; - }), - }); + groupedValues = _.groupBy(values, (item) => item[nameIndex]); + + if (isMultiCompare.value) { + handleMultiCompare(); + } else { + chartInstance.value.setOption({ + title: { + text: title, + }, + series: + groupedValues && + Object.keys(groupedValues).map((item) => { + const values = groupedValues[item]; + return { + data: values.map((item) => [item[timeIndex], item[valueIndex]]), + }; + }), + }); + } }; + +const getSingleDayOption = (day = COMMON_DAY) => + ({ + tooltip: { + show: true, + trigger: 'axis', + formatter(params) { + const itemList = params.map((item, index) => { + return `<div style="margin: ${index === 0 ? 0 : 10}px 0 0; line-height: 1"> + <div style="margin: 0px 0 0; line-height: 1"> + ${item.marker}<span style="font-size: 14px; color: #666; font-weight: 400; margin-left: 2px" + >${item.seriesName}</span + ><span style="float: right; margin-left: 20px; font-size: 14px; color: #666; font-weight: 900">${ + originChartType === ChartTypeEnum.Score ? scoreMap[item.data[1]] : item.data[1] + }</span> + <div style="clear: both"></div> + </div> + <div style="clear: both"></div> + </div>`; + }); + + const result = `<div style="margin: 0px 0 0; line-height: 1"> + <div style="margin: 0px 0 0; line-height: 1"> + <div style="font-size: 14px; color: #666; font-weight: 400; line-height: 1">${params?.[0]?.data[0]?.slice(10, 16)}</div> + <div style="margin: 10px 0 0; line-height: 1"> + ${itemList.join('')} + <div style="clear: both"></div> + </div> + <div style="clear: both"></div> + </div> + <div style="clear: both"></div> + </div>`; + return result; + }, + }, + xAxis: { + min: day + ' 00:00:00', + max: day + ' 23:59:59', + splitNumber: 10, + axisLabel: { + formatter: (val) => { + const newVal = moment(val).format('HH:mm'); + return newVal; + }, + showMaxLabel: true, + }, + }, + } as echarts.EChartsOption); +//#region ====================== 璁剧疆Y鑼冨洿 ====================== +const debounceSetYRange = debounce((val) => { + chartInstance.value.setOption({ + yAxis: { + min: val.min, + max: val.max, + }, + }); +}); + +const yRangeInput = (val) => { + debounceSetYRange(val); +}; + +//#endregion + +//#region ====================== 澶氭棩瀵规瘮 ====================== +// 澶氭棩瀵规瘮鍩哄噯鏃堕棿 +const COMMON_DAY = '2024-07-26'; + +const isMultiCompare = ref(false); +const handleMultiCompare = () => { + if (!isMultiCompare.value) return; + const cloneData = deepClone(groupedValues); + const seriesData = Object.keys(cloneData).reduce((preVal, curVal, curIndex, arr) => { + const values = cloneData[curVal]; + const isMulti = arr.length > 1; + const groupByDateValues = _.groupBy(values, (item) => moment(item[timeIndex]).format('YYYY-MM-DD')); + for (const key in groupByDateValues) { + if (Object.prototype.hasOwnProperty.call(groupByDateValues, key)) { + const val = groupByDateValues[key]; + + const newVal = val.map((item) => { + // 鏂板悕绉� + item[nameIndex] = isMulti ? `${curVal}_${key}` : `${key}`; + item[timeIndex] = COMMON_DAY + ' ' + moment(item[timeIndex]).format('HH:mm:ss'); + return item; + }); + + preVal.push(newVal); + } + } + return preVal; + }, []); + const series = seriesData.map<echarts.SeriesOption>((item) => ({ + name: item[0]?.[nameIndex], + data: item.map((item) => [item[timeIndex], item[valueIndex]]), + ...getChartTypeSeriesOption(activeChartType), + })); + setNewOption(series, getSingleDayOption()); +}; +const multiCompareChange = (val) => { + if (!groupedValues) return; + if (val) { + handleMultiCompare(); + } else { + setNewOption(); + } +}; +//#endregion + +defineExpose({ + drawChart, + isMultiCompare, + handleMultiCompare, + handleData, +}); </script> <style scoped lang="scss"></style> -- Gitblit v1.9.3