xiuos_IoT/xiuosiot-frontend/src/views/gateway/device/index.vue

633 lines
17 KiB
Vue
Raw 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>
<div class="app-container">
<el-row
type="flex"
justify="space-between"
style="align-items: baseline; margin-bottom: 30px"
>
<div class="header">
<h1 class="title">设备节点</h1>
<span class="date">{{ date }}</span>
<span class="sum">{{ "共" + deviceSum + "个设备节点" }}</span>
</div>
</el-row>
<el-row>
<el-button
class="add_btn"
icon="el-icon-plus"
@click="visible = true"
>新增节点</el-button>
</el-row>
<div class="list_container">
<div class="title_box">
<p />
<p>节点名称</p>
<p>终端ID</p>
<p>所属网关ID</p>
<p>支持OTAA</p>
<p>支持Class-C</p>
<i />
</div>
<div v-for="(item, index) in list" :key="index" class="item_box">
<img src="@/assets/images/geteway_device.png">
<p>{{ item.name }}</p>
<p>
<a @click="showDataDialog(item.devEui, item.status)">{{
item.devEui
}}</a>
</p>
<p>{{ item.gatewayid }}</p>
<p>{{ item.supportOtaa ? "是" : "否" }}</p>
<p>{{ item.supportClassc ? "是" : "否" }}</p>
<i
type="danger"
class="remove_icon el-icon-delete"
@click="remove(item.name, item.devEui)"
/>
</div>
</div>
<!-- 设备采集数据弹窗 -->
<div v-show="dataVisible" class="dialog_wrapper">
<div class="dialog-container">
<div class="dialog_header">
<p class="ip">设备采集数据</p>
<div class="remove_icon" @click="close">X</div>
</div>
<div class="dialog_content">
<div class="title" style="margin-top: -40px">
<img src="@/assets/images/gateway_device_status.png">
<p class="label">设备在线状态</p>
<p class="data">{{ transformStatus(currentDevice.status) }}</p>
</div>
<div class="line" />
<div v-if="currentDevice.dataType === 1">
<div class="title">
<img src="@/assets/images/gateway_device_data_type.png">
<p class="label">采集数据类型</p>
<p class="data">{{ transformType(currentDevice.dataType) }}</p>
</div>
<div class="chart">
<img src="@/assets/images/gateway_device_pm1.png">
<p class="data_center">{{ currentDevice.value }}</p>
<p class="unit">单位ug/m³</p>
</div>
<p class="name blue">PM1.0</p>
</div>
<div v-else-if="currentDevice.dataType === 2">
<div class="title">
<img src="@/assets/images/gateway_device_data_type.png">
<p class="label">采集数据类型</p>
<p class="data">{{ transformType(currentDevice.dataType) }}</p>
</div>
<div class="chart">
<img src="@/assets/images/gateway_device_pm2_5.png">
<p class="data_center">{{ currentDevice.value }}</p>
<p class="unit">单位ug/m³</p>
</div>
<p class="name green">PM2.5</p>
</div>
<div v-else-if="currentDevice.dataType === 3">
<div class="title">
<img src="@/assets/images/gateway_device_data_type.png">
<p class="label">采集数据类型</p>
<p class="data">{{ transformType(currentDevice.dataType) }}</p>
</div>
<div class="chart">
<img src="@/assets/images/gateway_device_pm10.png">
<p class="data_center">{{ currentDevice.value }}</p>
<p class="unit">单位ug/m³</p>
</div>
<p class="name orange">PM10</p>
</div>
<div v-else-if="currentDevice.dataType === 4">
<div class="title">
<img src="@/assets/images/gateway_device_data_type.png">
<p class="label">采集数据类型</p>
<p class="data">{{ transformType(currentDevice.dataType) }}</p>
</div>
<div class="chart">
<img src="@/assets/images/gateway_device_temperature.png">
<p class="data">{{ currentDevice.value }}</p>
<p class="label">当前温度</p>
<p class="unit">单位:℃</p>
</div>
</div>
<div v-else-if="currentDevice.dataType === 5">
<div class="title">
<img src="@/assets/images/gateway_device_data_type.png">
<p class="label">采集数据类型</p>
<p class="data">{{ transformType(currentDevice.dataType) }}</p>
</div>
<div class="chart">
<img src="@/assets/images/gateway_device_humidity.png">
<p class="data">{{ currentDevice.value }}</p>
<p class="label">当前湿度</p>
<p class="unit">单位:%RH</p>
</div>
</div>
<div v-else>
<div style="height: 200px; line-height: 200px; text-align: center">
暂无数据
</div>
</div>
</div>
</div>
</div>
<!-- 设备新增弹窗 -->
<div v-show="visible" class="dialog_wrapper">
<div class="dialog-container">
<div class="dialog_header">
<p class="ip">设备节点新增</p>
<div class="remove_icon" @click="close">X</div>
</div>
<div class="dialog_content">
<div class="form">
<div class="form_content">
<div class="item_title">
<img src="@/assets/images/device_name.png">名称
</div>
<div class="item_content">
<el-input v-model="form.name" />
</div>
<div class="item_title">
<img src="@/assets/images/device_devEUI.png">终端<br>ID
</div>
<div class="item_content">
<el-input v-model="form.devEui" />
</div>
</div>
<div class="line" />
<div class="form_content">
<div class="item_title">
<img src="@/assets/images/device_joinEUI.png">所属网<br>关ID
</div>
<div class="item_content">
<el-input v-model="form.gatewayid" />
</div>
</div>
<div class="line" />
<div class="form_content">
<div class="item_title">
<img src="@/assets/images/device_otaa.png">支持<br>OTAA
</div>
<div class="item_content">
<el-switch v-model="form.supportOtaa" active-color="#00CCF2" />
</div>
<div class="item_title">
<img src="@/assets/images/device_classc.png">支持<br>Class-C
</div>
<div class="item_content">
<el-switch
v-model="form.supportClassc"
active-color="#00CCF2"
/>
</div>
</div>
<div class="line" />
</div>
<div class="footer">
<el-button
size="medium"
class="cancel_btn"
@click="close"
>取消</el-button>
<el-button
size="medium"
class="save_btn"
style="border-radius: 4px"
type="primary"
@click="save"
>保存</el-button>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { getList, add, remove } from '@/api/gateway/device'
export default {
data() {
return {
date: '',
deviceSum: 0,
list: [
{
name: '11',
devEui: '12345689',
gatewayid: '123',
supportOtaa: true,
supportClassc: false
}
],
visible: false,
dataVisible: false,
form: {
name: '',
devEui: '',
gatewayid: '',
supportOtaa: true,
supportClassc: true
},
currentDevice: {},
interval: null
}
},
mounted() {
this.date = new Date().toLocaleDateString()
this.getList()
// localStorage.setItem('A00001', JSON.stringify({ dataType: 4, value: 25 }))
// localStorage.setItem('A00002', JSON.stringify({ dataType: 5, value: 63 }))
// localStorage.setItem('A00004', JSON.stringify({ dataType: 1, value: 25 }))
// localStorage.setItem('A00005', JSON.stringify({ dataType: 2, value: 63 }))
// localStorage.setItem('A00006', JSON.stringify({ dataType: 3, value: 63 }))
},
methods: {
getList() {
getList({ gatewayid: '' }).then((res) => {
this.list = res.data
this.deviceSum = this.list.length
})
},
close() {
this.visible = false
this.dataVisible = false
clearInterval(this.interval)
},
remove(name, devEui) {
this.$confirm(`确认删除设备节点${name}`, '提示', { type: 'warning' })
.then(() => {
remove({ devEui }).then((res) => {
this.$message.success('删除成功')
this.getList()
})
})
.catch()
},
save() {
console.log('form', this.form)
add({ ...this.form, status: 0 }).then((res) => {
this.$message.success('新增成功')
this.getList()
this.close()
})
},
showDataDialog(devEui, status) {
this.dataVisible = true
this.getDeviceData(devEui, status)
this.interval = setInterval(() => {
this.getDeviceData(devEui, status)
}, 1000)
},
getDeviceData(devEui, status) {
const data = localStorage.getItem(devEui)
? JSON.parse(localStorage.getItem(devEui))
: {}
this.currentDevice = {
status,
...data
}
},
transformStatus(status) {
switch (status) {
case 0:
return '从未连接'
case 1:
return '在线'
case 2:
return '离线'
}
},
transformType(type) {
switch (type) {
case 1:
return 'PM1.0'
case 2:
return 'PM2.5'
case 3:
return 'PM10'
case 4:
return '温度'
case 5:
return '湿度'
}
}
}
}
</script>
<style lang="scss" scoped>
.header {
font-family: Lato;
.title {
color: #174a84;
}
.date {
color: #a5c9ff;
}
.sum {
margin-left: 85px;
color: #a5c9ff;
}
}
.add_btn {
width: 100%;
color: #fff;
border: 2px solid transparent;
background: linear-gradient(#789af3, #789af3) padding-box,
repeating-linear-gradient(
45deg,
#789af3 0,
#789af3 12px,
#fff 12px,
#fff 24px
);
}
.list_container {
width: 100%;
margin-top: 30px;
.title_box {
width: 100%;
height: 40px;
margin: 10px auto;
display: inline-grid;
grid-template-columns:
80px minmax(105px, 1fr) 2fr 2fr 2fr minmax(130px, 2fr) minmax(130px, 2fr)
100px;
justify-items: center;
align-content: center;
align-items: center;
p {
line-height: 40px;
font-size: 26px;
font-family: Microsoft YaHei;
color: #2e4765;
}
}
.item_box {
border: 1px solid rgba(0, 204, 242, 0.2);
background: linear-gradient(
90deg,
rgba(0, 204, 242, 0.2) 0%,
rgba(150, 230, 161, 0.2) 100%
);
border-radius: 10px;
width: 100%;
height: 100px;
margin: 5px auto;
display: inline-grid;
grid-template-columns:
80px 1fr 2fr 2fr 2fr minmax(130px, 2fr) minmax(130px, 2fr)
100px;
justify-items: center;
align-content: center;
align-items: center;
img {
width: 45px;
aspect-ratio: 1 / 1;
}
p {
line-height: 100px;
font-size: 26px;
font-family: Microsoft YaHei;
color: #2e4765;
a:hover {
text-decoration: underline;
}
}
.remove_icon {
font-size: 26px;
color: #f56c6c;
cursor: pointer;
}
}
}
.dialog_wrapper {
z-index: 2;
position: fixed;
left: 230px;
right: 0;
top: 0;
bottom: 0;
margin: 0;
&::before {
content: "";
position: absolute;
left: -230px;
right: 0;
top: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.4);
z-index: 2;
}
.dialog-container {
z-index: 10;
width: 600px;
transform: none;
margin: 15vh auto;
position: relative;
border-radius: 8px;
border: 2px solid #00ccf2;
font-family: Microsoft YaHei;
box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.16);
.dialog_header {
background-color: #00ccf2;
text-align: center;
color: #fff;
padding: 5px;
position: relative;
p {
font-size: 24px;
font-weight: bold;
margin: 5px auto;
}
.remove_icon {
position: absolute;
font-size: 18px;
right: 15px;
top: 10px;
cursor: pointer;
}
}
.dialog_content {
background-color: #fff;
border-radius: 0 0 8px 8px;
padding: 40px 0 20px;
.form {
width: 80%;
margin: auto;
.form_content {
display: flex;
width: 100%;
div {
justify-content: center;
display: flex;
align-items: center;
img {
vertical-align: middle;
margin-right: 10px;
}
}
.item_title {
text-align: center;
background: #c7f4fc;
width: 110px;
min-height: 90px;
font-size: 20px;
color: #00ccf2;
}
.item_content {
flex: 1;
word-break: break-all;
padding: 9px;
}
}
}
.title {
display: flex;
align-items: center;
justify-content: center;
img {
width: 18px;
height: 22px;
margin-right: 5px;
}
p {
font-size: 23px;
font-family: Microsoft YaHei;
}
.label {
color: #00ccf2;
}
.data {
color: #5f6874;
margin-left: 10px;
}
}
.line {
width: 100%;
height: 2px;
background-image: linear-gradient(
to right,
#00ccf2 0%,
#00ccf2 50%,
transparent 50%
);
background-size: 18px 100%;
background-repeat: repeat-x;
}
.chart {
margin: auto;
width: 180px;
aspect-ratio: 1 / 1;
position: relative;
img {
width: 100%;
height: 100%;
}
p {
margin: 0;
}
.data {
position: absolute;
left: 50%;
top: 0;
transform: translateX(-50%);
font-size: 45px;
font-family: DINCond-Medium;
color: #358caa;
line-height: 63px;
}
.label {
position: absolute;
left: 50%;
bottom: 45px;
transform: translateX(-50%);
font-size: 25px;
font-family: Microsoft YaHei;
font-weight: bold;
color: #358caa;
white-space: nowrap;
}
.unit {
position: absolute;
right: 0;
bottom: 0;
transform: translateX(100%);
font-size: 15px;
font-family: Segoe UI;
color: #358caa;
}
.data_center {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
font-size: 69px;
font-family: DINCond-Medium;
color: #000000;
}
}
.name {
font-size: 35px;
font-family: MicrosoftYaHei;
line-height: 44px;
margin: 0;
text-align: center;
}
.orange {
color: #ff4e00;
}
.green {
color: #20be0b;
}
.blue {
color: #00ccf2;
}
}
// .radio {
// ::v-deep .el-radio-button__inner {
// color: #8f59eb;
// border-color: #8f59eb;
// }
// ::v-deep .el-radio-button__orig-radio:checked + .el-radio-button__inner {
// background-color: #8f59eb;
// color: #fff;
// }
// ::v-deep .el-radio-button:first-child .el-radio-button__inner {
// border-radius: 9px 0 0 9px;
// }
// ::v-deep .el-radio-button:last-child .el-radio-button__inner {
// border-radius: 0 9px 9px 0;
// }
// }
}
.footer {
text-align: center;
margin: 40px auto 20px;
.cancel_btn {
border-color: #00ccf2;
color: #00ccf2;
&:hover {
background-color: rgba(0, 204, 242, 0.1);
}
}
.save_btn {
border-color: #00ccf2;
background-color: #00ccf2;
border-radius: 2px;
&:hover {
background-color: #00ccf2;
}
}
}
}
::v-deep .el-input > .el-input__inner {
border: none;
}
</style>