123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 |
- <template>
- <ContentWrap v-loading="formLoading">
- <ContentWrap>
- <el-form style="height:89px;margin-left: 20px;">
- <el-row style="display: flex;flex-direction: row; ">
- <el-col :span="8">
- <el-form-item prop="deviceCode">
- <template #label>
- <span class="custom-label">资产编码:</span>
- </template>
- <span class="custom-label">{{ formData.deviceCode }}</span>
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item prop="deviceName">
- <template #label>
- <span class="custom-label">设备类别:</span>
- </template>
- <span class="custom-label">{{ formData.deviceName }}</span>
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item prop="dept">
- <template #label>
- <span class="custom-label">所在部门:</span>
- </template>
- <span class="custom-label">{{ formData.dept }}</span>
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item prop="ifInline">
- <template #label>
- <span class="custom-label">是否在线:</span>
- </template>
- <!-- <span class="custom-label">{{ getDictLabel(DICT_TYPE.IOT_DEVICE_STATUS, formData.ifInline) }}</span>-->
- <!-- <span class="custom-label">-->
- <!-- {{ getDictLabel(DICT_TYPE.IOT_DEVICE_STATUS, formData.ifInline) }}-->
- <template #default>
- <dict-tag :type="DICT_TYPE.IOT_DEVICE_STATUS" :value="formData.ifInline" />
- </template>
- <!-- </span>-->
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item prop="lastInlineTime">
- <template #label>
- <span class="custom-label">最后数据时间:</span>
- </template>
- <span class="custom-label">{{ formData.lastInlineTime }}</span>
- </el-form-item>
- </el-col>
- </el-row>
- </el-form>
- </ContentWrap>
- <ContentWrap>
- <el-row>
- <el-col :span="24">
- <TdDeviceLabel :tags="specs" @select="labelSelect" tag-width="24%" />
- </el-col>
- </el-row>
- </ContentWrap>
- <ContentWrap>
- <div class="chart-container">
- <!-- 日期选择区域 -->
- <!-- <div class="date-controls">-->
- <!-- <input-->
- <!-- type="datetime-local"-->
- <!-- v-model="startTime"-->
- <!-- :max="endTime"-->
- <!-- @change="handleDateChange"-->
- <!-- />-->
- <!-- <span class="separator">至</span>-->
- <!-- <input-->
- <!-- type="datetime-local"-->
- <!-- v-model="endTime"-->
- <!-- :min="startTime"-->
- <!-- @change="handleDateChange"-->
- <!-- />-->
- <!-- <button class="query-btn" @click="fetchData">查询</button>-->
- <!-- </div>-->
- <!-- 图表容器 -->
- <div v-loading="loading" style="height: 100%" ref="chartContainer"></div>
- </div>
- </ContentWrap>
- </ContentWrap>
- </template>
- <script setup lang="ts">
- import { DICT_TYPE, getDictLabel } from '@/utils/dict'
- import TdDeviceLabel from '@/views/pms/device/monitor/TdDeviceLabel.vue'
- import {IotDeviceApi} from "@/api/pms/device";
- import * as echarts from 'echarts'
- import dayjs from 'dayjs'
- import {IotStatApi} from "@/api/pms/stat";
- const { params, name } = useRoute() // 查询参数
- const info = ref({})
- const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
- const id = params.id
- defineOptions({ name: 'TdDeviceDetail' })
- const formData = ref({
- deviceCode: '',
- deviceName: '',
- ifInline: undefined,
- lastInlineTime: ''
- })
- const specs = ref([])
- // 响应式数据
- const startTime = ref('')
- const endTime = ref('')
- const topicName = ref([])
- const loading = ref(false)
- const topic = ref('')
- const labelSelect = (row) =>{
- topic.value = row.identifier
- topicName.value = row.modelName
- initChart()
- }
- const chartContainer = ref(null)
- let chartInstance = null
- // 时间格式化(HH:mm)
- const formatTime = timestamp => {
- return new Date(timestamp)
- .toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit',second:'2-digit' })
- .slice(0, 5)
- }
- // 初始化图表
- const initChart = async () => {
- if (!chartContainer.value) return
- // 销毁旧实例
- if (chartInstance) chartInstance.dispose()
- chartInstance = markRaw(echarts.init(chartContainer.value))
- const result = await IotStatApi.getDeviceInfoChart(params.code, topic.value)
- const option = {
- title:{
- text: topicName.value+'数据趋势',
- left:'center',
- },
- tooltip: { trigger: 'axis', },
- xAxis: {
- type: 'category',
- data: result.map(d => formatTime(d.timestamp)),
- axisLabel: { rotate: 45 } // X轴标签旋转防止重叠
- },
- yAxis: { type: 'value' },
- dataZoom: [{
- type: 'slider',
- xAxisIndex: 0,
- start: 0, // 初始显示范围开始位置
- end: 100 // 初始显示范围结束位置:ml-citation{ref="7" data="citationList"}
- }],
- series: [{
- data: result.map(d => d.value),
- type: 'line',
- smooth: true,
- areaStyle: {} // 显示区域填充
- }]
- }
- chartInstance.setOption(option)
- // 窗口自适应
- window.addEventListener('resize', () => chartInstance.resize())
- }
- onMounted(async () => {
- formLoading.value = true
- formData.value.deviceCode = params.code
- formData.value.deviceName = params.name
- formData.value.lastInlineTime = params.time
- formData.value.ifInline = params.ifInline
- formData.value.dept = params.dept
- await IotDeviceApi.getIotDeviceTds(id).then(res => {
- specs.value = res
- specs.value = specs.value.sort((a, b) => {
- return b.modelOrder - a.modelOrder
- })
- formLoading.value = false
- topic.value = specs.value[0].identifier
- topicName.value = specs.value[0].modelName
- })
- await initChart()
- })
- </script>
- <style scoped lang="scss">
- .container {
- width: 100%;
- margin: 20px auto;
- padding: 24px;
- //background: #f8f9fa;
- border-radius: 12px;
- }
- .chart-container {
- width: 100%;
- height: 600px;
- padding: 20px;
- background: #fff;
- border-radius: 8px;
- box-shadow: 0 2px 12px rgba(0,0,0,0.1);
- }
- .date-controls {
- display: flex;
- align-items: center;
- gap: 15px;
- margin-bottom: 20px;
- }
- input[type="datetime-local"] {
- padding: 8px 12px;
- border: 1px solid #dcdfe6;
- border-radius: 4px;
- transition: border-color 0.2s;
- }
- input[type="datetime-local"]:focus {
- border-color: #409eff;
- outline: none;
- }
- .separator {
- color: #606266;
- }
- .query-btn {
- padding: 8px 20px;
- background: #409eff;
- color: white;
- border: none;
- border-radius: 4px;
- cursor: pointer;
- transition: opacity 0.2s;
- }
- .query-btn:hover {
- opacity: 0.8;
- }
- //.chart {
- // width: 100%;
- // height: 500px;
- // margin-top: 20px;
- //}
- .custom-label{
- font-size: 17px;
- font-weight: bold;
- }
- </style>
|