Эх сурвалжийг харах

fix: 设备属性实时数据更新从 10s 改为 1s

yanglzh 7 сар өмнө
parent
commit
8859f9e5ed

+ 356 - 363
src/views/iot/device/instance/component/chart.vue

@@ -1,305 +1,298 @@
 <template>
-	<div class="system-edit-dic-container">
-		<el-dialog v-model="isShowDialog" :title="data.name + `(${data.key})`" width="850px" :fullscreen="isFullscreen" destroy-on-close>
-			<template #header="{ close, titleId, titleClass }">
-				<div class="dialog-header">
-					<h4 :id="titleId" :class="titleClass">{{ data.name + `(${data.key})` }}</h4>
-					<div class="dialog-header-actions">
-						<el-button type="text" @click="toggleFullscreen" class="fullscreen-btn">
-							<i class="iconfont" :class="!isFullscreen ? 'icon-fullscreen' : 'icon-tuichuquanping'"></i>
-						</el-button>
-					</div>
-				</div>
-			</template>
-			<!-- 添加 tab 切换 -->
-			<el-tabs v-model="activeTab">
-				<el-tab-pane label="趋势图" name="trend">
-					<!-- 这里是 echarts 线图 -->
-					<div id="lineChart" ref="chartRef" class="chart-container" :class="{ 'chart-container-big': isFullscreen }"></div>
-				</el-tab-pane>
-				<el-tab-pane label="历史数据" name="history">
-					<!-- 历史日志数据表格 -->
-					<div class="history-container">
-						<div class="date-picker-container">
-							<el-radio-group v-model="historyDateRangeType" @change="chengDateRangeType">
-								<el-radio-button label="1">最近半小时</el-radio-button>
-								<el-radio-button label="2">最近1小时</el-radio-button>
-								<el-radio-button label="3">最近12小时</el-radio-button>
-							</el-radio-group>
-							<el-date-picker
-								v-model="params.dateRange"
-								:disabled-date="disabledDate"
-								type="datetimerange"
-								range-separator="至"
-								start-placeholder="开始日期"
-								end-placeholder="结束日期"
-								format="YYYY-MM-DD HH:mm:ss"
-								value-format="YYYY-MM-DD HH:mm:ss"
-								@change="dateRangeChange()"
-								style="width: 220px"
-							/>
-							<el-button type="primary" @click="exportData"
-								><el-icon><Download /></el-icon>导出</el-button
-							>
-						</div>
-						<el-table
-							:data="historyData"
-							border
-							style="width: 100%"
-							v-loading="historyLoading"
-							:max-height="isFullscreen ? 'calc(100vh - 250px)' : 'calc(90vh - 300px)'"
-						>
-							<el-table-column prop="dataTime" label="时间" align="center" />
-							<el-table-column prop="dataValue" label="属性值" align="center" />
-							<el-table-column prop="unit" label="数据单位" align="center">
-								<template #default>{{ data.unit }}</template>
-							</el-table-column>
-						</el-table>
-						<div class="pagination-container">
-							<el-pagination
-								v-model:current-page="currentPage"
-								v-model:page-size="pageSize"
-								:page-sizes="[10, 20, 50, 100]"
-								layout="total, sizes, prev, pager, next, jumper"
-								:total="totalItems"
-								@size-change="handleSizeChange"
-								@current-change="handleCurrentChange"
-							/>
-						</div>
-					</div>
-				</el-tab-pane>
-			</el-tabs>
-		</el-dialog>
-	</div>
+  <div class="system-edit-dic-container">
+    <el-dialog v-model="isShowDialog" :title="data.name + `(${data.key})`" width="850px" :fullscreen="isFullscreen" destroy-on-close>
+      <template #header="{ close, titleId, titleClass }">
+        <div class="dialog-header">
+          <h4 :id="titleId" :class="titleClass">{{ data.name + `(${data.key})` }}</h4>
+          <div class="dialog-header-actions">
+            <el-button type="text" @click="toggleFullscreen" class="fullscreen-btn">
+              <i class="iconfont" :class="!isFullscreen ? 'icon-fullscreen' : 'icon-tuichuquanping'"></i>
+            </el-button>
+          </div>
+        </div>
+      </template>
+      <!-- 添加 tab 切换 -->
+      <el-tabs v-model="activeTab">
+        <el-tab-pane label="趋势图" name="trend">
+          <!-- 这里是 echarts 线图 -->
+          <div id="lineChart" ref="chartRef" class="chart-container" :class="{ 'chart-container-big': isFullscreen }"></div>
+        </el-tab-pane>
+        <el-tab-pane label="历史数据" name="history">
+          <!-- 历史日志数据表格 -->
+          <div class="history-container">
+            <div class="date-picker-container">
+              <el-radio-group v-model="historyDateRangeType" @change="chengDateRangeType">
+                <el-radio-button label="1">最近半小时</el-radio-button>
+                <el-radio-button label="2">最近1小时</el-radio-button>
+                <el-radio-button label="3">最近12小时</el-radio-button>
+              </el-radio-group>
+              <el-date-picker
+                v-model="params.dateRange"
+                :disabled-date="disabledDate"
+                type="datetimerange"
+                range-separator="至"
+                start-placeholder="开始日期"
+                end-placeholder="结束日期"
+                format="YYYY-MM-DD HH:mm:ss"
+                value-format="YYYY-MM-DD HH:mm:ss"
+                @change="dateRangeChange()"
+                style="width: 220px"
+              />
+              <el-button type="primary" @click="exportData"
+                ><el-icon><Download /></el-icon>导出</el-button
+              >
+            </div>
+            <el-table :data="historyData" border style="width: 100%" v-loading="historyLoading" :max-height="isFullscreen ? 'calc(100vh - 250px)' : 'calc(90vh - 300px)'">
+              <el-table-column prop="dataTime" label="时间" align="center" />
+              <el-table-column prop="dataValue" label="属性值" align="center" />
+              <el-table-column prop="unit" label="数据单位" align="center">
+                <template #default>{{ data.unit }}</template>
+              </el-table-column>
+            </el-table>
+            <div class="pagination-container">
+              <el-pagination
+                v-model:current-page="currentPage"
+                v-model:page-size="pageSize"
+                :page-sizes="[10, 20, 50, 100]"
+                layout="total, sizes, prev, pager, next, jumper"
+                :total="totalItems"
+                @size-change="handleSizeChange"
+                @current-change="handleCurrentChange"
+              />
+            </div>
+          </div>
+        </el-tab-pane>
+      </el-tabs>
+    </el-dialog>
+  </div>
 </template>
 
 <script lang="ts" setup>
