|
@@ -1,298 +1,314 @@
|
|
<template>
|
|
<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="900px" :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"
|
|
|
|
+ />
|
|
|
|
+ <div class="flex">
|
|
|
|
+ <el-button type="primary" plain @click="refresh"
|
|
|
|
+ ><el-icon><Refresh /></el-icon>刷新</el-button
|
|
|
|
+ >
|
|
|
|
+ <el-button type="info" plain @click="exportData"
|
|
|
|
+ ><el-icon><Download /></el-icon>导出</el-button
|
|
|
|
+ >
|
|
|
|
+ </div>
|
|
|
|
+ </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>
|
|
</template>
|
|
|
|
|
|
<script lang="ts" setup>
|
|
<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, Refresh } 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) => {
|
|
const disabledDate = (time: Date) => {
|
|
- return time.getTime() > Date.now();
|
|
|
|
-};
|
|
|
|
|
|
+ return time.getTime() > Date.now()
|
|
|
|
+}
|
|
|
|
|
|
// 新增 Tab 相关状态
|
|
// 新增 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({
|
|
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) {
|
|
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 refresh() {
|
|
|
|
+ chengDateRangeType(historyDateRangeType.value)
|
|
}
|
|
}
|
|
|
|
|
|
function dateRangeChange() {
|
|
function dateRangeChange() {
|
|
- historyDateRangeType.value = "";
|
|
|
|
- fetchHistoryData();
|
|
|
|
|
|
+ historyDateRangeType.value = ''
|
|
|
|
+ fetchHistoryData()
|
|
}
|
|
}
|
|
|
|
|
|
// 初始化图表
|
|
// 初始化图表
|
|
const initChart = () => {
|
|
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 = () => {
|
|
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 = () => {
|
|
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 = () => {
|
|
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) => {
|
|
const handleSizeChange = (size: number) => {
|
|
- pageSize.value = size;
|
|
|
|
- fetchHistoryData();
|
|
|
|
-};
|
|
|
|
|
|
+ pageSize.value = size
|
|
|
|
+ fetchHistoryData()
|
|
|
|
+}
|
|
|
|
|
|
// 处理页码变化
|
|
// 处理页码变化
|
|
const handleCurrentChange = (page: number) => {
|
|
const handleCurrentChange = (page: number) => {
|
|
- currentPage.value = page;
|
|
|
|
- fetchHistoryData();
|
|
|
|
-};
|
|
|
|
|
|
+ currentPage.value = page
|
|
|
|
+ fetchHistoryData()
|
|
|
|
+}
|
|
|
|
|
|
// 导出数据
|
|
// 导出数据
|
|
const exportData = () => {
|
|
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(
|
|
watch(
|
|
- () => lineData.value,
|
|
|
|
- () => {
|
|
|
|
- nextTick(() => {
|
|
|
|
- updateChart();
|
|
|
|
- });
|
|
|
|
- },
|
|
|
|
- { deep: true }
|
|
|
|
-);
|
|
|
|
|
|
+ () => lineData.value,
|
|
|
|
+ () => {
|
|
|
|
+ nextTick(() => {
|
|
|
|
+ updateChart()
|
|
|
|
+ })
|
|
|
|
+ },
|
|
|
|
+ { deep: true }
|
|
|
|
+)
|
|
|
|
|
|
// 监听 loading 状态变化
|
|
// 监听 loading 状态变化
|
|
// watch(
|
|
// watch(
|
|
@@ -310,149 +326,149 @@ watch(
|
|
|
|
|
|
// 监听弹窗显示状态
|
|
// 监听弹窗显示状态
|
|
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(
|
|
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 = () => {
|
|
const toggleFullscreen = () => {
|
|
- isFullscreen.value = !isFullscreen.value;
|
|
|
|
- nextTick(() => {
|
|
|
|
- if (chartInstance) {
|
|
|
|
- chartInstance.resize();
|
|
|
|
- }
|
|
|
|
- });
|
|
|
|
-};
|
|
|
|
|
|
+ isFullscreen.value = !isFullscreen.value
|
|
|
|
+ nextTick(() => {
|
|
|
|
+ if (chartInstance) {
|
|
|
|
+ chartInstance.resize()
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+}
|
|
|
|
|
|
// 启动定时更新
|
|
// 启动定时更新
|
|
const startAutoUpdate = () => {
|
|
const startAutoUpdate = () => {
|
|
- // 先清除可能存在的定时器
|
|
|
|
- stopAutoUpdate();
|
|
|
|
|
|
+ // 先清除可能存在的定时器
|
|
|
|
+ stopAutoUpdate()
|
|
|
|
|
|
- // 创建新的定时器,每1秒更新一次数据
|
|
|
|
- updateTimer = window.setInterval(() => {
|
|
|
|
- fetchChartData();
|
|
|
|
- }, 1000); // 1秒
|
|
|
|
-};
|
|
|
|
|
|
+ // 创建新的定时器,每1秒更新一次数据
|
|
|
|
+ updateTimer = window.setInterval(() => {
|
|
|
|
+ fetchChartData()
|
|
|
|
+ }, 1000) // 1秒
|
|
|
|
+}
|
|
|
|
|
|
// 停止定时更新
|
|
// 停止定时更新
|
|
const stopAutoUpdate = () => {
|
|
const stopAutoUpdate = () => {
|
|
- if (updateTimer !== null) {
|
|
|
|
- window.clearInterval(updateTimer);
|
|
|
|
- updateTimer = null;
|
|
|
|
- }
|
|
|
|
-};
|
|
|
|
|
|
+ if (updateTimer !== null) {
|
|
|
|
+ window.clearInterval(updateTimer)
|
|
|
|
+ updateTimer = null
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
|
|
// 组件卸载前清除定时器
|
|
// 组件卸载前清除定时器
|
|
onBeforeUnmount(() => {
|
|
onBeforeUnmount(() => {
|
|
- stopAutoUpdate();
|
|
|
|
-});
|
|
|
|
|
|
+ stopAutoUpdate()
|
|
|
|
+})
|
|
|
|
|
|
// 打开弹窗
|
|
// 打开弹窗
|
|
const openDialog = (row: any, deviceKey: string) => {
|
|
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>
|
|
</script>
|
|
<style scoped lang="scss">
|
|
<style scoped lang="scss">
|
|
.chart-container {
|
|
.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 {
|
|
.history-container {
|
|
- width: 100%;
|
|
|
|
|
|
+ width: 100%;
|
|
}
|
|
}
|
|
|
|
|
|
.date-picker-container {
|
|
.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 {
|
|
.pagination-container {
|
|
- margin-top: 15px;
|
|
|
|
- display: flex;
|
|
|
|
- justify-content: flex-end;
|
|
|
|
|
|
+ margin-top: 15px;
|
|
|
|
+ display: flex;
|
|
|
|
+ justify-content: flex-end;
|
|
}
|
|
}
|
|
|
|
|
|
.dialog-header {
|
|
.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 {
|
|
.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,
|
|
.fullscreen-btn,
|
|
.close-btn {
|
|
.close-btn {
|
|
- margin-left: 8px;
|
|
|
|
|
|
+ margin-left: 8px;
|
|
}
|
|
}
|
|
</style>
|
|
</style>
|