smart-power-ui/src/views/iot/project/profileV2/DeviceManage/EDeviceTable.vue

557 lines
15 KiB
Vue

<template>
<div class="e-object-device-manage-table">
<el-form
:model="queryParams"
ref="queryForm"
:inline="true"
label-width="68px"
v-show="showChildrenView === false"
>
<el-row>
<el-col :span="5">
<el-form-item label="型号名称" prop="prodKey">
<el-select
v-model="queryParams.prodKey"
placeholder="请选择项目类型"
clearable
size="small"
>
<el-option
v-for="dict in projectModelList"
:key="dict.prodKey"
:label="dict.modelName"
:value="dict.prodKey"
></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="设备名称" prop="deviceName">
<el-input
v-model="queryParams.deviceName"
placeholder="请输入设备名称"
clearable
size="small"
/>
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="设备状态" prop="deviceState">
<el-select
v-model="queryParams.deviceState"
placeholder="请选择设备状态"
clearable
size="small"
>
<el-option
:label="keys"
v-for="(keys, vals) in deviceStatusOpt"
:key="vals"
:value="vals"
/>
</el-select>
</el-form-item>
</el-col>
<!-- <el-col :span="5">
<el-form-item label="设备类型" prop="deviceStatus">
<el-input
v-model="queryParams.deviceStatus"
placeholder="请输入设备类型"
clearable
size="small"
/>
</el-form-item>
</el-col> -->
<el-col :span="9">
<el-form-item class="query-foot">
<el-button
type="primary"
icon="el-icon-search"
size="small"
@click="handleQuery"
>搜索</el-button
>
<el-button icon="el-icon-refresh" size="small" @click="resetQuery"
>重置</el-button
>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div class="table-container" v-show="showChildrenView === false">
<e-simple-card
title=""
extra=""
class="object-device-card"
v-for="(devItem, idx) in list"
:key="idx"
>
<template slot="cardHeader" class="card-custom-head">
<div
:class="
devItem['deviceState'] == 'ONLINE'
? 'card-left'
: 'card-left off-line'
"
>
<icon
v-if="devItem['deviceState'] == 'ONLINE'"
class="iconfont iconSYS_STA_1"
/>
<icon v-else class="iconfont iconlixian" />
<span style="margin-left: 8px">{{
devItem["deviceState"] == "ONLINE" ? "在线" : "离线"
}}</span>
</div>
<div class="card-right">
<span class="c-label">线路数:</span>
<span class="c-number">{{ devItem.routeCount || 0 }}</span>
<el-dropdown>
<icon class="el-icon-s-operation card-opt-i" />
<el-dropdown-menu slot="dropdown">
<el-dropdown-item @click.native="handleChildrenDevice(devItem)"
>查看线路列表</el-dropdown-item
>
<!-- <el-dropdown-item>修改服务指向</el-dropdown-item>
<el-dropdown-item>设备巡检记录</el-dropdown-item> -->
<el-dropdown-item @click.native="handleLinkToDeviceDetails(devItem)">设备参数调整</el-dropdown-item>
<!-- <el-dropdown-item>内置定时配置</el-dropdown-item> -->
</el-dropdown-menu>
</el-dropdown>
</div>
</template>
<template slot="cardBody">
<div class="object-device-body">
<div class="card-body-info">
<div class="card-body-left">
<img
:src="
devItem['deviceImage']
? getIotFileUrl(devItem['deviceImage'])
: '/images/devcie_default.png'
"
/>
</div>
<div class="card-body-right">
<span :title="devItem.deviceName">{{
devItem.deviceName
}}</span>
<span :title="devItem.deviceKey">{{ devItem.deviceKey }}</span>
<span :title="devItem.deviceAddress">{{
devItem.deviceAddress
}}</span>
</div>
</div>
<div class="card-body-footer">
<!-- {{ renderCardFooter(devItem) }} -->
<div
:class="
devItem.alarmProcessStatus == 1
? 'card-footer'
: 'card-footer dev-error'
"
>
<icon class="iconfont icontongzhi"></icon>
<span stle="margin-left: 10px;" class="footer-title">{{
devItem.alarmProcessStatus == 1
? "正常"
: `时间:${devItem.alarmTime} ${
devItem.alarmTypeName || "--"
}`
}}</span>
</div>
</div>
</div>
</template>
</e-simple-card>
<div
v-if="!list || list.length <= 0"
style="
width: 100%;
height: 300px;
display: flex;
justify-content: center;
align-items: center;
"
>
暂无数据
</div>
</div>
<div v-if="showChildrenView">
<e-device-children
ref="eDeviceChildren"
:gatewayDevice="showGatewayInfo"
:sourceId="sourceId"
:deviceType="deviceType"
:wsGuid="ws_guid"
@handleLinkToHome="handleLinkToHome"
></e-device-children>
</div>
</div>
</template>
<script>
import ESimpleCard from "@/components/Cards/index";
import EDeviceChildren from "./EDeviceChildren";
import { webSocketProjectGatewayUrl } from "@/config/env";
import { listProjectDevice, listProjectModel } from "@/api/iot/project_new";
import { getIotFileUrl } from "@/utils/hciot";
const deviceStatusOpt = {
ONLINE: "在线",
OFFLINE: "离线",
OUTLINE: "脱线",
UNACTIVE: "未激活",
};
export default {
name: "EDeviceTable",
components: {
ESimpleCard,
EDeviceChildren,
},
props: {
sourceId: {
type: [String, Number],
require: true,
},
deviceType: {
type: String,
default: "",
},
},
data() {
return {
deviceStatusOpt,
queryParams: {
prodKey: undefined,
deviceName: undefined,
deviceStatus: undefined,
},
showChildrenView: false,
list: [],
showGatewayInfo: {},
projectModelList: [],
stompClient: null,
socket_flag: true,
timeout_flag: null,
ws_guid: '',
};
},
watch: {
sourceId(val) {
if (val) {
this.initHTML();
this.showChildrenView = false;
}
},
deviceType(val) {
if (val) {
this.initHTML();
}
},
},
created() {
this.initHTML();
},
methods: {
getIotFileUrl,
// init html
initHTML() {
this.ws_guid = this.getGuid();
this.getGatewayList();
this.getProjectModelList();
},
// 查看子设备列表信息
handleChildrenDevice(gatewayDevice) {
this.showChildrenView = true;
this.showGatewayInfo = gatewayDevice;
this.$forceUpdate();
},
// 子设备列表 返回 网关设备列表
handleLinkToHome() {
this.showChildrenView = false;
},
// 内容部分
renderCardContent(item) {
return (
<template>
<div class="card-body-left">
<image
src={
item["deviceImage"]
? item["deviceImage"]
: "/images/devcie_default.png"
}
></image>
</div>
<div class="card-body-right">
<span>{item.deviceId}</span>
<span>{item.deviceSecret}</span>
<span>{item.deviceAddress}</span>
</div>
</template>
);
},
// 卡片 底部 报警状态
renderCardFooter(item) {
return (
<template>
<div
class={
item.deviceStatus == 0 ? "card-footer" : "card-footer dev-error"
}
>
<icon class="iconfont icontongzhi"></icon>
<span>
{item.deviceStatus == 0 ? "正常" : "card-footer dev-error"}
</span>
</div>
</template>
);
},
handleQuery() {
this.getGatewayList();
},
resetQuery() {
this.resetForm("queryForm");
this.getGatewayList();
},
// 获取 项目 型号列表
getProjectModelList() {
listProjectModel({
projectId: this.sourceId,
deviceTags: this.deviceType || "",
}).then((res) => {
this.projectModelList = res.data;
});
},
// 获取 项目网关设备列表
getGatewayList() {
this.list = [];
this.ws_guid = this.getGuid();
listProjectDevice(
Object.assign(
{
projectId: this.sourceId,
deviceTags: this.deviceType || "",
sign: this.ws_guid,
},
this.queryParams
)
).then((res) => {
this.list = res.rows;
if (this.stompClient) {
this.closeSocket();
}
this.connection();
});
},
// 创建一个ws 监听获取报警实时数据
connection() {
if (this.stompClient) {
return;
}
if (!webSocketProjectGatewayUrl) {
return;
}
if (!this.list || this.length <= 0) {
return;
}
let deviceIds = this.list.map((v) => v["deviceKey"]);
this.stompClient = new WebSocket(
`${webSocketProjectGatewayUrl}/${this.ws_guid}/${deviceIds.toString()}`
);
this.stompClient.onmessage = this.socket_message;
this.stompClient.onclose = this.socket_onclose;
},
socket_message(evt) {
const data = JSON.parse(evt.data);
this.handleDeviceInfo(data);
this.$forceUpdate();
},
// 处理 socket 数据返回 赋值问题
handleDeviceInfo(param) {
console.log( this.list)
if (this.list && this.list.length > 0) {
this.list = this.list.map((v) => {
if (v["deviceKey"] === param["deviceKey"]) {
return Object.assign(v, param);
} else {
return v;
}
});
this.$refs.eDeviceChildren.socket_message(param);
}
},
socket_onclose(e) {
this.stompClient = null;
if (this.socket_flag) {
this.socket_flag = false;
let _this = this;
this.timeout_flag = setTimeout(function () {
_this.socket_flag = true;
_this.connection();
}, 10000);
}
},
closeSocket() {
if (this.stompClient) {
this.stompClient.close();
}
this.socket_flag = false;
this.stompClient = null;
clearTimeout(this.timeout_flag);
},
getGuid() {
return "xxxxxxx_xxxxx_4xxx_yxxx_xxxxxxxxxxxx".replace(
/[xy]/g,
function (c) {
var r = (Math.random() * 16) | 0,
v = c == "x" ? r : (r & 0x3) | 0x8;
return v.toString(16);
}
);
},
/**
* 跳转 设备 详情
*/
handleLinkToDeviceDetails(row) {
this.$router.push({ path:'/device/device', query: { 'deviceId': row.deviceId, 'tempType': 'details' } })
}
},
destroyed() {
this.closeSocket();
},
};
</script>
<style lang="scss">
.e-object-device-manage-table {
.el-form-item--medium .el-form-item__content {
width: calc(100% - 70px);
}
.query-foot.el-form-item--medium .el-form-item__content {
width: 100%;
}
.table-container {
width: 100%;
height: 100%;
overflow: auto;
display: flex;
flex-wrap: wrap;
justify-content: start;
.object-device-card {
width: 285px;
height: 164px;
background: #ffffff;
border: 1px solid #e4ebf4;
box-shadow: 0px 0px 8px 0px rgba(17, 76, 157, 0.26);
border-radius: 5px;
margin: 5px;
.card-left {
font-size: 14px;
font-family: Source Han Sans CN;
font-weight: 400;
color: #00c805;
}
.off-line {
color: #da2710;
}
.card-right {
display: flex;
font-size: 14px;
font-family: Source Han Sans CN;
font-weight: 400;
color: #6b778c;
align-items: baseline;
.c-label {
}
.c-number {
color: #344567;
margin: 0 8px;
}
.card-opt-i {
font-size: 18px;
-ms-transform: rotate(90deg); /* IE 9 */
-webkit-transform: rotate(90deg); /* Safari and Chrome */
transform: rotate(90deg);
}
.card-opt-i:hover {
color: #46a6ff;
}
}
.e-simple-card__header {
width: 100%;
display: flex;
justify-content: space-between;
}
.e-simple-card__body {
padding: 10px;
}
.object-device-body {
width: 100%;
height: 100%;
display: flex;
flex-wrap: wrap;
.card-body-info {
width: 100%;
height: 85px;
display: flex;
.card-body-left {
width: 40%;
display: flex;
justify-content: center;
align-items: center;
> img {
width: 93px;
height: 52px;
}
}
.card-body-right {
width: 60%;
display: flex;
flex-wrap: wrap;
font-size: 14px;
font-family: Source Han Sans CN;
font-weight: 300;
color: #344567;
> span {
display: block;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
.card-body-footer {
width: 100%;
display: flex;
.card-footer {
font-size: 14px;
font-family: Source Han Sans CN;
font-weight: 400;
color: #344567;
width: 100%;
display: flex;
align-items: center;
.footer-title {
width: 100%;
margin-left: 3px;
display: block;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
}
.dev-error {
color: #dc3520;
}
}
}
}
}
}
</style>