-import { ref, reactive, watch, nextTick, onBeforeUnmount, onMounted } from 'vue'
-import api from '/@/api/device'
-import * as echarts from 'echarts'
-import dayjs from 'dayjs'
-import { Download, FullScreen } from '@element-plus/icons-vue'
-import downloadFile from '/@/utils/download'
-
-const data = ref({ name: '', key: '', unit: '' })
-const historyDateRangeType = ref('1')
-const loading = ref(false)
-const isShowDialog = ref(false)
-const chartRef = ref()
-let chartInstance: echarts.ECharts | null = null
-const lineData = ref([])
+import { ref, reactive, watch, nextTick, onBeforeUnmount, onMounted } from "vue";
+import api from "/@/api/device";
+import * as echarts from "echarts";
+import dayjs from "dayjs";
+import { Download, FullScreen } from "@element-plus/icons-vue";
+import downloadFile from "/@/utils/download";
+
+const data = ref({ name: "", key: "", unit: "" });
+const historyDateRangeType = ref("1");
+const loading = ref(false);
+const isShowDialog = ref(false);
+const chartRef = ref();
+let chartInstance: echarts.ECharts | null = null;
+const lineData = ref([]);
 
 // 定时器引用
-let updateTimer: number | null = null
+let updateTimer: number | null = null;
 
 const disabledDate = (time: Date) => {
-	return time.getTime() > Date.now()
-}
+  return time.getTime() > Date.now();
+};
 
 // 新增 Tab 相关状态
