From 4e394d1f4ed0928d5498083621966aba390a7642 Mon Sep 17 00:00:00 2001
From: wujingjing <gersonwu@qq.com>
Date: 星期三, 05 三月 2025 16:05:15 +0800
Subject: [PATCH] 图表查询

---
 src/components/chat/chatComponents/summaryCom/components/recordSet/RecordSet.vue |  398 +++++++++++++++++++++++++++++++++++++++++++-------------
 1 files changed, 301 insertions(+), 97 deletions(-)

diff --git a/src/components/chat/chatComponents/summaryCom/components/recordSet/RecordSet.vue b/src/components/chat/chatComponents/summaryCom/components/recordSet/RecordSet.vue
index 2c32c23..2f082a3 100644
--- a/src/components/chat/chatComponents/summaryCom/components/recordSet/RecordSet.vue
+++ b/src/components/chat/chatComponents/summaryCom/components/recordSet/RecordSet.vue
@@ -1,12 +1,12 @@
 <!-- 鏄ㄦ棩渚涙按绠$綉姒傚喌 -->
 <template>
-	<div class="w-full">
-		<div class="flex mb-4 flex-wrap">
+	<div class="w-full flex-column">
+		<div class="flex mb-4 flex-wrap flex-0">
 			<!-- TimeRange v-model 璺� @change 涓殑鍊间細涓嶄竴鏍凤紝浠change 涓负鍑� -->
-			<template v-if="visibleParams && visibleParams.length > 0">
+			<template v-if="visibleParams && visibleParams.length > 0 && showFilter">
 				<component
-					class="flex-0 m-1"
-					v-model="paramsValueList[index].value"
+					class="flex-0 m-2"
+					v-model="visibleParams[index].value"
 					v-for="(item, index) in visibleParams as any"
 					:key="item.id"
 					:id="item.id"
@@ -14,19 +14,40 @@
 					:data="item"
 					:originData="originData"
 					@change="(val) => handleQueryChange(val, item)"
-					:disabled="chartLoading"
+					:disabled="chartLoading || disabled"
 				></component>
 			</template>
 			<slot> </slot>
