2025-03-27 14:23:27 +08:00

532 lines
14 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="device-history">
<view class="tools-wrap">
<view class="time-shortcut">
<uni-data-select v-model="queryParams.timeShortcut" :localdata="timeShortcuts"
@change="handleTimeShortcutChange" :clear="false"></uni-data-select>
</view>
<view class="date-wrap" @click="handleDateTimeClick">
<u--input
customStyle="height: 68rpx; padding: 0 18rpx; background-color:transparent; pointer-events:none;"
:placeholder="$tt('deviceHistory.inputDate')" :value="formatDate(queryParams.strTime)" disabled>
</u--input>
</view>
<view class="filter-btn">
<u-icon :label="$tt('deviceHistory.filtrate')" labelPos="left" name="hourglass" size="18"
@click="handleFilterClick"></u-icon>
</view>
</view>
<!-- 折线图 -->
<view class="charts-box" v-if="historys.length !== 0">
<qiun-data-charts type="line" :opts="chartOpts" :chartData="chartData" canvasId="multiLineChart" />
</view>
<!-- 表格 -->
<view class="table-box" v-if="historys.length !== 0">
<uni-table :border="false" :show="devTotal === 0" stripe :emptyText="$tt('deviceHistory.emptyTable')">
<uni-tr>
<uni-td align="center">{{ $tt('deviceHistory.updateTime') }}</uni-td>
<uni-td align="center" v-for="item in tableHeaders" :key="item.value">{{item.name}}</uni-td>
</uni-tr>
<uni-tr v-for="item in tableCom" :key="item.value">
<uni-td align="center">{{item.time}}</uni-td>
<uni-td align="center" v-for="chil in tableHeaders" :key="chil.value">{{item[chil.value]}}</uni-td>
</uni-tr>
</uni-table>
<view class="pagination-box">
<uni-pagination show-icon :page-size="devPageSize" :current="devPageNum" :total="devTotal"
@change="getTableComsList" />
</view>
</view>
<u-empty mode="data" :show="historys.length === 0" :text="$tt('deviceHistory.emptyData')"
marginTop="30"></u-empty>
<view class="other-wrap">
<!-- 日期选择器 -->
<u-datetime-picker ref="datetimePicker" :show="isDateTime" mode="datetime" :closeOnClickOverlay="true"
:confirmText="dateTimeIndex > 1 ? $tt('deviceHistory.confirm') : $tt('deviceHistory.nextStep')"
:cancelText="$tt('deviceHistory.cancel')" @confirm="handleConfirmDateTime"
@cancel="handleCancelDateTime" @close="handleCloseDateTime">
</u-datetime-picker>
<u-popup :show="isFilter" mode="top" :safeAreaInsetBottom="false" @close="isFilter = false">
<view class="filter-pop">
<view class="content-wrap">
<!-- <view class="title-wrap" v-if="deviceInfo.deviceType === 2">子设备</view>
<view class="check-box-wrap" v-if="deviceInfo.deviceType === 2">
<uni-data-checkbox mode="tag" v-model="queryParams.slaveId"
:localdata="slaveList"></uni-data-checkbox>
</view> -->
<view class="title-wrap">{{ $tt('deviceHistory.variable')}}</view>
<view class="check-box-wrap">
<uni-data-checkbox mode="tag" multiple v-model="queryParams.identifiers"
:localdata="identifierList" @change="handleIdentifierCheck"></uni-data-checkbox>
</view>
</view>
<u-line direction='row'></u-line>
<view class="bottom-wrap">
<u-button customStyle="border: none;" plain :text="$tt('deviceHistory.cancel')"
@click="isFilter = false"></u-button>
<u-line direction='col' length="40"></u-line>
<u-button customStyle="border: none;" type="primary" plain :text="$tt('deviceHistory.confirm')"
@click="handleConfirmFilter"></u-button>
</view>
</view>
</u-popup>
</view>
</view>
</template>
<script>
import moment from 'moment';
import uniDataCheckbox from '@/pagesA/components/uni-data-checkbox/index.vue';
import uniPagination from '@/pagesA/components/uni-pagination/index.vue';
import {
getSubGatewayList
} from '@/apis/modules/gateway.js';
import {
listThingsModel
} from '@/apis/modules/device.js';
import {
getHistoryList
} from '@/apis/modules/deviceLog.js';
export default {
name: 'deviceHistory',
components: {
uniDataCheckbox,
uniPagination
},
props: {
device: {
type: Object,
default: null,
require: true,
},
type: Number
},
watch: {
device: function(newVal, oldVal) {
this.deviceInfo = newVal;
},
type(val) {
if (val === 3) {
// const { deviceType } = this.deviceInfo || {};
// if (deviceType === 2) {
// this.getSlaveDatas();
// }
this.getData();
}
}
},
data() {
const beginTime = new Date().getTime() - 3600 * 1000 * 24;
const endTime = new Date().getTime();
return {
deviceInfo: {}, // 设备信息
deviceId: null,
// 时间快捷数据列表
timeShortcuts: [{
value: 0,
text: this.$tt('deviceHistory.lastTwoHours')
},
{
value: 1,
text: this.$tt('deviceHistory.lastOneDay')
},
{
value: 2,
text: this.$tt('deviceHistory.lastThirtyDay')
},
{
value: 3,
text: this.$tt('deviceHistory.custom')
},
],
// 查询参数
queryParams: {
timeShortcut: 1,
strTime: `${beginTime}-${endTime}`,
beginTime: beginTime,
endTime: endTime,
slaveId: '',
identifiers: [],
},
isDateTime: false, // 是否开启日期选择器
dateTimeIndex: 1, // 次数
isFilter: false, // 是否开启筛选
slaveList: [], // 子设备列表
identifierList: [], // 变量列表
// chart option
chartOpts: {
color: ['#1890FF', '#91CB74', '#FAC858', '#EE6666', '#73C0DE', '#3CA272', '#FC8452', '#9A60B4',
'#ea7ccc'
], // 三组数据的颜色
padding: [15, 10, 0, 15], // 图表的内边距
dataLabel: false, // 不显示数据标签
dataPointShape: false, // 显示数据点形状
enableScroll: false, // 禁用图表滚动
legend: {}, // 启用图例
xAxis: {
disableGrid: true, // 禁用X轴网格线
disabled: true, // 禁用x轴的显示
},
yAxis: {
disableGrid: false, // 禁用Y轴网格线
data: [{
// min: 0,
// max: 100 // 设置Y轴的最小值和最大值
}],
},
extra: {
line: {
type: "step", // 直线类型的折线图
width: 1, // 线条宽度
activeType: "hollow", // 激活状态下的线条样式
linearType: "custom" // 自定义线条渐变颜色
},
},
},
// 存储图表数据
chartData: {
categories: [],
series: []
},
historys: [], // 历史数据
tableHeaders: [], // 设备列表table数据
tableComTemp: [],
devPageSize: 10,
devPageNum: 1,
devTotal: 0, // 数据总量
};
},
computed: {
tableCom() {
const start = (this.devPageNum - 1) * this.devPageSize;
const end = start + this.devPageSize;
return this.tableComTemp.slice(start, end);
},
},
methods: {
// 快捷时间选择
handleTimeShortcutChange(val) {
if (val === 3) {
return;
}
const endTime = new Date().getTime();
let beginTime = null;
if (val === 0) {
beginTime = endTime - 3600 * 1000 * 2;
} else if (val === 1) {
beginTime = endTime - 3600 * 1000 * 24;
} else if (val === 2) {
beginTime = endTime - 3600 * 1000 * 24 * 30;
};
this.queryParams.beginTime = beginTime;
this.queryParams.endTime = endTime;
this.queryParams.strTime = beginTime + '-' + endTime;
this.getHistory();
},
// 格式化时间
formatDate(strTime) {
const times = strTime.split('-');
const beginTime = new Date(Number(times[0]));
const endTime = new Date(Number(times[1]));
const beginMonth = (beginTime.getMonth() + 1).toString().padStart(2, '0');
const beginDay = beginTime.getDate().toString().padStart(2, '0');
const beginHours = beginTime.getHours().toString().padStart(2, '0');
const beginMinutes = beginTime.getMinutes().toString().padStart(2, '0');
const endMonth = (endTime.getMonth() + 1).toString().padStart(2, '0');
const endDay = endTime.getDate().toString().padStart(2, '0');
const endHours = endTime.getHours().toString().padStart(2, '0');
const endMinutes = endTime.getMinutes().toString().padStart(2, '0');
return `${beginMonth}-${beginDay} ${beginHours}:${beginMinutes} - ${endMonth}-${endDay} ${endHours}:${endMinutes}`;
},
// 日期选择
handleDateTimeClick() {
const {
beginTime,
endTime
} = this.queryParams;
if (this.dateTimeIndex === 1) {
this.$refs.datetimePicker.innerValue = beginTime;
} else {
this.$refs.datetimePicker.innerValue = endTime;
}
this.isDateTime = true;
},
// 时间选择下一步/确定
handleConfirmDateTime(e) {
const {
beginTime,
endTime
} = this.queryParams;
if (this.dateTimeIndex === 1) {
this.queryParams.beginTime = e.value;
this.dateTimeIndex = this.dateTimeIndex + 1;
this.queryParams.strTime = e.value + '-' + endTime;
this.$refs.datetimePicker.innerValue = endTime;
this.isDateTime = false;
setTimeout(() => {
this.isDateTime = true;
}, 1);
} else {
this.queryParams.endTime = e.value;
this.dateTimeIndex = 1;
this.queryParams.strTime = beginTime + '-' + e.value;
this.getHistory();
this.isDateTime = false;
this.queryParams.timeShortcut = 3;
}
},
// 取消日期选择
handleCancelDateTime() {
this.isDateTime = false;
},
// 点击遮取消日期选择
handleCloseDateTime() {
this.isDateTime = false;
},
// 筛选
handleFilterClick() {
this.isFilter = true;
},
// 变量选择
handleIdentifierCheck(e) {
const value = e.detail.value;
const length = value.length;
if (length > 9) {
uni.showToast({
icon: 'none',
title: '变量数不能超过9个'
});
this.queryParams.identifiers = value.slice(0, 9);
}
},
// 筛选确认
handleConfirmFilter() {
const {
identifiers
} = this.queryParams;
if (identifiers.length === 0) {
uni.showToast({
icon: 'none',
title: '请选择变量!'
});
} else {
this.getHistory();
this.isFilter = false;
}
},
// 获取子设备列表数据
getSlaveDatas() {
const {
deviceId
} = this.deviceInfo;
const params = {
gwDeviceId: deviceId,
pageNum: 1,
pageSize: 9999,
};
getSubGatewayList(params).then(res => {
const {
code,
rows
} = res;
if (code === 200) {
this.slaveList = rows.map(item => ({
text: item.subDeviceName,
value: item.slaveId
}));
this.queryParams.slaveId = this.slaveList[0].value;
}
});
},
// 获取物模型
getIdentifierList() {
const {
deviceId
} = this.deviceInfo;
const params = {
deviceId: deviceId,
pageNum: 1,
pageSize: 9999,
};
listThingsModel(params).then((res) => {
const {
code,
rows
} = res;
if (code === 200) {
this.identifierList = rows.map(item => ({
text: item.modelName,
value: item.identifier,
type: item.type,
}));
this.queryParams.identifiers = [this.identifierList[0].value];
}
});
},
// 获取统计数据
getData() {
this.getIdentifierList();
this.getHistory(); // 获取统计数据
},
// 获取统计数据
getHistory() {
const {
identifiers,
beginTime,
endTime,
slaveId
} = this.queryParams;
const {
deviceId,
serialNumber
} = this.deviceInfo;
if (identifiers.length !== 0) {
const idenList = identifiers.map((item) => {
const iden = this.identifierList.find((chil) => chil.value === item);
return {
identifier: iden.value,
type: iden.type
};
});
const params = {
identifierList: idenList,
beginTime: moment(beginTime).format('YYYY-MM-DD HH:mm:ss'),
endTime: moment(endTime).format('YYYY-MM-DD HH:mm:ss'),
deviceId: deviceId,
// slaveId: slaveId,
serialNumber: serialNumber,
};
getHistoryList(params).then(res => {
this.historys = res.data;
this.chartData = this.getChartDatas();
this.getTableDatas();
})
}
},
// 获取折线图数据
getChartDatas() {
const categories = this.historys.map((item) => Object.keys(item)[0]);
const series = this.queryParams.identifiers.map((item) => {
return {
name: this.identifierList.find((chil) => chil.value === item).text,
data: this.historys.map((d) => {
const ide = Object.values(d)[0].find((f) => Object.keys(f)[0] === item);
return Object.values(ide)[0];
}),
};
});
return {
categories,
series
}
},
// 获取表格数据
getTableDatas() {
this.tableHeaders = this.queryParams.identifiers.map((item) => ({
name: this.identifierList.find((chil) => chil.value === item).text,
value: item,
}));
this.tableComTemp = this.historys.map((item) => {
const time = Object.keys(item)[0];
let obj = {};
Object.values(item)[0].forEach((chil) => {
obj[Object.keys(chil)[0]] = Object.values(chil)[0];
});
return {
time,
...obj
};
});
this.devTotal = this.historys.length;
},
// 获取设备列表数据
getTableComsList(e) {
this.devPageNum = e.current;
},
},
options: {
styleIsolation: 'shared'
}
};
</script>
<style lang="scss" scoped>
.device-history {
width: 100%;
.tools-wrap {
display: flex;
flex-direction: row;
align-items: center;
padding: 20rpx 14rpx;
background: #fff;
.time-shortcut {
width: 190rpx;
::v-deep .uni-select {
height: 70rpx;
}
}
.date-wrap {
flex: 1;
margin-left: 10rpx;
}
.filter-btn {
font-size: 28rpx;
margin-left: 14rpx;
height: 70rpx;
display: flex;
align-items: center;
}
}
.charts-box {
width: 100%;
background-color: #fff;
padding: 20rpx 0;
margin-top: 20rpx;
}
.table-box {
width: 100%;
background-color: #fff;
padding: 10px 0;
margin-top: 10px;
.pagination-box {
margin: 10px 10px 0 0;
}
}
.other-wrap {
.filter-pop {
.content-wrap {
padding: 10px;
.title-wrap {
font-size: 28rpx;
font-weight: bold;
margin-top: 10rpx;
}
.check-box-wrap {
margin: 10rpx 0 30rpx 0;
max-height: 200px;
overflow-y: auto;
}
}
.bottom-wrap {
display: flex;
flex-direction: row;
align-items: center;
}
}
}
}
</style>