Xazn-vue/src/views/iot/device/device-edit.vue
2025-05-22 16:32:24 +08:00

1317 lines
63 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="device-edit">
<el-card class="top-card" :body-style="{ padding: '26px 20px' }">
<div class="title-wrap">
<el-button class="top-button" type="info" size="small" @click="goBack()">
<i class="el-icon-arrow-left"></i>
{{ $t('product.product-edit.473153-44') }}
</el-button>
<span class="info-item">{{ $t('device.device-edit.148398-1') }}{{ form.deviceName }}</span>
<span class="info-item">{{ $t('device.device-edit.148398-7') }}{{ form.serialNumber }}</span>
<span class="info-item" v-if="!!form.status">
{{ $t('device.device-edit.148398-83') }}
<span class="status" :style="{ color: statusColor }">
<span class="dot" :style="{ backgroundColor: statusColor }"></span>
<span v-if="form.status == 1">{{ $t('home.notActive') }}</span>
<span v-if="form.status == 2">{{ $t('home.disabled') }}</span>
<span v-if="form.status == 3">{{ $t('home.onLine') }}</span>
<span v-if="form.status == 4">{{ $t('home.offline') }}</span>
</span>
</span>
<span class="info-item">{{ $t('device.device-edit.148398-4') }}{{ form.productName }}</span>
</div>
</el-card>
<el-card style="padding-bottom: 100px">
<el-tabs id="deviceDetailTab" class="custom-tabs" v-model="activeName" tab-position="top" @tab-click="tabChange" style="min-height: 400px" lazy>
<el-tab-pane name="basic">
<span slot="label">{{ $t('device.device-edit.148398-0') }}</span>
<el-form class="basic-span" ref="form" :model="form" :rules="rules" label-width="100px">
<el-row :gutter="100">
<el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="8">
<el-form-item :label="$t('device.device-edit.148398-1')" prop="deviceName">
<el-input v-model="form.deviceName" :placeholder="$t('device.device-edit.148398-2')">
<el-button slot="append" @click="openSummaryDialog" v-if="form.deviceId != 0">{{ $t('device.device-edit.148398-3') }}</el-button>
</el-input>
</el-form-item>
<el-form-item :label="$t('device.device-edit.148398-4')" prop="productName">
<el-input readonly v-model="form.productName" :placeholder="$t('device.device-edit.148398-5')" :disabled="form.status != 1">
<el-button slot="append" @click="selectProduct()" :disabled="form.status != 1">{{ $t('device.device-edit.148398-6') }}</el-button>
</el-input>
</el-form-item>
<el-form-item :label="$t('device.device-edit.148398-7')" prop="serialNumber">
<el-input v-model="form.serialNumber" :placeholder="$t('device.device-edit.148398-8')" maxlength="32" :disabled="form.status != 1" :readonly="form.deviceType === 3">
<el-button v-if="form.deviceType !== 3" slot="append" @click="generateNum" :loading="genDisabled" :disabled="form.status != 1" v-hasPermi="['iot:device:add']">
{{ $t('device.device-edit.148398-9') }}
</el-button>
<el-button v-if="form.deviceType === 3" slot="append" @click="genSipID()" :disabled="form.status != 1" v-hasPermi="['iot:device:add']">
{{ $t('device.device-edit.148398-9') }}
</el-button>
</el-input>
<el-alert v-if="openServerTip" class="alert-wrap" type="info" show-icon :description="$t('device.device-edit.148398-10')"></el-alert>
</el-form-item>
<el-form-item :label="$t('device.device-edit.148398-12')" prop="firmwareVersion">
<el-input v-model="form.firmwareVersion" :placeholder="$t('device.device-edit.148398-13')" type="number" step="0.1" :readonly="form.status != 1 || form.deviceType === 3">
<template slot="prepend">Version</template>
<template slot="append">{{ form.firmwareType === 1 ? $t('firmware.index.222541-52') : $t('firmware.index.222541-53') }}</template>
</el-input>
</el-form-item>
<!-- 设备影子 -->
<el-form-item v-if="form.deviceType !== 3" :label="$t('device.device-edit.148398-15')" prop="isShadow">
<el-radio-group v-model="form.isShadow">
<el-radio :label="1">{{ $t('device.device-edit.148398-85') }}</el-radio>
<el-radio :label="0">{{ $t('device.device-edit.148398-86') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item :label="$t('device.device-edit.148398-32')" prop="rssi">
<el-input v-model="form.rssi" :placeholder="$t('device.device-edit.148398-33')" readonly />
</el-form-item>
<el-form-item :label="$t('device.device-edit.148398-17')" prop="remark">
<el-input v-model="form.remark" type="textarea" :autosize="{ minRows: 3, maxRows: 5 }" :placeholder="$t('device.device-edit.148398-18')" />
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="8">
<el-form-item :label="$t('device.device-edit.148398-19')" prop="locationWay">
<el-select v-model="form.locationWay" :placeholder="$t('device.device-edit.148398-20')" clearable style="width: 100%">
<el-option v-for="dict in dict.type.iot_location_way" :key="dict.value" :label="dict.label" :value="Number(dict.value)" />
</el-select>
</el-form-item>
<el-form-item :label="$t('device.device-edit.148398-21')" prop="longitude">
<el-input v-model="form.longitude" :placeholder="$t('device.device-edit.148398-22')" type="number" :disabled="form.locationWay !== 3">
<el-link slot="append" :underline="false" href="https://api.map.baidu.com/lbsapi/getpoint/index.html" target="_blank" :disabled="form.locationWay != 3">
{{ $t('device.device-edit.148398-23') }}
</el-link>
</el-input>
</el-form-item>
<el-form-item :label="$t('device.device-edit.148398-24')" prop="latitude">
<el-input v-model="form.latitude" :placeholder="$t('device.device-edit.148398-25')" type="number" :disabled="form.locationWay !== 3">
<el-link slot="append" :underline="false" href="https://api.map.baidu.com/lbsapi/getpoint/index.html" target="_blank" :disabled="form.locationWay != 3">
{{ $t('device.device-edit.148398-23') }}
</el-link>
</el-input>
</el-form-item>
<el-form-item :label="$t('device.device-edit.148398-26')" prop="networkAddress">
<el-input v-model="form.networkAddress" :placeholder="$t('device.device-edit.148398-27')" :disabled="form.locationWay !== 3" />
</el-form-item>
<el-form-item :label="$t('device.device-edit.148398-28')" prop="networkIp">
<el-input v-model="form.networkIp" :placeholder="$t('device.device-edit.148398-29')" readonly />
</el-form-item>
<el-form-item :label="$t('device.device-edit.148398-30')" prop="activeTime">
<el-date-picker v-model="form.activeTime" type="date" value-format="yyyy-MM-dd" :placeholder="$t('device.device-edit.148398-31')" readonly style="width: 100%"></el-date-picker>
</el-form-item>
<el-form-item v-if="form.transport === 'MQTT'" :label="$t('device.device-edit.148398-16')" prop="deviceStatus">
<el-switch v-model="deviceStatus" active-text="" inactive-text="" :disabled="form.status === 1" :active-value="1" :inactive-value="0"></el-switch>
</el-form-item>
<el-form-item :label="$t('device.device-edit.148398-34')" prop="remark" v-if="form.deviceId != 0">
<el-button
size="mini"
@click="handleViewMqtt()"
:disabled="this.form.transport !== 'MQTT' && this.form.transport !== 'TCP' && this.form.transport !== 'HTTP' && this.form.transport !== 'GB28181'"
>
{{ $t('device.device-edit.148398-35') }}
</el-button>
<el-button size="mini" @click="openCodeDialog()">{{ $t('device.device-edit.148398-36') }}</el-button>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="8" v-if="form.deviceId != 0">
<div style="border: 1px solid #dfe4ed; border-radius: 5px; padding: 5px; margin-left: 20px">
<div id="map" style="height: 435px; width: 100%">{{ $t('device.device-edit.148398-37') }}</div>
</div>
</el-col>
</el-row>
</el-form>
<el-form label-width="100px" style="margin-top: 70px">
<el-form-item style="text-align: center; margin-left: -100px; margin-top: 10px">
<el-button type="primary" @click="submitForm" v-hasPermi="['iot:device:edit']" v-show="form.deviceId != 0">
{{ $t('update') }}
</el-button>
<el-button type="primary" @click="submitForm" v-hasPermi="['iot:device:add']" v-show="form.deviceId == 0">
{{ $t('add') }}
</el-button>
</el-form-item>
</el-form>
<!-- 选择产品 -->
<product-list ref="productList" :productId="form.productId" @productEvent="getProductData($event)" />
<sipid ref="sipidGen" :product="form" @addGenEvent="getSipIDData($event)" />
</el-tab-pane>
<el-tab-pane name="runningStatus" v-if="form.deviceType !== 3">
<span slot="label">{{ $t('device.device-edit.148398-42') }}</span>
<!-- <real-time-status ref="realTimeStatus" :device="form" @statusEvent="getDeviceStatusData($event)" /> -->
<running-status ref="runningStatus" :device="form" @statusEvent="getDeviceStatusData($event)" />
</el-tab-pane>
<el-tab-pane name="variable" :disabled="form.deviceId == 0" v-if="form.deviceType !== 3" lazy>
<span slot="label">{{ $t('device.device-edit.148398-74') }}</span>
<device-variable ref="deviceVariable" :device="form" />
</el-tab-pane>
<el-tab-pane name="instructionParsing" :disabled="form.deviceId == 0" v-if="form.deviceType !== 3" lazy>
<span slot="label">{{ $t('device.device-edit.148398-76') }}</span>
<instruction-parsing ref="instructionParsing" :device="form" />
</el-tab-pane>
<el-tab-pane
name="deviceSub"
:disabled="form.deviceId == 0"
v-if="form.deviceType == 2 && (form.protocolCode == 'MODBUS-RTU' || form.protocolCode == 'MODBUS-TCP' || form.protocolCode == 'MODBUS-JSON-HP' || form.protocolCode == 'MODBUS-JSON-ZQWL')"
lazy
>
<span slot="label">{{ $t('device.device-edit.148398-43') }}</span>
<device-sub ref="deviceSub" :device="form" />
</el-tab-pane>
<!-- 轮询任务 -->
<el-tab-pane name="deviceModbusTask" :disabled="form.deviceId == 0" v-if="form.canConfigPoll === true" lazy>
<span slot="label">{{ $t('device.device-edit.148398-77') }}</span>
<device-modbus-task ref="deviceModbusTask" :device="form" />
</el-tab-pane>
<el-tab-pane name="scada" :disabled="form.deviceId == 0" v-if="form.deviceType !== 3 && isShowScada == true" lazy>
<span slot="label">{{ $t('device.device-edit.148398-73') }}</span>
<device-scada ref="deviceScada" :device="form" />
</el-tab-pane>
<el-tab-pane name="deviceMonitor" :disabled="form.deviceId == 0" v-if="form.deviceType !== 3">
<span slot="label">{{ $t('device.device-edit.148398-51') }}</span>
<device-monitor ref="deviceMonitor" :device="form" />
</el-tab-pane>
<el-tab-pane name="deviceStastic" :disabled="form.deviceId == 0" v-if="form.deviceType !== 3">
<span slot="label">{{ $t('device.device-edit.148398-52') }}</span>
<device-statistic ref="deviceStatistic" :device="form" />
</el-tab-pane>
<el-tab-pane name="sipChannel" :disabled="form.deviceId == 0" v-if="form.deviceType === 3" lazy>
<span slot="label">{{ $t('device.device-edit.148398-44') }}</span>
<channel ref="Channel" :device="form" @playerEvent="getPlayerData($event)" />
</el-tab-pane>
<el-tab-pane name="sipPlayer" :disabled="form.deviceId == 0" v-if="form.deviceType === 3" lazy>
<span slot="label">{{ $t('device.device-edit.148398-45') }}</span>
<device-live-stream ref="deviceLiveStream" :device="form" />
</el-tab-pane>
<el-tab-pane name="sipVideo" :disabled="form.deviceId == 0" v-if="form.deviceType === 3" lazy>
<span slot="label">{{ $t('device.device-edit.148398-46') }}</span>
<deviceVideo ref="deviceVideo" :device="form" />
</el-tab-pane>
<el-tab-pane name="ossRecord" :disabled="form.deviceId == 0" v-if="form.deviceType === 3" lazy>
<span slot="label">{{ $t('device.device-edit.148398-79') }}</span>
<oss-record-list ref="OssRecord" :device="form"></oss-record-list>
</el-tab-pane>
<el-tab-pane name="sipTalk" :disabled="form.deviceId == 0" v-if="form.deviceType === 3">
<span slot="label">{{ $t('device.device-edit.148398-82') }}</span>
<siptalk ref="siptalk" :device="form" />
</el-tab-pane>
<el-tab-pane name="deviceTimer" :disabled="form.deviceId == 0" v-if="form.deviceType !== 3" lazy>
<span slot="label">{{ $t('device.device-edit.148398-47') }}</span>
<device-timer ref="deviceTimer" :device="form" />
</el-tab-pane>
<el-tab-pane name="deviceLog" :disabled="form.deviceId == 0" v-if="form.deviceType !== 3" lazy>
<span slot="label">{{ $t('device.device-edit.148398-49') }}</span>
<device-log ref="deviceLog" :device="form" />
</el-tab-pane>
<el-tab-pane name="deviceFuncLog" :disabled="form.deviceId == 0" v-if="form.deviceType !== 3" lazy>
<span slot="label">{{ $t('device.device-edit.148398-50') }}</span>
<device-func ref="deviceFuncLog" :device="form" />
</el-tab-pane>
<el-tab-pane name="alertUser" v-hasPermi="['iot:device:alert:user:list']" :disabled="form.deviceId == 0" v-if="form.deviceType !== 3">
<span slot="label">{{ $t('device.device-edit.148398-80') }}</span>
<alert-user ref="alertUser" :device="form" />
</el-tab-pane>
<el-tab-pane name="inlineVideo" :disabled="form.deviceId == 0" v-if="form.deviceType !== 3" lazy>
<span slot="label">{{ $t('device.device-edit.148398-75') }}</span>
<device-inline-video ref="deviceInlineVideo" :sipRelationList="form.sipRelationVOList" />
</el-tab-pane>
<el-tab-pane name="deviceAlert" v-hasPermi="['iot:alertLog:list']" :disabled="form.deviceId == 0" lazy>
<span slot="label">{{ $t('device.device-edit.148398-81') }}</span>
<device-alert ref="deviceAlert" :device="form" />
</el-tab-pane>
<el-tab-pane name="deviceUser" :disabled="form.deviceId == 0" lazy>
<span slot="label">{{ $t('device.device-edit.148398-48') }}</span>
<device-user ref="deviceUser" :device="form" @userEvent="getUserData($event)" />
</el-tab-pane>
<!-- <el-tab-pane name="device04" v-if="form.deviceType !== 3" disabled>
<span slot="label">
<el-tooltip class="item" effect="dark" content="用于查看发送的指令,设备是否已经响应" placement="right-start">
<el-button type="warning" size="mini" @click="deviceSynchronization()" :disabled="form.deviceId == 0">数据同步</el-button>
</el-tooltip>
</span>
</el-tab-pane> -->
</el-tabs>
<!-- 设备配置JSON -->
<el-dialog :title="$t('device.device-edit.148398-54')" :visible.sync="openSummary" width="700px" append-to-body>
<el-row :gutter="20">
<el-col :span="14">
<div style="border: 1px solid #ccc; height: 234px; width: 360px; overflow: scroll">
<json-viewer :value="summary" :expand-depth="10" copyable style="margin-top: 5px; cursor: pointer">
<template v-slot:copy>{{ $t('device.device-edit.148398-55') }}</template>
</json-viewer>
</div>
</el-col>
<el-col :span="10">
<div style="border: 1px solid #ccc; width: 220px; text-align: center; margin-left: 20px">
<vue-qr :text="qrText" :size="200"></vue-qr>
<div style="padding-bottom: 10px">{{ $t('device.device-edit.148398-56') }}</div>
</div>
</el-col>
</el-row>
<div slot="footer" class="dialog-footer">
<el-button @click="closeSummaryDialog">{{ $t('device.device-edit.148398-57') }}</el-button>
</div>
</el-dialog>
<el-dialog :visible.sync="openCode" width="300px" append-to-body>
<div style="border: 1px solid #ccc; width: 220px; text-align: center; margin: 0 auto; margin-top: -15px">
<vue-qr :text="qrText" :size="200"></vue-qr>
<div style="padding-bottom: 10px">{{ $t('device.device-edit.148398-56') }}</div>
</div>
</el-dialog>
<el-dialog :title="$t('device.device-edit.148398-58')" :visible.sync="openViewMqtt" width="600px" append-to-body>
<el-form ref="listQuery" :model="listQuery" :rules="rules" label-width="120px" v-if="this.form.transport == 'MQTT'">
<el-form-item label="clientId" prop="clientId">
<el-input v-model="listQuery.clientId" disabled style="width: 400px" />
</el-form-item>
<el-form-item label="username" prop="username">
<el-input v-model="listQuery.username" disabled style="width: 400px" />
</el-form-item>
<el-form-item label="passwd" prop="passwd">
<el-input clearable v-model="listQuery.passwd" disabled style="width: 400px"></el-input>
</el-form-item>
<el-form-item label="subscribeTopic" prop="subscribeTopic">
<el-input clearable v-model="listQuery.subscribeTopic" disabled style="width: 400px"></el-input>
</el-form-item>
<el-form-item label="reportTopic" prop="reportTopic">
<el-input clearable v-model="listQuery.reportTopic" disabled style="width: 400px"></el-input>
</el-form-item>
<el-form-item label="port" prop="port">
<el-input clearable v-model="listQuery.port" disabled style="width: 400px"></el-input>
</el-form-item>
</el-form>
<el-form ref="listQuery" :model="listQuery" :rules="rules" label-width="120px" v-if="this.form.transport == 'TCP'">
<!-- 注册包 -->
<el-form-item label="enrollPackage" prop="enrollPackage">
<el-input clearable v-model="listQuery.enrollPackage" disabled style="width: 400px"></el-input>
</el-form-item>
<el-form-item label="port" prop="port">
<el-input clearable v-model="listQuery.port" disabled style="width: 400px"></el-input>
</el-form-item>
</el-form>
<el-form ref="httpForm" :model="httpForm" :rules="rules" label-width="120px" v-if="this.form.transport == 'HTTP'">
<!-- 认证类型 -->
<el-form-item :label="$t('device.device-edit.148398-91')">
<el-input clearable v-model="httpForm.type" disabled style="width: 400px"></el-input>
</el-form-item>
<el-form-item :label="$t('device.device-edit.148398-92')">
<el-input clearable v-model="httpForm.username" disabled style="width: 400px"></el-input>
</el-form-item>
<el-form-item :label="$t('device.device-edit.148398-93')">
<el-input clearable v-model="httpForm.password" disabled style="width: 400px"></el-input>
</el-form-item>
</el-form>
<el-form ref="GBform" :model="GBform" :rules="rules" label-width="120px" v-if="this.form.transport == 'GB28181'">
<!-- 服务器域 -->
<el-form-item :label="$t('device.device-edit.148398-87')">
<el-input clearable v-model="GBform.domainAlias" disabled style="width: 400px"></el-input>
</el-form-item>
<!-- 服务器sipid" -->
<el-form-item :label="$t('device.device-edit.148398-88')">
<el-input clearable v-model="GBform.serverSipid" disabled style="width: 400px"></el-input>
</el-form-item>
<!-- 认证密码-->
<el-form-item :label="$t('device.device-edit.148398-89')">
<el-input clearable v-model="GBform.password" disabled style="width: 400px"></el-input>
</el-form-item>
<!-- 接入端口号 -->
<el-form-item :label="$t('device.device-edit.148398-90')">
<el-input clearable v-model="GBform.port" disabled style="width: 400px"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button class="btns" type="primary" @click="doCopy(2)">{{ $t('device.device-edit.148398-59') }}</el-button>
<el-button @click="closeSummaryDialog">{{ $t('device.device-edit.148398-57') }}</el-button>
</div>
</el-dialog>
</el-card>
</div>
</template>
<script>
import 'vue-json-viewer/style.css';
import JsonViewer from 'vue-json-viewer';
import productList from './product-list';
import deviceLog from './device-log';
import deviceAlert from './device-alert';
import alertUser from './alert-user';
import deviceUser from './device-user';
import runningStatus from './running-status';
import deviceMonitor from './device-monitor';
import deviceStatistic from './device-statistic';
import instructionParsing from './instruction-parsing';
import deviceModbusTask from './device-modbus-task';
import deviceTimer from './device-timer';
import channel from '../sip/channel';
import player from '@/views/components/player/player.vue';
import deviceVideo from '@/views/components/player/deviceVideo.vue';
import siptalk from '@/views/components/player/webrtc.vue';
import OssRecordList from './oss-record-list.vue';
import deviceLiveStream from '@/views/components/player/deviceLiveStream';
import sipid from '../sip/sipidGen.vue';
import deviceScada from './device-scada';
import deviceVariable from './device-variable-card';
import deviceInlineVideo from './device-inline-video';
import deviceFuncLog from './device-functionlog';
import deviceSub from './device-sub';
import vueQr from 'vue-qr';
import { loadBMap } from '@/utils/map.js';
import { deviceSynchronization, getDevice, addDevice, updateDevice, generatorDeviceNum, getMqttConnect, getSipConfig, getHttpConfig } from '@/api/iot/device';
import { getDeviceRunningStatus } from '@/api/iot/device';
import { cacheJsonThingsModel } from '@/api/iot/model';
import DeviceFunc from '@/views/iot/device/device-functionlog';
import RealTimeStatus from '@/views/iot/device/realTime-status';
import { clientOut } from '@/api/iot/netty';
import defaultSettings from '@/settings';
export default {
name: 'DeviceEdit',
dicts: ['iot_device_status', 'iot_location_way'],
components: {
RealTimeStatus,
DeviceFunc,
deviceLog,
deviceAlert,
deviceUser,
alertUser,
deviceMonitor,
deviceStatistic,
runningStatus,
productList,
deviceTimer,
deviceFuncLog,
deviceVideo,
siptalk,
OssRecordList,
player,
deviceLiveStream,
deviceSub,
JsonViewer,
vueQr,
channel,
sipid,
deviceScada,
deviceVariable,
instructionParsing,
deviceModbusTask,
deviceInlineVideo,
},
watch: {
activeName(val) {
if (val == 'deviceStastic') {
this.$nextTick(() => {
// TODO 重置统计表格的尺寸
});
}
},
},
computed: {
deviceStatus: {
set(val) {
if (val == 1) {
// 1-未激活2-禁用3-在线4-离线
this.form.status = 2;
} else {
this.form.status = this.oldDeviceStatus;
}
},
get() {
if (this.form.status == 2) {
return 1;
}
return 0;
},
},
statusColor() {
switch (this.form.status) {
case 1:
return '#ffba00';
case 2:
return '#f56c6c';
case 3:
return '#67c23a';
case 4:
return '#909399';
default:
return '#f56c6c';
}
},
},
data() {
return {
// 二维码内容
qrText: 'fastbee',
// 打开设备配置对话框
openSummary: false,
//二维码
openCode: false,
openViewMqtt: false,
// 生成设备编码是否禁用
genDisabled: false,
// 选中选项卡
activeName: 'basic',
//查看mqtt参数
mqttList: [],
// 遮罩层
loading: true,
// 设备开始状态
oldDeviceStatus: null,
deviceId: '',
channelId: '',
// 表单参数
form: {
productId: 0,
status: 1,
locationWay: 1,
firmwareType: 1,
firmwareVersion: 1,
serialNumber: '',
deviceType: 1,
isSimulate: 0,
},
//mqtt参数查看
listQuery: {
clientId: 0,
username: '',
passwd: '',
port: '',
},
GBform: {
domainAlias: '',
serverSipid: '',
password: '',
port: '',
},
httpForm: {
type: '',
username: '',
password: '',
},
openServerTip: false,
serverType: 1,
// 设备摘要
summary: [],
// 地址
baseUrl: process.env.VUE_APP_BASE_API,
// 地图相关
map: null,
mk: null,
latitude: '',
longitude: '',
//组态相关按钮是否显示true显示false不显示
isShowScada: defaultSettings.isShowScada,
// 表单校验
rules: {
deviceName: [
{
required: true,
message: this.$t('device.device-edit.148398-60'),
trigger: 'blur',
},
{
min: 2,
max: 32,
message: this.$t('device.device-edit.148398-61'),
trigger: 'blur',
},
],
productName: [
{
required: true,
message: this.$t('device.device-edit.148398-67'),
trigger: 'blur',
},
],
serialNumber: [
{
required: true,
message: this.$t('device.device-edit.148398-65'),
trigger: 'blur',
},
],
firmwareVersion: [
{
required: true,
message: this.$t('device.device-edit.148398-62'),
trigger: 'blur',
},
],
},
isMediaDevice: false,
};
},
created() {
let activeName = this.$route.query.activeName;
if (activeName != null && activeName != '') {
this.activeName = activeName;
}
// 获取设备信息
this.form.deviceId = this.$route.query && this.$route.query.deviceId;
if (this.form.deviceId != 0) {
// this.connectMqtt();
this.getDevice(this.form.deviceId);
}
},
activated() {
// 跳转选项卡
let activeName = this.$route.query.activeName;
if (activeName != null && activeName != '') {
this.activeName = activeName;
}
},
destroyed() {
// 取消订阅主题
this.mqttUnSubscribe(this.form);
},
methods: {
/* 连接Mqtt消息服务器 */
async connectMqtt() {
if (this.$mqttTool.client == null) {
await this.$mqttTool.connect(this.vuex_token);
}
// 删除所有message事件监听器
// this.$mqttTool.client.removeAllListeners('message');
// 添加message事件监听器
this.mqttCallback();
},
/* Mqtt回调处理 */
mqttCallback() {
this.$mqttTool.client.on('message', (topic, message, buffer) => {
let topics = topic.split('/');
let productId = topics[1];
let deviceNum = topics[2];
if (message instanceof Uint8Array) {
// 创建TextDecoder对象来转换Uint8Array到字符串
const decoder = new TextDecoder('utf-8');
const str = decoder.decode(message);
message = str; //转换后的字符串
}
console.log('🚀 ~ this.$mqttTool.client.on ~ message:', message);
console.log('🚀 ~ this.$mqttTool.client.on ~ topics:', topic);
message = JSON.parse(message.toString());
if (!message) {
return;
}
if (topics[3] == 'status' || topics[2] == 'status') {
this.$busEvent.$emit('updateStatus', {
serialNumber: topics[2],
productId: this.form.productId,
data: message,
});
console.log('接收到【设备状态-详情】主题:', topic);
console.log('接收到【设备状态-详情】内容:', message);
// 更新列表中设备的状态
if (this.form.serialNumber == deviceNum) {
this.oldDeviceStatus = message.status;
this.form.status = message.status;
this.form.isShadow = message.isShadow;
this.form.rssi = message.rssi;
}
}
if (topic.endsWith('ws/service')) {
this.$busEvent.$emit('updateData', {
serialNumber: topics[2],
productId: this.form.productId,
data: message,
});
}
if (topic.endsWith('service/reply')) {
this.$busEvent.$emit('updateLog', {
serialNumber: topics[2],
productId: this.form.productId,
data: message,
});
}
/**mqtt测试 */
if (topic.endsWith('message/post')) {
this.$busEvent.$emit('updateMqttMessage', {
serialNumber: topics[2],
data: message,
});
}
});
},
/** Mqtt topics array */
getMqttTopics(device) {
// 订阅当前设备状态和实时监测
const topicService = '/ws/service';
const topicStatus = '/status/post';
const topicFunction = '/function/post';
const topicMonitor = '/monitor/post';
const topicReply = '/service/reply';
//订阅mqtt测试
let messagePost = '/message/post';
const topics = [topicService, topicStatus, topicFunction, topicMonitor, topicReply, messagePost];
return topics.map((topic) => {
return `/${device.productId}/${device.serialNumber}${topic}`;
});
},
// 获取子组件订阅的设备状态
getDeviceStatusData(status) {
this.form.status = status;
},
/** Mqtt取消订阅主题 */
mqttUnSubscribe(device) {
const topics = this.getMqttTopics(device);
this.$mqttTool.unsubscribe(topics);
},
/** Mqtt订阅主题 */
mqttSubscribe(device) {
const topics = this.getMqttTopics(device);
this.$mqttTool.subscribe(topics);
},
// 获取直播子组件传递的激活选项卡名称
getPlayerData(data) {
this.activeName = data.tabName;
this.channelId = data.channelId;
// this.$set(this.form, 'channelId', this.channelId);
this.$nextTick(() => {
if (this.channelId) {
this.$refs.deviceLiveStream.channelId = this.channelId;
this.$refs.deviceLiveStream.changeChannel();
}
});
},
/** 选项卡改变事件*/
tabChange(panel) {
this.$nextTick(() => {
if (this.form.deviceType == 3 && panel.name != 'deviceReturn') {
if (panel.name === 'sipPlayer') {
if (this.$refs.deviceVideo && this.$refs.deviceVideo.destroy) {
this.$refs.deviceVideo.destroy();
}
if (this.channelId) {
if (this.$refs.deviceLiveStream && this.$refs.deviceLiveStream.channelId !== undefined) {
this.$refs.deviceLiveStream.channelId = this.channelId;
}
this.$refs.deviceLiveStream.changeChannel();
}
if (this.$refs.deviceLiveStream.channelId !== undefined) {
this.$refs.deviceLiveStream.changeChannel();
}
} else if (panel.name === 'sipVideo') {
if (this.$refs.deviceLiveStream && this.$refs.deviceLiveStream.destroy) {
this.$refs.deviceLiveStream.destroy();
}
if (this.$refs.deviceVideo && this.$refs.deviceVideo.channelId !== undefined && this.$refs.deviceVideo.queryDate) {
this.$refs.deviceVideo.loadDevRecord();
}
} else if (panel.name === 'sipChannel') {
this.$nextTick(() => {
this.$refs.Channel.getList();
});
}
//关闭直播流
if (panel.name !== 'sipPlayer' && this.$refs.deviceLiveStream && this.$refs.deviceLiveStream.playing) {
this.$refs.deviceLiveStream.closeDestroy(false);
}
//关闭录像流
if (panel.name !== 'sipVideo' && this.$refs.deviceVideo && this.$refs.deviceVideo.playing) {
this.$refs.deviceVideo.closeDestroy();
}
}
});
this.$nextTick(() => {
// 获取监测统计数据
if (panel.name === 'deviceStastic') {
this.$refs.deviceStatistic.getListHistory();
} else if (panel.name === 'deviceTimer') {
this.$refs.deviceTimer.getList();
} else if (panel.name === 'deviceSub') {
if (this.form.serialNumber) {
this.$refs.deviceSub.queryParams.gwDeviceId = this.form.deviceId;
this.$refs.deviceSub.gateway.gwDeviceId = this.form.deviceId;
this.$refs.deviceSub.getList();
}
}
});
if (this.form.deviceType !== 3) {
// 用于关闭视频推流(页面切换时候需要关闭推流)
if (panel.name !== 'inlineVideo') {
this.$refs.deviceInlineVideo && this.$refs.deviceInlineVideo.handleClose();
}
if (panel.name !== 'scada') {
const scadaRef = this.$refs.deviceScada || {};
if (scadaRef && scadaRef.$refs && scadaRef.$refs.deviceScada) {
const copmRef = scadaRef.$refs.deviceScada;
if (copmRef.$refs && copmRef.$refs.spirit) {
copmRef.$refs.spirit.forEach((item) => {
if (item.$vnode.tag.includes('ViewInlineVideo')) {
item.handleCloseJessibuca();
}
});
}
}
}
}
},
/** 数据同步*/
deviceSynchronization() {
deviceSynchronization(this.form.serialNumber).then(async (response) => {
// 获取缓存物模型
response.data.cacheThingsModel = await this.getCacheThingsModdel(response.data.productId);
// 获取设备运行状态
response.data.thingsModels = await this.getDeviceStatus(this.form);
// 格式化物模型,拆分出监测值,数组添加前缀
this.formatThingsModel(response.data);
this.form = response.data;
// 选项卡切换
this.activeName = 'runningStatus';
this.oldDeviceStatus = this.form.status;
this.loadMap();
});
},
/**获取设备详情*/
getDevice(deviceId) {
getDevice(deviceId).then(async (response) => {
this.form.protocolCode = response.data.protocolCode;
// 获取设备状态和物模型
this.getDeviceStatusWitchThingsModel(response);
});
},
/**用户是否拥有分享设备权限*/
// hasShrarePerm(permission) {
// if (this.form.isOwner == 0) {
// // 分享设备权限
// if (this.form.userPerms.indexOf(permission) == -1) {
// return false;
// }
// }
// return true;
// },
/** 获取缓存物模型*/
getCacheThingsModdel(productId) {
return new Promise((resolve, reject) => {
cacheJsonThingsModel(productId)
.then((response) => {
resolve(JSON.parse(response.data));
})
.catch((error) => {
reject(error);
});
});
},
/**获取设备运行状态*/
getDeviceStatus(data) {
const params = {
deviceId: data.deviceId,
slaveId: data.slaveId,
};
return new Promise((resolve, reject) => {
getDeviceRunningStatus(params)
.then((response) => {
resolve(response.data.thingsModels);
})
.catch((error) => {
reject(error);
});
});
},
formatThingsModel(data) {
data.chartList = [];
data.monitorList = [];
data.staticList = [];
// 物模型格式化
for (let i = 0; i < data.thingsModels.length; i++) {
// 数字类型设置默认值并转换未数值
if (data.thingsModels[i].datatype.type == 'integer' || data.thingsModels[i].datatype.type == 'decimal') {
if (data.thingsModels[i].shadow == '') {
data.thingsModels[i].shadow = Number(data.thingsModels[i].datatype.min);
} else {
data.thingsModels[i].shadow = Number(data.thingsModels[i].shadow);
}
}
// 物模型分类放置
if (data.thingsModels[i].datatype.type == 'array') {
if (data.thingsModels[i].datatype.arrayType == 'object' && data.thingsModels[i].datatype.arrayParams.length > 0) {
for (let k = 0; k < data.thingsModels[i].datatype.arrayParams.length; k++) {
for (let j = 0; j < data.thingsModels[i].datatype.arrayParams[k].length; j++) {
// 数组元素中参数ID添加前缀例如array_00_
let index = k > 9 ? String(k) : '0' + k;
let prefix = 'array_' + index + '_';
data.thingsModels[i].datatype.arrayParams[k][j].id = prefix + data.thingsModels[i].datatype.arrayParams[k][j].id;
// 图表、实时监测、监测统计分类放置
if (data.thingsModels[i].datatype.arrayParams[k][j].isChart == 1) {
// 图表
data.thingsModels[i].datatype.arrayParams[k][j].name = '[' + data.thingsModels[i].name + (k + 1) + '] ' + data.thingsModels[i].datatype.arrayParams[k][j].name;
data.thingsModels[i].datatype.arrayParams[k][j].datatype.arrayType = 'object';
data.chartList.push(data.thingsModels[i].datatype.arrayParams[k][j]);
if (data.thingsModels[i].datatype.arrayParams[k][j].isHistory == 1) {
// 监测统计
data.staticList.push(data.thingsModels[i].datatype.arrayParams[k][j]);
}
if (data.thingsModels[i].datatype.arrayParams[k][j].isMonitor == 1) {
// 实时监测
data.monitorList.push(data.thingsModels[i].datatype.arrayParams[k][j]);
}
data.thingsModels[i].datatype.arrayParams[k].splice(j--, 1);
}
}
}
} else if (data.thingsModels[i].datatype.arrayCount > 0) {
// 字符串拆分为物模型数组 model=id/name/type/isReadonly/value/shadow
let values = data.thingsModels[i].value != '' ? data.thingsModels[i].value.split(',') : [];
let shadows = data.thingsModels[i].shadow != '' ? data.thingsModels[i].shadow.split(',') : [];
for (let j = 0; j < data.thingsModels[i].datatype.arrayCount; j++) {
if (!data.thingsModels[i].datatype.arrayModel) {
data.thingsModels[i].datatype.arrayModel = [];
}
// 数组里面的ID需要添加前缀和索引例如array_00_temperature
let index = j > 9 ? String(j) : '0' + j;
let prefix = 'array_' + index + '_';
data.thingsModels[i].datatype.arrayModel[j] = {
id: prefix + data.thingsModels[i].id,
name: data.thingsModels[i].name,
type: data.thingsModels[i].type,
isReadonly: data.thingsModels[i].isReadonly,
value: values[j] ? values[j] : '',
shadow: shadows[j] ? shadows[j] : '',
};
}
}
} else if (data.thingsModels[i].datatype.type == 'object' && data.thingsModels[i].datatype.params.length > 0) {
for (let j = 0; j < data.thingsModels[i].datatype.params.length; j++) {
// 图表、实时监测、监测统计分类放置
if (data.thingsModels[i].datatype.params[j].isChart == 1) {
// 图表
data.thingsModels[i].datatype.params[j].name = '[' + data.thingsModels[i].name + '] ' + data.thingsModels[i].datatype.params[j].name;
data.chartList.push(data.thingsModels[i].datatype.params[j]);
if (data.thingsModels[i].datatype.params[j].isHistory == 1) {
// 监测统计
data.staticList.push(data.thingsModels[i].datatype.params[j]);
}
if (data.thingsModels[i].datatype.params[j].isMonitor == 1) {
// 实时监测
data.monitorList.push(data.thingsModels[i].datatype.params[j]);
}
data.thingsModels[i].datatype.params.splice(j--, 1);
}
}
} else if (data.thingsModels[i].isChart == 1) {
// // 图表、实时监测、监测统计分类放置
data.chartList.push(data.thingsModels[i]);
if (data.thingsModels[i].isHistory == 1) {
// 监测统计
data.staticList.push(data.thingsModels[i]);
}
if (data.thingsModels[i].isMonitor == 1) {
// 实时监测
data.monitorList.push(data.thingsModels[i]);
}
// 使用i--解决索引变更问题
data.thingsModels.splice(i--, 1);
}
}
},
/**加载地图*/
loadMap() {
this.$nextTick(() => {
loadBMap().then(() => {
this.getmap();
});
});
},
/** 返回按钮 */
goBack() {
const obj = {
path: '/iot/device',
query: {
t: Date.now(),
pageNum: this.$route.query.pageNum,
},
};
this.$tab.closeOpenPage(obj);
this.reset();
},
// 表单重置
reset() {
this.form = {
deviceId: 0,
deviceName: null,
productId: null,
productName: null,
userId: null,
userName: null,
tenantId: null,
tenantName: null,
serialNumber: '',
firmwareType: 1,
firmwareVersion: 1,
status: 1,
rssi: null,
networkAddress: null,
networkIp: null,
longitude: null,
latitude: null,
activeTime: null,
createBy: null,
createTime: null,
updateBy: null,
updateTime: null,
remark: null,
locationWay: 1,
clientId: 0,
};
this.deviceStatus = 0;
this.resetForm('form');
},
/** 提交按钮 */
async submitForm() {
if (this.form.serialNumber == null || this.form.serialNumber == 0) {
this.$modal.alertError(this.$t('device.device-edit.148398-65'));
return;
}
let reg = /^[0-9a-zA-Z]+$/;
if (!reg.test(this.form.serialNumber)) {
this.$modal.alertError(this.$t('device.device-edit.148398-66'));
return;
}
if (this.form.productId == null || this.form.productId == 0) {
this.$modal.alertError(this.$t('device.device-edit.148398-67'));
return;
}
this.$refs['form'].validate((valid) => {
if (valid) {
if (this.form.deviceId != 0) {
updateDevice(this.form).then((response) => {
if (response.data == 0) {
this.$modal.alertError(response.msg);
} else {
this.$modal.alertSuccess(this.$t('device.device-edit.148398-68'));
this.form = JSON.parse(JSON.stringify(this.form));
this.loadMap();
//是否设备设置为禁用状态,则踢出设备
if (this.form.status === 2) {
const params = { clientId: this.form.serialNumber };
clientOut(params).then((res) => {});
}
}
});
} else {
addDevice(this.form).then(async (response) => {
// 获取设备状态
await this.getDeviceStatusWitchThingsModel(response);
if (this.form.deviceId == null || this.form.deviceId == 0) {
this.$modal.alertError(this.$t('device.device-edit.148398-69'));
} else {
if (this.form.status == 2) {
this.deviceStatus = 1;
}
this.$modal.alertSuccess(this.$t('device.device-edit.148398-70'));
this.loadMap();
}
});
}
}
});
},
/** 获取设备状态和物模型 **/
async getDeviceStatusWitchThingsModel(response) {
// 获取缓存物模型
response.data.cacheThingsModel = await this.getCacheThingsModdel(response.data.productId);
// 获取设备运行状态
response.data.thingsModels = await this.getDeviceStatus(response.data);
//分享设备过滤没有权限的物模型
// if (response.data.isOwner == 0) {
// for (let i = 0; i < response.data.thingsModels.length; i++) {
// if (response.data.userPerms.indexOf(response.data.thingsModels[i].id) == -1) {
// response.data.thingsModels.splice(i--, 1)
// }
// }
// }
// 格式化物模型,拆分出监测值,数组添加前缀
this.formatThingsModel(response.data);
this.form = response.data;
// 解析设备摘要
if (this.form.summary != null && this.form.summary != '') {
this.summary = JSON.parse(this.form.summary);
}
this.oldDeviceStatus = this.form.status;
this.loadMap();
//Mqtt订阅
this.connectMqtt();
this.mqttSubscribe(this.form);
},
/**选择产品 */
selectProduct() {
this.$refs.productList.open = true;
this.$refs.productList.getList();
},
genSipID() {
this.$refs.sipidGen.open = true;
},
/**获取选中的产品 */
getProductData(product) {
this.form.productId = product.productId;
this.form.productName = product.productName;
this.form.deviceType = product.deviceType;
this.form.protocolCode = product.protocolCode;
this.form.tenantId = product.tenantId;
this.form.tenantName = product.tenantName;
if (product.transport === 'TCP') {
this.openServerTip = true;
this.serverType = 3;
} else {
this.openServerTip = false;
this.serverType = 1;
}
},
// 获取监控产品设备编号
getSipIDData(devsipid) {
this.form.serialNumber = devsipid;
},
// 获取选中的用户
getUserData(user) {},
/**关闭物模型 */
openSummaryDialog() {
let json = {
type: 1, // 1=扫码关联设备
deviceNumber: this.form.serialNumber,
productId: this.form.productId,
// productName: this.form.productName,
};
this.qrText = JSON.stringify(json);
this.openSummary = true;
},
/**关闭物模型 */
closeSummaryDialog() {
this.openSummary = false;
this.openViewMqtt = false;
},
doCopy() {
const input = document.createElement('input');
if (this.form.transport == 'MQTT') {
input.value =
'{clientId:' +
this.listQuery.clientId +
',username:' +
this.listQuery.username +
',passwd:' +
this.listQuery.passwd +
',subscribeTopic:' +
this.listQuery.subscribeTopic +
',reportTopic:' +
this.listQuery.reportTopic +
',port:' +
this.listQuery.port +
'}';
} else if (this.form.transport == 'TCP') {
input.value = '{enrollPackage:' + this.listQuery.enrollPackage + ',port:' + this.listQuery.port + '}';
} else if (this.form.transport == 'HTTP') {
input.value = '{type:' + this.httpForm.type + ',username:' + this.httpForm.username + ',password:' + this.httpForm.password + '}';
}
if (this.form.transport == 'GB28181') {
input.value = '{domainAlias:' + this.GBform.domainAlias + ',serverSipid:' + this.GBform.serverSipid + ',password:' + this.GBform.password + ',port:' + this.GBform.port + '}';
}
document.body.appendChild(input);
input.select(); //选中输入框
document.execCommand('Copy'); //复制当前选中文本到剪切板
document.body.removeChild(input);
this.$message.success(this.$t('device.device-edit.148398-71'));
},
openCodeDialog() {
let json = {
type: 1, // 1=扫码关联设备
deviceNumber: this.form.serialNumber,
productId: this.form.productId,
productName: this.form.productName,
};
this.qrText = JSON.stringify(json);
this.openCode = true;
},
// 地图定位
getmap() {
this.map = new BMap.Map('map');
let point = null;
if (this.form.longitude != null && this.form.longitude != '' && this.form.latitude != null && this.form.latitude != '') {
point = new BMap.Point(this.form.longitude, this.form.latitude);
} else {
point = new BMap.Point(116.404, 39.915);
}
this.map.centerAndZoom(point, 19);
this.map.enableScrollWheelZoom(true); // 开启鼠标滚轮缩放
this.map.addControl(new BMap.NavigationControl());
// 标注设备位置
this.mk = new BMap.Marker(point);
this.map.addOverlay(this.mk);
this.map.panTo(point);
},
// 生成随机字母和数字
generateNum() {
if (!this.form.productId || this.form.productId == 0) {
this.$modal.alertError(this.$t('device.device-edit.148398-72'));
return;
}
this.genDisabled = true;
const params = { type: this.serverType };
generatorDeviceNum(params).then((response) => {
this.form.serialNumber = response.data;
this.genDisabled = false;
});
},
//mqtt参数查看
handleViewMqtt() {
this.openViewMqtt = true;
this.loading = true;
if (this.form.transport === 'MQTT' || this.form.transport === 'TCP') {
const params = {
deviceId: this.form.deviceId,
};
getMqttConnect(params).then((response) => {
if (response.code == 200) {
this.listQuery = response.data;
this.loading = false;
}
});
} else if (this.form.transport === 'GB28181') {
const deviceSipId = this.form.deviceId;
getSipConfig(deviceSipId).then((response) => {
if (response.code == 200) {
this.GBform = response.data;
this.loading = false;
}
});
} else if (this.form.transport === 'HTTP') {
const params = {
deviceId: this.form.deviceId,
};
getHttpConfig(params).then((response) => {
if (response.code == 200) {
this.httpForm = response.data;
this.loading = false;
}
});
}
},
},
};
</script>
<style lang="scss" scoped>
.device-edit {
padding: 20px;
.top-card {
margin-bottom: 10px;
.title-wrap {
display: flex;
flex-direction: row;
align-items: center;
.top-button {
height: 22px;
color: #909399;
background: #f4f5f7;
padding: 0px 8px;
border: none;
}
.info-item {
font-weight: normal;
font-size: 14px;
color: #333333;
line-height: 20px;
margin-left: 36px;
.status {
position: relative;
margin-left: 4px;
.dot {
position: absolute;
top: 3px;
left: -8px;
width: 4px;
height: 4px;
border-radius: 50%;
}
}
}
}
}
.custom-tabs {
.basic-span {
margin-top: 16px;
}
::v-deep .el-card__body {
padding: 0 20px;
}
::v-deep .el-tabs__active-bar {
background-color: transparent;
}
::v-deep.el-tabs__nav {
margin-bottom: 12px;
}
::v-deep .el-tabs__item {
padding: 0px 25px !important;
box-sizing: border-box;
display: inline-block;
list-style: none;
font-size: 14px;
font-weight: 500;
color: #303133;
position: relative;
}
::v-deep .el-tabs__item.is-active {
color: #fff;
background-color: #486ff2;
border-radius: 4px;
height: 32px;
line-height: 34px;
}
.alert-wrap {
height: 35px;
margin-top: 10px;
::v-deep .el-alert__icon {
font-size: 16px;
width: 16px;
}
::v-deep .el-alert__description {
font-size: 12px;
margin: 0;
}
}
}
}
</style>