+			<YRange @input="yRangeInput" />
+			<el-tooltip
+				v-if="originChartType === ChartTypeEnum.Score"
+				:content="`${Object.keys(scoreMap)
+					.map((key) => `${key} 琛ㄧず${scoreMap[key]}`)
+					.join(', ')}`"
+				placement="top-start"
+			>
+				<SvgIcon name="fa fa-question-circle-o" :size="15" class="ml-1 cursor-help flex-center" color="#909399" />
+			</el-tooltip>
 
-			<YRange v-model="yRange" @input="yRangeInput" />
-			<el-checkbox class="m-1" v-model="isMultiCompare" label="澶氭棩瀵规瘮" @change="multiCompareChange"></el-checkbox>
+			<el-checkbox class="m-2" v-model="isMultiCompare" label="澶氭棩瀵规瘮" @change="multiCompareChange"></el-checkbox>
 
 			<DisplayMode class="ml-auto" v-model="showMode" @change="displayModeChange" />
 		</div>
 
-		<RecordSetTable :data="tableData" v-if="tableIsShow" :key="tableKey" />
-		<div v-show="!tableIsShow" :style="{ height: chartHeight }" v-resize="chartContainerResize" v-loading="chartLoading">
+		<RecordSetTable
+			:data="tableData"
+			v-if="tableIsShow"
+			:key="tableKey"
+			:tableLimitHeight="tableLimitHeight"
+			:class="{ 'flex-auto': chartHeight == undefined }"
+		/>
+		<div
+			v-show="!tableIsShow"
+			:style="{ height: chartHeight }"
+			:class="{ 'flex-auto': chartHeight == undefined }"
+			v-resize="chartContainerResize"
+			v-loading="chartLoading"
+		>
 			<div ref="chartRef"></div>
 		</div>
 	</div>
@@ -34,7 +55,6 @@
 
 <script setup lang="ts">
 import type * as echarts from 'echarts';
-import _ from 'lodash';
 import moment from 'moment';
 import type { PropType } from 'vue';
 import { computed, ref, shallowRef, watch } from 'vue';
@@ -44,6 +64,7 @@
 import RecordSetTable from '../recordSetTable/RecordSetTable.vue';
 import DisplayMode from './components/DisplayMode.vue';
 import YRange from './components/YRange.vue';
+import { IS_DAY_LIST } from './components/constants';
 import { DisplayModeType } from './components/types';
 import type { RecordSetParamsItem } from './types';
 import { RecordSetParamsType, recordSetMapCom, scoreMap } from './types';
@@ -51,11 +72,8 @@
 import { axisLabelFormatter } from '/@/utils/chart';
 import { deepClone } from '/@/utils/other';
 import { debounce } from '/@/utils/util';
+import { defaultsDeep, groupBy, random } from 'lodash-es';
 const chartRef = ref<HTMLDivElement>(null);
-const yRange = ref({
-	min: null as number,
-	max: null as number,
-});
 
 const showMode = ref(DisplayModeType.Chart);
 // const props = defineProps({
@@ -63,6 +81,10 @@
 // 		type: Object as PropType<RecordSet>,
 // 	},
 // });
+
+const emits = defineEmits<{
+	(event: 'updateQuery', res: any): void;
+}>();
 
 const props = defineProps({
 	data: {
@@ -76,11 +98,31 @@
 	},
 	chartHeight: {
 		type: String,
-		default: '20rem',
+		required: false,
 	},
-}) as {
-	data: any;
-};
+	tableHeight: {
+		type: Number,
+		default: document.body.clientHeight * 0.7,
+	},
+	showFilter: {
+		type: Boolean,
+		default: true,
+	},
+	disabled: {
+		type: Boolean,
+		default: false,
+	},
+	reportIndex: {
+		type: Number,
+		default: 0,
+	},
+	historyId: {
+		type: String,
+	},
+});
+
+const tableLimitHeight = props.chartHeight == undefined ? undefined : props.tableHeight;
+
 const chartLoading = ref(false);
 
 const stepOptions = [
@@ -91,13 +133,16 @@
 	{ title: '1澶�', value: '1 days' },
 ];
 
-const visibleParams = computed(() => {
+const getVisibleParams = (data) => {
 	// const visibleList = props.data?.params?.filter((item) => !item?.hide) ?? [];
 	// index 浣滀负 id
-	const visibleList = (props.data?.filter ?? []).map((item, index) => ({
-		id: index + '',
-		...item,
-	}));
+	const dataFilter = data?.filter ?? [];
+	const visibleList = (data?.filter ?? []).map((item, index) => {
+		// 涓嶄慨鏀瑰師濮嬪湴鍧�
+		item.id = index + '';
+
+		return item;
+	});
 	const newList: RecordSetParamsItem[] = [];
 	for (let index = 0; index < visibleList.length; index++) {
 		const current = visibleList[index];
@@ -116,7 +161,7 @@
 					id: current.id,
 					type: RecordSetParamsType.Step,
 					origin: current,
-					value: current.value,
+					value: current.step_value,
 					list: stepOptions,
 					title: current.title,
 				});
@@ -128,8 +173,35 @@
 	}
 
 	return newList;
-});
-const paramsValueList = ref(deepClone(visibleParams.value));
+};
+
+// 鏇存敼 value 鍊硷紝瀹屽叏瑕嗙洊浼氫涪澶卞搷搴旀�э紝鍙慨鏀� value
+const updateVisibleParams = (data) => {
+	const filter = data?.filter ?? [];
+
+	filter.map((newItem, index) => {
+		const currentItem = visibleParams.value.find((item) => item.id === index + '');
+
+		if (currentItem) {
+			if (newItem.type === RecordSetParamsType.TimeRange) {
+				currentItem.value = [newItem.start_value, newItem.end_value];
+			} else {
+				currentItem.value = newItem.step_value;
+			}
+		}
+	});
+};
+const visibleParams = ref(getVisibleParams(props.data));
+
+const checkIsDayTime = () => {
+	if (!props.showFilter) return false;
+	const stepFilter = visibleParams.value.find((item) => item.type === RecordSetParamsType.Step);
+	if (!stepFilter.origin.step_value) return false;
+
+	return IS_DAY_LIST.includes(stepFilter.origin.step_value);
+};
+// 璺ㄥ害鏄惁鏄棩鏈熷舰寮�
+// const isDayTime = checkIsDayTime();
 let groupedValues = null;
 let timeIndex = undefined;
 let valueIndex = undefined;
@@ -141,7 +213,7 @@
 let preData = null;
 
 let activeChartType: ChartTypeEnum = props.data?.chart_type ?? ChartTypeEnum.Line;
-const originChartType = activeChartType;
+let originChartType = activeChartType;
 
 // 缁欒〃鏍肩敤鐨� series
 const currentSeries = shallowRef<any[]>(null);
@@ -195,7 +267,11 @@
 			const values = groupedValues[item];
 			return {
 				name: item === 'default' ? '' : item,
-				data: values.map((item) => [item[timeIndex], item[valueIndex]]),
+				data: values
+					.map((item) => [item[timeIndex], item[valueIndex]])
+					.toSorted((b, a) => {
+						return b[timeIndex].localeCompare(a[timeIndex]);
+					}),
 				...getChartTypeSeriesOption(activeChartType),
 			};
 		});
@@ -208,12 +284,10 @@
 			  }
 			: axisLabelFormatter;
 
-	const tooltipValueFormatter =
-		originChartType === ChartTypeEnum.Score
-			? (value) => {
-					return scoreMap[value];
-			  }
-			: undefined;
+	const tooltipValueFormatter = (value) => {
+		const realValue = originChartType === ChartTypeEnum.Score ? scoreMap[value] : value;
+		return realValue + (props.data.unit ? ` ${props.data.unit}` : '');
+	};
 
 	const scoreYAxisOption: echarts.YAXisComponentOption = {
 		min: 0,
@@ -223,7 +297,7 @@
 			formatter: yAxisFormatter,
 		},
 	};
-	const combineOption = _.defaultsDeep(
+	const combineOption = defaultsDeep(
 		{
 			grid: {
 				bottom: 20,
@@ -284,7 +358,8 @@
 				name: timeCol?.title,
 			},
 			yAxis: {
-				name: valueCol?.title,
+				name: props.data.unit ? `${props.data.unit}` : valueCol?.title,
+
 				/** @description 涓嶅己鍒朵繚鐣� */
 				scale: true,
 				...(originChartType === ChartTypeEnum.Score ? scoreYAxisOption : {}),
@@ -299,8 +374,7 @@
 	});
 };
 
-const handleData = () => {
-	const data = props.data;
+const handleData = (data = props.data) => {
 	if (!data || !data.cols || !data.values) {
 		return;
 	}
@@ -326,7 +400,7 @@
 			nameIndex = 1;
 		}
 		nameCol = data.cols[nameIndex];
-		groupedValues = _.groupBy(data.values, (item) => item[nameIndex]);
+		groupedValues = groupBy(data.values, (item) => item[nameIndex]);
 	} else if (data.chart === 'single_line') {
 		groupedValues = {
 			default: data.values,
@@ -338,42 +412,118 @@
 			nameIndex = 1;
 		}
 		nameCol = data.cols[nameIndex];
-		groupedValues = _.groupBy(data.values, (item) => item[nameIndex]);
+		groupedValues = groupBy(data.values, (item) => item[nameIndex]);
 	}
 };
 
-const drawChart = () => {
-	const data = props.data;
+const drawChart = (data = props.data) => {
 	if (!data || !data.cols || !data.values) {
 		return;
 	}
+
 	handleData();
 	setNewOption();
 };
-const { chartContainerResize, chartInstance, initChart } = useDrawChatChart({ chartRef, drawChart });
+const { chartContainerResize, chartInstance } = useDrawChatChart({ chartRef, drawChart });
 
-// 鏇存崲鍒楄〃
-const changeMap = new Map<string, any>(null);
+const updateCurrent = (res, isNew = false) => {
+	const title = res?.title;
+	const values = res?.values ?? [];
+	//#region ====================== 鍒锋柊褰撳墠 filter ======================
+	// 鍙洿鏂� value锛屼笉鐩存帴瑕嗙洊锛岄槻姝涪澶卞搷搴旀��
+	// updateVisibleParams(res);
+	//#endregion
+	groupedValues = groupBy(values, (item) => item[nameIndex]);
+	if (isMultiCompare.value) {
+		handleMultiCompare();
+	} else {
+		if (isNew) {
+			setNewOption();
+		} else {
+			(currentSeries.value =
+				groupedValues &&
+				Object.keys(groupedValues).map((item, index) => {
+					const values = groupedValues[item];
+					return {
+						name: item === 'default' ? '' : item,
+						data: values
+							.map((item) => [item[timeIndex], item[valueIndex]])
+							.toSorted((b, a) => {
+								return b[timeIndex].localeCompare(a[timeIndex]);
+							}),
+					};
+				})),
+				chartInstance.value?.setOption({
+					title: {
+						text: title,
+					},
+					series: currentSeries.value,
+				});
+		}
+	}
+};
+
+const getFilterList = () => {
+	const curAgentKey = props.data.agent_key;
+
+	// 鐩稿悓 agent_key 涓嬫墍鏈� filter 璇锋眰鍙傛暟
+	const filterList = ((props as any).originData?.content?.origin?.summary ?? []).reduce((preVal, curVal) => {
+		if (curVal.agent_key !== curAgentKey) return preVal;
+
+		const filter = (curVal.filter ?? []).reduce((subPreVal, subCurVal) => {
+			if (subCurVal.type === RecordSetParamsType.TimeRange) {
+				subPreVal.push(
+					...[
+						{
+							update: subCurVal.update,
+							value: subCurVal.start_value,
+							path: subCurVal.start_path,
+						},
+						{
+							update: subCurVal.update,
+							value: subCurVal.end_value,
+							path: subCurVal.end_path,
+						},
+					]
+				);
+			} else {
+				subPreVal.push({
+					update: subCurVal.update,
+					value: subCurVal.step_value,
+					path: subCurVal.step_path,
+				});
+			}
+
+			return subPreVal;
+		}, []);
+
+		preVal = preVal.concat(filter);
+
+		return preVal;
+	}, []);
+	return filterList;
+};
 const handleQueryChange = async (val: any, item: RecordSetParamsItem) => {
 	if (!val) return;
-	const historyId = (props as any).originData.historyId;
+	const historyId = props.historyId;
 	let res = null;
 
-	try {
-		if (item.type === RecordSetParamsType.TimeRange) {
-			item.origin.start_value = val[0];
-			item.origin.end_value = val[1];
-			changeMap.set(item.id, item.origin);
-		} else {
-			item.origin.value = val;
-			changeMap.set(item.id, item.origin);
-		}
+	// 鏀瑰彉鍘熷鍊�
+	if (item.type === RecordSetParamsType.TimeRange) {
+		item.origin.start_value = val[0];
+		item.origin.end_value = val[1];
+	} else {
+		item.origin.step_value = val;
+	}
 
-		const filterObj = Array.from(changeMap.values());
+	const filterList = getFilterList();
+	try {
 		const params = {
 			history_id: historyId,
+			// 鏌ヨ鍓嶅悗 agent_key 涓嶄細鍙�
 			agent_key: props.data.agent_key,
-			filter_json: JSON.stringify(filterObj),
+			filter_json: JSON.stringify(filterList),
+			result_group_index: props.reportIndex,
 		};
 		res = await curveQuery(params);
 		chartLoading.value = true;
@@ -381,28 +531,14 @@
 		chartLoading.value = false;
 	}
 
-	const title = res?.values?.title;
-	const values = res?.values?.values ?? [];
-	groupedValues = _.groupBy(values, (item) => item[nameIndex]);
+	emits('updateQuery', res);
 
-	if (isMultiCompare.value) {
-		handleMultiCompare();
-	} else {
-		(currentSeries.value =
-			groupedValues &&
-			Object.keys(groupedValues).map((item) => {
-				const values = groupedValues[item];
-				return {
-					data: values.map((item) => [item[timeIndex], item[valueIndex]]),
-				};
-			})),
-			chartInstance.value.setOption({
-				title: {
-					text: title,
-				},
-				series: currentSeries.value,
-			});
-	}
+	return;
+};
+
+let realRange = {
+	min: null,
+	max: null,
 };
 
 const getSingleDayOption = (day = COMMON_DAY) =>
@@ -454,11 +590,9 @@
 	} as echarts.EChartsOption);
 //#region ====================== 璁剧疆Y鑼冨洿 ======================
 const debounceSetYRange = debounce((val) => {
+	(realRange.min = val.min), (realRange.max = val.max);
 	chartInstance.value.setOption({
-		yAxis: {
-			min: val.min,
-			max: val.max,
-		},
+		yAxis: realRange,
 	});
 
 	currentSeries.value = currentSeries.value.concat([]);
@@ -481,7 +615,7 @@
 	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'));
+		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];
@@ -500,7 +634,11 @@
 	}, []);
 	const series = seriesData.map<echarts.SeriesOption>((item) => ({
 		name: item[0]?.[nameIndex],
-		data: item.map((item) => [item[timeIndex], item[valueIndex]]),
+		data: item
+			.map((item) => [item[timeIndex], item[valueIndex]])
+			.toSorted((b, a) => {
+				return b[timeIndex].localeCompare(a[timeIndex]);
+			}),
 		...getChartTypeSeriesOption(activeChartType),
 	}));
 	setNewOption(series, getSingleDayOption());
@@ -527,17 +665,25 @@
 
 const tableData = computed(() => {
 	if (!currentSeries.value) return [];
-	// const min = yRange.value.min == null ? -Infinity : yRange.value.min;
-	// const max = yRange.value.max == null ? Infinity : yRange.value.max;
+	const min = realRange.min == null ? -Infinity : realRange.min;
+	const max = realRange.max == null ? Infinity : realRange.max;
 	const timeDataMap = currentSeries.value.reduce((preVal, curVal, index) => {
 		for (const item of curVal.data) {
-			const [time, value] = item;
-
-			// if (value < min || value > max) {
-			// 	continue;
-			// }
+			let [time, value] = item;
+			// 澶氭棩瀵规瘮锛屽彧鏄剧ず鏃跺垎绉�
+			if (isMultiCompare.value) {
+				time = time.slice(11);
+			}
+			if (value < min || value > max) {
+				continue;
+			}
 			if (!preVal[time]) {
 				preVal[time] = [];
+			}
+
+			// score 绫诲瀷锛寁alue 鍊硷紝闇�瑕佹槧灏勬垚鍙︿竴涓��
+			if (originChartType === ChartTypeEnum.Score) {
+				value = scoreMap[value];
 			}
 			preVal[time][index] = value;
 		}
@@ -545,11 +691,23 @@
 		return preVal;
 	}, {});
 
-	const data = Object.keys(timeDataMap).map((item) => [item, ...timeDataMap[item]]);
+	// 鏃堕棿鏈�鏃╁埌鏈�鏅氭帓搴�
+	const data = Object.keys(timeDataMap)
+		.map((item) => [item, ...timeDataMap[item]])
+		.toSorted((b, a) => {
+			return b[0].localeCompare(a[0]);
+		});
+	const getColName = (name) => {
+		if (props.data.unit) {
+			return `${name}锛�${props.data.unit}锛塦;
+		}
+		return name;
+	};
 	const cols = currentSeries.value.map((item, index) => ({
-		title: item.name ?? `鍊�${index + 1}`,
+		title: getColName(item.name ?? `鍊�${index + 1}`),
 		type: 'text',
 	}));
