From 0d801118cc32be9637e3314b11775e3fa5aec778 Mon Sep 17 00:00:00 2001 From: zwb Date: Tue, 30 Jul 2024 18:15:24 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=9D=E8=AF=95=E5=AE=8C=E5=96=84=E5=9B=BE?= =?UTF-8?q?=E8=A1=A8=E6=9B=B4=E6=96=B0=20bug=20=E5=9B=BE=E8=A1=A8=E6=97=A0?= =?UTF-8?q?=E6=B3=95=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/ServerController.cs | 42 ++---- web/components/Cards/IChart.vue | 56 +++----- web/components/Charts/AreaChart.vue | 126 ++++++------------ 3 files changed, 76 insertions(+), 148 deletions(-) diff --git a/LoongPanel-Asp/Controllers/ServerController.cs b/LoongPanel-Asp/Controllers/ServerController.cs index 3719ddc..ee4b2de 100755 --- a/LoongPanel-Asp/Controllers/ServerController.cs +++ b/LoongPanel-Asp/Controllers/ServerController.cs @@ -52,50 +52,34 @@ public class ServerController( [FromQuery] List? dataTypes = null, [FromQuery] int? startIndex = 0) { var userId = HttpContext.User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier)!.Value; - //创建一个缓存 - Dictionary temp = new(); - //创建一个时间缓存 //创建查询 流式 var query = dbContext.ServerMonitoringData .AsNoTracking() // 不追踪实体状态 .Where(x => x.ServerId == serverId) // 筛选服务器ID .Where(x => dataTypes == null || dataTypes.Contains(x.DataType)) // 如果dataTypes不为空,则进一步筛选 + .OrderBy(x => x.Time) .Skip(Math.Max(startIndex ?? 0, 0)) // 跳过指定数量的记录 .Take(1000) .AsAsyncEnumerable(); // 启用流式查询 + Dictionary>> temp = new(); + await foreach (var data in query) { - //计算两者时间差 按秒分割 - if (!temp.TryGetValue(data.DataType, out var tempData)) tempData = data; - temp[data.DataType] = data; - var time = tempData?.Time; - if (time == null || data.Time == null) continue; - var timeDifferenceInSeconds = (data.Time - time)?.TotalSeconds; - if (timeDifferenceInSeconds <= 0) continue; - var steps = (int)timeDifferenceInSeconds!; - var value = double.Parse(data.Data ?? "0"); - var lastValue = double.Parse(tempData?.Data ?? "0"); - //计算中间值 贝塞尔曲线 - var controlPoint = (value + lastValue) / 2; - List> values = []; - for (var i = 0; i < steps; i++) + if (!temp.TryGetValue(data.DataType, out var value)) { - var t = (double)i / (steps - 1); - var bezierValue = (1 - t) * (1 - t) * value + 2 * (1 - t) * t * controlPoint + t * t * lastValue; - var bezierTime = time.Value.AddSeconds(i); - var utcTime = bezierTime.ToUniversalTime(); - var unixTimestamp = ((DateTimeOffset)utcTime).ToUnixTimeMilliseconds(); - List innerList = - [ - unixTimestamp, - ((int)bezierValue).ToString(CultureInfo.InvariantCulture) - ]; - values.Add(innerList); + value = new List>(); + temp[data.DataType] = value; } - await hubContext.Clients.Groups(userId).SendAsync("ReceiveDataHistory", data.DataType, values); + var unixTimestamp = ((DateTimeOffset)data.Time?.ToUniversalTime()!).ToUnixTimeMilliseconds(); + value.Add([unixTimestamp!, data.Data!]); } + foreach (var entry in temp) + { + await hubContext.Clients.Groups(userId).SendAsync("ReceiveDataHistory", entry.Key, entry.Value, true); + } + return Ok(); } diff --git a/web/components/Cards/IChart.vue b/web/components/Cards/IChart.vue index bfc39e7..fd0896f 100755 --- a/web/components/Cards/IChart.vue +++ b/web/components/Cards/IChart.vue @@ -95,13 +95,14 @@ const items = [ @@ -109,46 +110,31 @@ const items = [ @import "base"; .card-layout { - width: 100%; height: 100%; + width: 100%; background: $light-bg-color; - border-radius: $radius; - box-shadow: 0 10px 30px 0 rgba(17, 38, 146, 0.05); - padding: $padding*1.5; - position: relative; - display: flex; - flex-direction: column; - gap: $gap; - will-change: scroll-position, contents; - border: $border; + display: grid; + grid-template-rows: 40px 1fr; + .dark-mode & { background: $dark-bg-color; } } - - .card-title { display: flex; + justify-content: space-between; align-items: center; - gap: $gap; - color: $light-text-color; - position: absolute; - z-index: 10; - &, - h3:hover { - cursor: move; - } - - .dark-mode & { - color: $dark-text-color; - } - - div { - width: 6px; - height: 20px; - border-radius: $radius; - background: $primary-color; + padding: 0 20px; + + h3 { + font-size: 14px; + line-height: 24px; + text-align: left; + color: #333; } } +.card-content{ + padding: 0 20px 20px; +} diff --git a/web/components/Charts/AreaChart.vue b/web/components/Charts/AreaChart.vue index 7595e13..a966dea 100644 --- a/web/components/Charts/AreaChart.vue +++ b/web/components/Charts/AreaChart.vue @@ -4,17 +4,13 @@ import {useMainLayoutStore} from "~/strores/UseMainLayoutStore"; import type {PropType} from "vue"; import {ref} from 'vue'; -import dayjs from "dayjs"; import VChart from 'vue-echarts'; import _ from "lodash"; import {useSessionSignalRStore} from "~/strores/HubStore"; const dataStore = useDataStore() -const hubStore=useSessionSignalRStore() +const hubStore = useSessionSignalRStore() const mainLayoutStore = useMainLayoutStore() -type ArbitraryKeyValuePairs = { - [key: string]: (number | string)[]; -}; const chartRef = ref(null) const isLoading = ref(true) const props = defineProps({ @@ -33,7 +29,7 @@ const props = defineProps({ }) const option = computed(() => { return { - backgroundColor:'', + backgroundColor: '', //关闭动画 // animation: false, tooltip: { @@ -46,18 +42,19 @@ const option = computed(() => { } }, grid: { - left: '2%', + left: '0', right: '50', - bottom: '10%', + bottom: '38', + top: '15', containLabel: true }, xAxis: [ { type: 'time', - // boundaryGap: false - axisLabel:{ - showMinLabel:true, - showMaxLabel:true, + boundaryGap: false, + axisLabel: { + showMinLabel: true, + showMaxLabel: true, } }, ], @@ -66,15 +63,6 @@ const option = computed(() => { type: 'value', } ], - toolbox: { - feature: { - dataZoom: { - yAxisIndex: 'none' - }, - - saveAsImage: {} - } - }, dataZoom: [ { type: 'inside', @@ -100,18 +88,18 @@ const option = computed(() => { large: true, smooth: true, largeThreshold: 10000, - sampling:'lttb', + sampling: 'lttb', emphasis: { focus: 'series' }, markPoint: { data: [ - { type: 'max', name: 'Max' }, - { type: 'min', name: 'Min' } + {type: 'max', name: 'Max'}, + {type: 'min', name: 'Min'} ] }, markLine: { - data: [{ type: 'average', name: 'Avg' }] + data: [{type: 'average', name: 'Avg'}] }, data: [], } @@ -122,19 +110,34 @@ let interval: NodeJS.Timeout; onUnmounted(() => { clearInterval(interval); }) +let maxValue = 100; onMounted(() => { - setTimeout(()=>{ - hubStore.connection?.on("ReceiveDataHistory",(type:string,values:string[][])=>{ - isLoading.value = true; - chartRef.value.appendData({ - seriesIndex: props.valueIds?.indexOf(type), - data:values - }) - - isLoading.value = false; + if (!chartRef.value) { + console.error('ECharts instance is not initialized'); + return; + } + hubStore.connection?.on("ReceiveDataHistory", (type: string, values: [number,string][], done: boolean) => { + chartRef.value.appendData({ + seriesIndex: props.valueIds?.indexOf(type), + data: values }) - },1000) - setTimeout(()=>{ + if (done) { + //设置y轴最大值为数据最大值的140% + // const currentOption = chartRef.value.getOption(); + // const maxData = Math.max(...values.map(item =>item[1])); + + // if (maxData > maxValue) { + // maxValue = maxData + // currentOption.yAxis[0].max = maxData * 1.4; + // chartRef.value.setOption(currentOption); + // } + + } + isLoading.value = false; + }) + + + setTimeout(() => { $fetch('/Api/Server/GetServerHistoryDate', { method: 'GET', headers: { @@ -147,53 +150,8 @@ onMounted(() => { }, baseURL: useRuntimeConfig().public.baseUrl, }) - setTimeout(()=>{ - interval = setInterval(() => { - const data = dataStore.data - const time=Date.now() - props.valueIds?.forEach((id, index) => { - const newData = data[id] ?? 0 - chartRef.value.appendData({ - seriesIndex: index, - data: [[time,newData]] - }) - const currentOption = chartRef.value.getOption(); - chartRef.value.setOption(currentOption) - })},1000) - }) - },1000) - // let history = dataStore.dataHistory - // setTimeout(() => { - // isLoading.value = false; - // }, 5000) - // nextTick(() => { - // props.valueIds?.forEach((id, index) => { - // chartRet.value.appendData({ - // seriesIndex: index, - // data: history.data[id] - // }) - // }) - // const currentOption = chartRet.value.getOption(); - // currentOption.xAxis[0].data = history.times - // chartRet.value.setOption(currentOption) - // isLoading.value = false - // interval = setInterval(() => { - // const data = dataStore.data - // props.valueIds?.forEach((id, index) => { - // const newData = data[id] ?? 0 - // if (!values.value[id]) { - // values.value[id] = [] - // } - // chartRet.value.appendData({ - // seriesIndex: index, - // data: [newData] - // }) - // }) - // const currentOption = chartRet.value.getOption(); - // currentOption.xAxis[0].data.push(dayjs().format('MM-DD HH:mm:ss')) - // chartRet.value.setOption(currentOption) - // }, 4000 + 1000 * Math.random()) - // }) + }, 2000) + }) // let endIndex = dataStore.dataHistory.times ? dataStore.dataHistory.times.length : 0 // let startTemp = 0; @@ -256,7 +214,7 @@ onMounted(() => { autoresize :theme="$colorMode.value" class="chart" - /> + />