-const activeTab = ref('trend')
-const historyData = ref([])
-const historyLoading = ref(false)
-const currentPage = ref(1)
-const pageSize = ref(10)
-const totalItems = ref(0)
+const activeTab = ref("trend");
+const historyData = ref([]);
+const historyLoading = ref(false);
+const currentPage = ref(1);
+const pageSize = ref(10);
+const totalItems = ref(0);
 
 const params = reactive({
-	deviceKey: '',
-	properties: '',
-	dateRange: [dayjs().subtract(30, 'minute').format('YYYY-MM-DD HH:mm:ss'), dayjs().format('YYYY-MM-DD HH:mm:ss')],
-})
+  deviceKey: "",
+  properties: "",
+  dateRange: [dayjs().subtract(30, "minute").format("YYYY-MM-DD HH:mm:ss"), dayjs().format("YYYY-MM-DD HH:mm:ss")],
+});
 
 function chengDateRangeType(type: string) {
-	if (type === '1') {
-		params.dateRange = [dayjs().subtract(30, 'minute').format('YYYY-MM-DD HH:mm:ss'), dayjs().format('YYYY-MM-DD HH:mm:ss')]
-	} else if (type === '2') {
-		params.dateRange = [dayjs().subtract(1, 'hour').format('YYYY-MM-DD HH:mm:ss'), dayjs().format('YYYY-MM-DD HH:mm:ss')]
-	} else if (type === '3') {
-		params.dateRange = [dayjs().subtract(12, 'hour').format('YYYY-MM-DD HH:mm:ss'), dayjs().format('YYYY-MM-DD HH:mm:ss')]
-	}
-	fetchHistoryData()
+  if (type === "1") {
+    params.dateRange = [dayjs().subtract(30, "minute").format("YYYY-MM-DD HH:mm:ss"), dayjs().format("YYYY-MM-DD HH:mm:ss")];
+  } else if (type === "2") {
+    params.dateRange = [dayjs().subtract(1, "hour").format("YYYY-MM-DD HH:mm:ss"), dayjs().format("YYYY-MM-DD HH:mm:ss")];
+  } else if (type === "3") {
+    params.dateRange = [dayjs().subtract(12, "hour").format("YYYY-MM-DD HH:mm:ss"), dayjs().format("YYYY-MM-DD HH:mm:ss")];
+  }
+  fetchHistoryData();
 }
 
 function dateRangeChange() {
-	historyDateRangeType.value = ''
-	fetchHistoryData()
+  historyDateRangeType.value = "";
+  fetchHistoryData();
 }
 
 // 初始化图表
 const initChart = () => {
-	if (chartRef.value) {
-		// 如果已有实例先销毁
-		if (chartInstance) {
-			chartInstance.dispose()
-		}
-		// 创建图表实例
-		chartInstance = echarts.init(chartRef.value)
-		// 设置加载状态
-		// if (loading.value) {
-		// 	chartInstance.showLoading()
-		// } else {
-		// 	chartInstance.hideLoading()
-		// }
-		// 更新图表
-		updateChart()
-	}
-}
+  if (chartRef.value) {
+    // 如果已有实例先销毁
+    if (chartInstance) {
+      chartInstance.dispose();
+    }
+    // 创建图表实例
+    chartInstance = echarts.init(chartRef.value);
+    // 设置加载状态
+    // if (loading.value) {
+    // 	chartInstance.showLoading()
+    // } else {
+    // 	chartInstance.hideLoading()
+    // }
+    // 更新图表
+    updateChart();
+  }
+};
 
 // 更新图表数据
 const updateChart = () => {
-	if (!chartInstance) return
-
-	// 从 lineData 中提取数据
-	const xData = lineData.value.map((item: any) => item.ts?.slice(10)).reverse()
-	const yData = lineData.value.map((item: any) => item.value).reverse()
-
-	// 配置图表选项
-	const option = {
-		tooltip: {
-			trigger: 'axis',
-			formatter: '{b}<br />{a}: {c}',
-		},
-		grid: {
-			top: 15,
-			left: 40,
-			right: 30,
-			bottom: 50, // 增加底部空间,为 dataZoom 留出位置
-			containLabel: true,
-		},
-		dataZoom: [
-			{
-				type: 'slider', // 滑动条型数据区域缩放组件
-				show: true,
-				start: 0,
-				end: 100,
-				height: 20,
-				bottom: 10,
-				borderColor: 'transparent',
-				backgroundColor: '#f5f5f5',
-				fillerColor: 'rgba(167, 183, 204, 0.4)',
-				handleIcon:
-					'M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z',
-				handleSize: '80%',
-				handleStyle: {
-					color: '#fff',
-					shadowBlur: 3,
-					shadowColor: 'rgba(0, 0, 0, 0.6)',
-					shadowOffsetX: 2,
-					shadowOffsetY: 2,
-				},
-			},
-			{
-				type: 'inside', // 内置型数据区域缩放组件,允许鼠标滚轮或触摸板缩放
-				start: 0,
-				end: 100,
-			},
-		],
-		xAxis: {
-			type: 'category',
-			data: xData,
-			axisLabel: {
-				rotate: 0,
-			},
-		},
-		yAxis: {
-			type: 'value',
-			splitLine: {
-				show: true,
-				lineStyle: {
-					color: 'rgba(88,88,88,0.5)',
-				},
-			},
-		},
-		series: [
-			{
-				name: '数值',
-				type: 'line',
-				data: yData,
-				smooth: true,
-				lineStyle: {
-					width: 2,
-				},
-				symbolSize: 4,
-			},
-		],
-	}
-
-	// 设置图表配置
-	chartInstance.setOption(option)
-}
+  if (!chartInstance) return;
+
+  // 从 lineData 中提取数据
+  const xData = lineData.value.map((item: any) => item.ts?.slice(10)).reverse();
+  const yData = lineData.value.map((item: any) => item.value).reverse();
+
+  // 配置图表选项
+  const option = {
+    tooltip: {
+      trigger: "axis",
+      formatter: "{b}<br />{a}: {c}",
+    },
+    grid: {
+      top: 15,
+      left: 40,
+      right: 30,
+      bottom: 50, // 增加底部空间,为 dataZoom 留出位置
+      containLabel: true,
+    },
+    dataZoom: [
+      {
+        type: "slider", // 滑动条型数据区域缩放组件
+        show: true,
+        start: 0,
+        end: 100,
+        height: 20,
+        bottom: 10,
+        borderColor: "transparent",
+        backgroundColor: "#f5f5f5",
+        fillerColor: "rgba(167, 183, 204, 0.4)",
+        handleIcon: "M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z",
+        handleSize: "80%",
+        handleStyle: {
+          color: "#fff",
+          shadowBlur: 3,
+          shadowColor: "rgba(0, 0, 0, 0.6)",
+          shadowOffsetX: 2,
+          shadowOffsetY: 2,
+        },
+      },
+      {
+        type: "inside", // 内置型数据区域缩放组件,允许鼠标滚轮或触摸板缩放
+        start: 0,
+        end: 100,
+      },
+    ],
+    xAxis: {
+      type: "category",
+      data: xData,
+      axisLabel: {
+        rotate: 0,
+      },
+    },
+    yAxis: {
+      type: "value",
+      splitLine: {
+        show: true,
+        lineStyle: {
+          color: "rgba(88,88,88,0.5)",
+        },
+      },
+    },
+    series: [
+      {
+        name: "数值",
+        type: "line",
+        data: yData,
+        smooth: true,
+        lineStyle: {
+          width: 2,
+        },
+        symbolSize: 4,
+      },
+    ],
+  };
+
+  // 设置图表配置
+  chartInstance.setOption(option);
+};
 
 // 获取图表数据
 const fetchChartData = () => {
-	if (!params.deviceKey || !params.properties) return
-	
-	loading.value = true
-	api.instance
-		.getLogDetail({
-			deviceKey: params.deviceKey,
-			propertyKey: params.properties,
-			pageSize: 100,
-		})
-		.then((res: any) => {
-			lineData.value = res.List
-		})
-		.finally(() => (loading.value = false))
-}
+  if (!params.deviceKey || !params.properties) return;
+
+  loading.value = true;
+  api.instance
+    .getLogDetail({
+      deviceKey: params.deviceKey,
+      propertyKey: params.properties,
+      pageSize: 100,
+    })
+    .then((res: any) => {
+      lineData.value = res.List;
+    })
+    .finally(() => (loading.value = false));
+};
 
 // 获取历史数据
 const fetchHistoryData = () => {
-	if (!params.deviceKey || !params.properties) return
-
-	historyLoading.value = true
-
-	const historyParams = {
-		...params,
-		pageNum: currentPage.value,
-		pageSize: pageSize.value,
-	}
-
-	api.device
-		.getDeviceAttributesHistoryList(historyParams)
-		.then((res: any) => {
-			historyData.value = res.list
-			totalItems.value = res.Total
-		})
-		.catch(() => {
-			historyData.value = []
-			totalItems.value = 0
-		})
-		.finally(() => (historyLoading.value = false))
-}
+  if (!params.deviceKey || !params.properties) return;
+
+  historyLoading.value = true;
+
+  const historyParams = {
+    ...params,
+    pageNum: currentPage.value,
+    pageSize: pageSize.value,
+  };
+
+  api.device
+    .getDeviceAttributesHistoryList(historyParams)
+    .then((res: any) => {
+      historyData.value = res.list;
+      totalItems.value = res.Total;
+    })
+    .catch(() => {
+      historyData.value = [];
+      totalItems.value = 0;
+    })
+    .finally(() => (historyLoading.value = false));
+};
 
 // 处理分页大小变化
 const handleSizeChange = (size: number) => {
-	pageSize.value = size
-	fetchHistoryData()
-}
+  pageSize.value = size;
+  fetchHistoryData();
+};
 
 // 处理页码变化
 const handleCurrentChange = (page: number) => {
-	currentPage.value = page
-	fetchHistoryData()
-}
+  currentPage.value = page;
+  fetchHistoryData();
+};
 
 // 导出数据
 const exportData = () => {
-	api.device.getDeviceAttributesHistoryListExport(params).then((res: any) => {
-		downloadFile(res, `${data.value.name}(${data.value.key}) 历史数据导出.xlsx`)
-	})
-}
+  api.device.getDeviceAttributesHistoryListExport(params).then((res: any) => {
+    downloadFile(res, `${data.value.name}(${data.value.key}) 历史数据导出.xlsx`);
+  });
+};
 
 // 监听数据变化,更新图表
 watch(
-	() => lineData.value,
-	() => {
-		nextTick(() => {
-			updateChart()
-		})
-	},
-	{ deep: true }
-)
+  () => lineData.value,
+  () => {
+    nextTick(() => {
+      updateChart();
+    });
+  },
+  { deep: true }
+);
 
 // 监听 loading 状态变化
 // watch(