+
 	cols.unshift({
 		title: '鏃堕棿',
 		type: 'time',
@@ -562,7 +720,6 @@
 		cols: cols,
 		values: data,
 	};
-
 	return result;
 });
 //#endregion
@@ -571,16 +728,63 @@
 watch(
 	() => currentSeries.value,
 	(val) => {
-		if (!tableIsShow.value) return;
-		tableKey.value = _.random(0, 100000) + '';
+		tableKey.value = random(0, 100000) + '';
 	}
 );
+
+const updateAll = (triggerIndex, res) => {
+	// 褰撳墠 agent_key
+	const curAgentKey = props.data.agent_key;
+	const triggerAgentKey = (props as any).originData?.content?.origin?.summary?.[triggerIndex]?.agent_key;
+	if (curAgentKey !== triggerAgentKey) {
+		return;
+	}
+	if (!curAgentKey) {
+		return;
+	}
+
+	// 褰撳墠椤规墍鍦ㄧ储寮�
+	let currentIndex = -1;
+	for (let index = 0; index < (props as any).originData.content.origin.summary.length; index++) {
+		const item = (props as any).originData.content.origin.summary[index];
+		if (item.agent_key === curAgentKey) {
+			currentIndex++;
+			if (index === props.summaryIndex) {
+				break;
+			}
+		}
+	}
+
+	const newSummary = res?.summary?.[currentIndex];
+	if (!newSummary) return;
+
+	updateCurrent(newSummary);
+};
+
+const updateIndexSummary = (summary) => {
+	updateCurrent(summary?.[props.summaryIndex], true);
+};
+
+const clearChart = () => {
+	chartInstance.value.setOption(
+		{
+			title: {
+				text: '',
+			},
+			series: [],
+		},
+		true
+	);
+};
 
 defineExpose({
 	drawChart,
 	isMultiCompare,
 	handleMultiCompare,
 	handleData,
+	updateAll,
+	clearChart,
+	updateIndexSummary,
 });
 </script>
 <style scoped lang="scss"></style>

--
Gitblit v1.9.3