|
|
@@ -1,6 +1,6 @@
|
|
|
<!-- 设备物模型 -> 运行状态 -> 查看数据(设备的属性值历史)-->
|
|
|
<template>
|
|
|
- <Dialog title="查看数据" v-model="dialogVisible">
|
|
|
+ <Dialog title="查看数据" v-model="dialogVisible" width="1024px">
|
|
|
<ContentWrap>
|
|
|
<!-- 搜索工作栏 -->
|
|
|
<el-form
|
|
|
@@ -10,52 +10,68 @@
|
|
|
:inline="true"
|
|
|
label-width="68px"
|
|
|
>
|
|
|
- <el-form-item label="时间" prop="createTime">
|
|
|
+ <el-form-item label="" prop="createTime">
|
|
|
<el-date-picker
|
|
|
v-model="queryParams.times"
|
|
|
value-format="YYYY-MM-DD HH:mm:ss"
|
|
|
type="datetimerange"
|
|
|
start-placeholder="开始日期"
|
|
|
end-placeholder="结束日期"
|
|
|
- class="!w-350px"
|
|
|
+ class="!w-360px"
|
|
|
+ @change="handleTimeChange"
|
|
|
/>
|
|
|
</el-form-item>
|
|
|
- <el-form-item>
|
|
|
- <el-button @click="handleQuery">
|
|
|
- <Icon icon="ep:search" class="mr-5px" />
|
|
|
- 搜索
|
|
|
- </el-button>
|
|
|
+ <el-form-item class="float-right !mr-0 !mb-0">
|
|
|
+ <el-button-group>
|
|
|
+ <el-button
|
|
|
+ :type="viewMode === 'chart' ? 'primary' : 'default'"
|
|
|
+ @click="viewMode = 'chart'"
|
|
|
+ >
|
|
|
+ <Icon icon="ep:histogram" />
|
|
|
+ </el-button>
|
|
|
+ <el-button
|
|
|
+ :type="viewMode === 'list' ? 'primary' : 'default'"
|
|
|
+ @click="viewMode = 'list'"
|
|
|
+ >
|
|
|
+ <Icon icon="ep:list" />
|
|
|
+ </el-button>
|
|
|
+ </el-button-group>
|
|
|
</el-form-item>
|
|
|
</el-form>
|
|
|
</ContentWrap>
|
|
|
|
|
|
- <!-- TODO @haohao:可参考阿里云 IoT,改成“图标”、“表格”两个选项 -->
|
|
|
- <!-- 列表 -->
|
|
|
+ <!-- 数据展示区域 -->
|
|
|
<ContentWrap>
|
|
|
- <el-table v-loading="detailLoading" :data="list" :stripe="true" :show-overflow-tooltip="true">
|
|
|
- <el-table-column
|
|
|
- label="时间"
|
|
|
- align="center"
|
|
|
- prop="updateTime"
|
|
|
- :formatter="dateFormatter"
|
|
|
- width="180px"
|
|
|
- />
|
|
|
- <el-table-column label="属性值" align="center" prop="value" />
|
|
|
- </el-table>
|
|
|
- <!-- 分页 -->
|
|
|
- <Pagination
|
|
|
- :total="total"
|
|
|
- v-model:page="queryParams.pageNo"
|
|
|
- v-model:limit="queryParams.pageSize"
|
|
|
- @pagination="getList"
|
|
|
- />
|
|
|
+ <!-- 图表模式 -->
|
|
|
+ <div v-if="viewMode === 'chart'" class="chart-container">
|
|
|
+ <div v-if="sortedList.length === 0" class="text-center text-gray-500 py-20"> 暂无数据 </div>
|
|
|
+ <Echart v-else :options="echartsOption" height="400px" />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 表格模式 -->
|
|
|
+ <div v-else>
|
|
|
+ <el-table
|
|
|
+ v-loading="detailLoading"
|
|
|
+ :data="sortedList"
|
|
|
+ :stripe="true"
|
|
|
+ :show-overflow-tooltip="true"
|
|
|
+ >
|
|
|
+ <el-table-column label="时间" align="center" prop="time" width="180px">
|
|
|
+ <template #default="scope">
|
|
|
+ {{ formatDate(new Date(scope.row.updateTime)) }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="属性值" align="center" prop="value" />
|
|
|
+ </el-table>
|
|
|
+ </div>
|
|
|
</ContentWrap>
|
|
|
</Dialog>
|
|
|
</template>
|
|
|
<script setup lang="ts">
|
|
|
import { DeviceApi, DeviceHistoryDataVO, DeviceVO } from '@/api/iot/device/device'
|
|
|
import { ProductVO } from '@/api/iot/product/product'
|
|
|
-import { beginOfDay, dateFormatter, endOfDay, formatDate } from '@/utils/formatTime'
|
|
|
+import { beginOfDay, endOfDay, formatDate } from '@/utils/formatTime'
|
|
|
+import { Echart } from '@/components/Echart'
|
|
|
|
|
|
defineProps<{ product: ProductVO; device: DeviceVO }>()
|
|
|
|
|
|
@@ -64,12 +80,94 @@ defineOptions({ name: 'IoTDeviceDataDetail' })
|
|
|
|
|
|
const dialogVisible = ref(false) // 弹窗的是否展示
|
|
|
const detailLoading = ref(false)
|
|
|
+const viewMode = ref<'chart' | 'list'>('chart') // 视图模式状态
|
|
|
|
|
|
const list = ref<DeviceHistoryDataVO[]>([]) // 列表的数据
|
|
|
-const total = ref(0) // 列表的总页数
|
|
|
+
|
|
|
+// 根据视图模式排序的数据
|
|
|
+const sortedList = computed(() => {
|
|
|
+ if (!list.value || list.value.length === 0) return []
|
|
|
+
|
|
|
+ const sortedData = [...list.value]
|
|
|
+
|
|
|
+ if (viewMode.value === 'list') {
|
|
|
+ // 列表模式:按时间倒序(最新的在前)
|
|
|
+ return sortedData.sort((a, b) => b.time - a.time)
|
|
|
+ } else {
|
|
|
+ // 图表模式:按时间升序(最早的在前)
|
|
|
+ return sortedData.sort((a, b) => a.time - b.time)
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+// Echarts 配置
|
|
|
+const echartsOption = reactive<any>({
|
|
|
+ title: {
|
|
|
+ text: '设备数据趋势',
|
|
|
+ left: 'center'
|
|
|
+ },
|
|
|
+ grid: {
|
|
|
+ left: 60,
|
|
|
+ right: 40,
|
|
|
+ bottom: 80,
|
|
|
+ top: 80,
|
|
|
+ containLabel: true
|
|
|
+ },
|
|
|
+ tooltip: {
|
|
|
+ trigger: 'axis',
|
|
|
+ axisPointer: {
|
|
|
+ type: 'cross'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ xAxis: {
|
|
|
+ type: 'time',
|
|
|
+ name: '时间',
|
|
|
+ axisLabel: {
|
|
|
+ formatter: (value: number) => formatDate(new Date(value), 'MM-DD HH:mm')
|
|
|
+ }
|
|
|
+ },
|
|
|
+ yAxis: {
|
|
|
+ type: 'value',
|
|
|
+ name: '属性值'
|
|
|
+ },
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ name: '属性值',
|
|
|
+ type: 'line',
|
|
|
+ smooth: true,
|
|
|
+ symbol: 'circle',
|
|
|
+ symbolSize: 6,
|
|
|
+ lineStyle: {
|
|
|
+ width: 2,
|
|
|
+ color: '#1890FF'
|
|
|
+ },
|
|
|
+ itemStyle: {
|
|
|
+ color: '#1890FF'
|
|
|
+ },
|
|
|
+ data: []
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ dataZoom: [
|
|
|
+ {
|
|
|
+ type: 'inside'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ type: 'slider',
|
|
|
+ height: 30
|
|
|
+ }
|
|
|
+ ]
|
|
|
+})
|
|
|
+
|
|
|
+// 更新图表数据
|
|
|
+const updateChartData = () => {
|
|
|
+ if (echartsOption.series && echartsOption.series[0]) {
|
|
|
+ echartsOption.series[0].data = sortedList.value.map((item) => [
|
|
|
+ item.updateTime,
|
|
|
+ parseFloat(item.value) || 0
|
|
|
+ ])
|
|
|
+ debugger
|
|
|
+ }
|
|
|
+}
|
|
|
const queryParams = reactive({
|
|
|
- pageNo: 1,
|
|
|
- pageSize: 10,
|
|
|
deviceId: -1,
|
|
|
identifier: '',
|
|
|
times: [
|
|
|
@@ -84,9 +182,12 @@ const queryFormRef = ref() // 搜索的表单
|
|
|
const getList = async () => {
|
|
|
detailLoading.value = true
|
|
|
try {
|
|
|
- const data = await DeviceApi.getHistoryDevicePropertyPage(queryParams)
|
|
|
- list.value = data.list
|
|
|
- total.value = data.total
|
|
|
+ const data = await DeviceApi.getHistoryDevicePropertyList(queryParams)
|
|
|
+ list.value = data || []
|
|
|
+ // 数据获取后更新图表
|
|
|
+ nextTick(() => {
|
|
|
+ updateChartData()
|
|
|
+ })
|
|
|
} finally {
|
|
|
detailLoading.value = false
|
|
|
}
|
|
|
@@ -100,11 +201,21 @@ const open = (deviceId: number, identifier: string) => {
|
|
|
getList()
|
|
|
}
|
|
|
|
|
|
-/** 搜索按钮操作 */
|
|
|
-const handleQuery = () => {
|
|
|
- queryParams.pageNo = 1
|
|
|
+/** 时间变化处理 */
|
|
|
+const handleTimeChange = () => {
|
|
|
getList()
|
|
|
}
|
|
|
|
|
|
+// 监听数据变化,更新图表
|
|
|
+watch(
|
|
|
+ () => sortedList.value,
|
|
|
+ () => {
|
|
|
+ if (viewMode.value === 'chart') {
|
|
|
+ updateChartData()
|
|
|
+ }
|
|
|
+ },
|
|
|
+ { deep: true }
|
|
|
+)
|
|
|
+
|
|
|
defineExpose({ open }) // 提供 open 方法,用于打开弹窗
|
|
|
</script>
|