@@ -317,149 +310,149 @@ watch(
 
 // 监听弹窗显示状态
 watch(
-	() => isShowDialog.value,
-	(val) => {
-		if (val) {
-			nextTick(() => {
-				initChart()
-				// 重置分页
-				currentPage.value = 1
-				// 如果是历史日志标签页,加载历史数据
-				if (activeTab.value === 'history') {
-					fetchHistoryData()
-				} else if (activeTab.value === 'trend') {
-					// 如果是趋势图标签页,启动自动更新
-					startAutoUpdate()
-				}
-			})
-		} else {
-			// 关闭弹窗时停止自动更新
-			stopAutoUpdate()
-		}
-	}
-)
+  () => isShowDialog.value,
+  (val) => {
+    if (val) {
+      nextTick(() => {
+        initChart();
+        // 重置分页
+        currentPage.value = 1;
+        // 如果是历史日志标签页,加载历史数据
+        if (activeTab.value === "history") {
+          fetchHistoryData();
+        } else if (activeTab.value === "trend") {
+          // 如果是趋势图标签页,启动自动更新
+          startAutoUpdate();
+        }
+      });
+    } else {
+      // 关闭弹窗时停止自动更新
+      stopAutoUpdate();
+    }
+  }
+);
 
 // 监听标签页切换
 watch(
-	() => activeTab.value,
-	(val) => {
-		if (val === 'history' && isShowDialog.value) {
-			// 切换到历史数据标签页时停止自动更新
-			stopAutoUpdate()
-			fetchHistoryData()
-		} else if (val === 'trend' && isShowDialog.value) {
-			nextTick(() => {
-				initChart()
-				// 切换到趋势图标签页时启动自动更新
-				startAutoUpdate()
-			})
-		}
-	}
-)
-
-const isFullscreen = ref(false)
+  () => activeTab.value,
+  (val) => {
+    if (val === "history" && isShowDialog.value) {
+      // 切换到历史数据标签页时停止自动更新
+      stopAutoUpdate();
+      fetchHistoryData();
+    } else if (val === "trend" && isShowDialog.value) {
+      nextTick(() => {
+        initChart();
+        // 切换到趋势图标签页时启动自动更新
+        startAutoUpdate();
+      });
+    }
+  }
+);
+
+const isFullscreen = ref(false);
 
 // 切换全屏状态
 const toggleFullscreen = () => {
-	isFullscreen.value = !isFullscreen.value
-	nextTick(() => {
-		if (chartInstance) {
-			chartInstance.resize()
-		}
-	})
-}
+  isFullscreen.value = !isFullscreen.value;
+  nextTick(() => {
+    if (chartInstance) {
+      chartInstance.resize();
+    }
+  });
+};
 
 // 启动定时更新
 const startAutoUpdate = () => {
-	// 先清除可能存在的定时器
-	stopAutoUpdate()
-	
-	// 创建新的定时器,每10秒更新一次数据
-	updateTimer = window.setInterval(() => {
-		fetchChartData()
-	}, 10000) // 10秒 = 10000毫
-}
+  // 先清除可能存在的定时器
+  stopAutoUpdate();
+
+  // 创建新的定时器,每1秒更新一次数据
+  updateTimer = window.setInterval(() => {
+    fetchChartData();
+  }, 1000); // 1
+};
 
 // 停止定时更新
 const stopAutoUpdate = () => {
-	if (updateTimer !== null) {
-		window.clearInterval(updateTimer)
-		updateTimer = null
-	}
-}
+  if (updateTimer !== null) {
+    window.clearInterval(updateTimer);
+    updateTimer = null;
+  }
+};
 
 // 组件卸载前清除定时器
 onBeforeUnmount(() => {
-	stopAutoUpdate()
-})
+  stopAutoUpdate();
+});
 
 // 打开弹窗
 const openDialog = (row: any, deviceKey: string) => {
-	params.deviceKey = deviceKey
-	params.properties = row.key
-
-	// 重置日期范围
-	historyDateRangeType.value = '1'
-	params.dateRange = [dayjs().subtract(30, 'minute').format('YYYY-MM-DD HH:mm:ss'), dayjs().format('YYYY-MM-DD HH:mm:ss')]
-	data.value = row
-	isShowDialog.value = true
-	
-	// 获取初始数据
-	fetchChartData()
-	
-	// 如果是趋势图标签页,启动自动更新
-	if (activeTab.value === 'trend') {
-		startAutoUpdate()
-	}
-}
+  params.deviceKey = deviceKey;
+  params.properties = row.key;
+
+  // 重置日期范围
+  historyDateRangeType.value = "1";
+  params.dateRange = [dayjs().subtract(30, "minute").format("YYYY-MM-DD HH:mm:ss"), dayjs().format("YYYY-MM-DD HH:mm:ss")];
+  data.value = row;
+  isShowDialog.value = true;
+
+  // 获取初始数据
+  fetchChartData();
+
+  // 如果是趋势图标签页,启动自动更新
+  if (activeTab.value === "trend") {
+    startAutoUpdate();
+  }
+};
 
