From ed1170014712737986ddcb4d760907c4b1d5f686 Mon Sep 17 00:00:00 2001
From: gerson <1405270578@qq.com>
Date: 星期六, 27 七月 2024 20:35:19 +0800
Subject: [PATCH] setTimeout

---
 src/components/chat/chatComponents/summaryCom/components/recordSet/RecordSet.vue |  444 +++++++++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 365 insertions(+), 79 deletions(-)

diff --git a/src/components/chat/chatComponents/summaryCom/components/recordSet/RecordSet.vue b/src/components/chat/chatComponents/summaryCom/components/recordSet/RecordSet.vue
index 9899e2c..660a252 100644
--- a/src/components/chat/chatComponents/summaryCom/components/recordSet/RecordSet.vue
+++ b/src/components/chat/chatComponents/summaryCom/components/recordSet/RecordSet.vue
@@ -1,39 +1,228 @@
 <template>
-	<div class="h-[20rem] w-full" v-resize="chartContainerResize">
-		<div ref="chartRef"></div>
+	<div class="w-full">
+		<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 :style="{ height: chartHeight }" v-resize="chartContainerResize" v-loading="chartLoading">
+			<div ref="chartRef"></div>
+		</div>
 	</div>
 </template>
 
 <script setup lang="ts">
 import type * as echarts from 'echarts';
 import _ from 'lodash';
-import { ref } from 'vue';
-import { SCATTER_SYMBOL_SIZE, chatComProps, getChatChartOption } from '../../../common';
+import moment from 'moment';
+import type { PropType } from 'vue';
+import { computed, ref } from 'vue';
+import { SCATTER_SYMBOL_SIZE, getChatChartOption } from '../../../common';
 import { useDrawChatChart } from '../../../hooks/useDrawChatChart';
+import YRange from './components/YRange.vue';
+import type { RecordSet, RecordSetParamsItem } from './types';
+import { RecordSetParamsType, recordSetMapCom } from './types';
+import { filterQuery } from '/@/api/ai/chat';
+import { deepClone } from '/@/utils/other';
+import { debounce } from '/@/utils/util';
+
 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>,
+// 	},
+// });
 
-const props = defineProps(chatComProps);
+const props = defineProps({
+	data: {
+		type: Object as PropType<any>,
+	},
+	originData: {
+		type: Object as PropType<any>,
+	},
+	summaryIndex: {
+		type: Number,
+	},
+	chartHeight: {
+		type: String,
+		default: '20rem',
+	},
+}) as {
+	data: RecordSet;
+};
+const chartLoading = ref(false);
+
+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;
+let nameIndex = undefined;
+
+let timeCol = null;
+let valueCol = null;
+
+let preData = null;
+
+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]]),
+				type: defaultDisplayType,
+				symbol: 'none',
+				smooth: true,
+			};
+		});
+	}
+	const combineOption = _.defaultsDeep(extraOption, getChatChartOption(), {
+		grid: {
+			bottom: 20,
+		},
+		legend: {
+			top: 19,
+			show: series?.length > 1,
+			type: 'scroll',
+		},
+		toolbox: {
+			show: true,
+			feature: {
+				myBar: {
+					onclick: () => {
+						chartInstance.value.setOption({
+							series: series.map((item) => ({
+								...item,
+								type: 'bar',
+								symbol: 'none',
+							})),
+						});
+					},
+				},
+
+				myScatter: {
+					onclick: () => {
+						chartInstance.value.setOption({
+							series: series.map((item) => ({
+								...item,
+								type: 'scatter',
+								symbol: 'circle',
+								symbolSize: SCATTER_SYMBOL_SIZE,
+							})),
+						});
+					},
+				},
+				myLine: {
+					onclick: () => {
+						chartInstance.value.setOption({
+							series: series.map((item) => ({
+								...item,
+								type: 'line',
+								symbol: 'none',
+								smooth: true,
+							})),
+						});
+					},
+				},
+			},
+		},
+
+		title: {
+			text: preData?.title,
+		},
+		xAxis: {
+			name: timeCol?.title,
+		},
+		yAxis: {
+			name: valueCol?.title,
+			/** @description 涓嶅己鍒朵繚鐣�0 */
+			scale: true,
+		},
+		series: series,
+	} as echarts.EChartsOption);
+	chartInstance.value.setOption(combineOption, {
+		notMerge: true,
+	});
+};
 
 const drawChart = () => {
 	const data = props.data;
+	if (!data || !data.cols || !data.values) {
+		return;
+	}
+	preData = data;
 	const xType = 'time';
-	let timeIndex = data.cols.findIndex((item) => item.type === 'time');
+	timeIndex = data.cols.findIndex((item) => item.type === 'time');
 	if (timeIndex === -1) {
 		timeIndex = 0;
 	}
-	const timeCol = data.cols[timeIndex];
+	timeCol = data.cols[timeIndex];
 
-	let valueIndex = data.cols.findIndex((item) => item.type === 'value');
+	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;
-	let groupedValues = 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;
 		}
@@ -53,75 +242,172 @@
 		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);
+	setNewOption();
 };
 const { chartContainerResize, chartInstance } = useDrawChatChart({ chartRef, drawChart });
+
+// 鏇存崲鍒楄〃
+const changeMap = new Map<string, string>(null);
+
+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 {
+		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) {
+			paramsObj[key] = value;
+		}
+		const params = {
+			history_id: historyId,
+			query_index: summaryIndex,
+			param_json: JSON.stringify(paramsObj),
+		};
+		res = await filterQuery(params);
+		chartLoading.value = true;
+	} finally {
+		chartLoading.value = false;
+	}
+
+	const title = res?.values?.title;
+	const values = res?.values?.values ?? [];
+	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]]),
+					};
+				}),
+		});
+	}
+};
+
+//#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]]),
+		type: defaultDisplayType,
+		symbol: 'none',
+		smooth: true,
+	}));
+	setNewOption(series, {
+		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">${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: COMMON_DAY + ' 00:00:00',
+			max: COMMON_DAY + ' 23:59:59',
+			splitNumber: 10,
+			axisLabel: {
+				formatter: (val) => {
+					const newVal = moment(val).format('HH:mm');
+					return newVal;
+				},
+				showMaxLabel: true,
+			},
+		},
+	});
+};
+const multiCompareChange = (val) => {
+	if (!groupedValues) return;
+	if (val) {
+		handleMultiCompare();
+	} else {
+		setNewOption();
+	}
+};
+//#endregion
+
+defineExpose({
+	drawChart,
+});
 </script>
 <style scoped lang="scss"></style>

--
Gitblit v1.9.3