-defineExpose({ openDialog })
+defineExpose({ openDialog });
 </script>
 <style scoped lang="scss">
 .chart-container {
-	width: 100%;
-	height: calc(90vh - 350px);
-	&-big {
-		height: calc(100vh - 180px);
-	}
+  width: 100%;
+  height: calc(90vh - 350px);
+  &-big {
+    height: calc(100vh - 180px);
+  }
 }
 
 .history-container {
-	width: 100%;
+  width: 100%;
 }
 
 .date-picker-container {
-	display: flex;
-	justify-content: space-between;
-	margin-bottom: 15px;
-	gap: 15px;
+  display: flex;
+  justify-content: space-between;
+  margin-bottom: 15px;
+  gap: 15px;
 }
 
 .pagination-container {
-	margin-top: 15px;
-	display: flex;
-	justify-content: flex-end;
+  margin-top: 15px;
+  display: flex;
+  justify-content: flex-end;
 }
 
 .dialog-header {
-	display: flex;
-	justify-content: space-between;
-	align-items: center;
-	width: 100%;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  width: 100%;
 }
 
 .dialog-header-actions {
-	display: flex;
-	align-items: center;
-	margin-top: -4px;
-	margin-right: 12px;
-	.iconfont {
-		font-size: 18px !important;
-	}
+  display: flex;
+  align-items: center;
+  margin-top: -4px;
+  margin-right: 12px;
+  .iconfont {
+    font-size: 18px !important;
+  }
 }
 
 .fullscreen-btn,
 .close-btn {
-	margin-left: 8px;
+  margin-left: 8px;
 }
 </style>