fastbee/yack-web/src/views/iot/device/device-edit.vue

1309 lines
53 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>
<el-card style="margin: 6px; padding-bottom: 100px">
<el-tabs id="deviceDetailTab" v-model="activeName" tab-position="left" @tab-click="tabChange"
style="padding: 10px; min-height: 400px" lazy>
<el-tab-pane name="basic">
<span slot="label">{{ $t('device.device-edit.148398-0') }}</span>
<el-form 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="" prop="productName">
<template slot="label">
<span style="color: red">*</span>
{{ $t('device.device-edit.148398-4') }}
</template>
<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="" prop="tenantName">
<template slot="label">
<span style="color: red;">*</span>
{{ $t('device.device-edit.tenant') }}
</template>
<el-input v-model="form.tenantName" disabled>
<el-button v-if="isSuperAdmin && form.deviceId != 0" slot="append" @click="openAssignUserDialog">
分配
</el-button>
</el-input>
</el-form-item>
<el-form-item label="" prop="serialNumber">
<template slot="label">
<span style="color: red">*</span>
{{ $t('device.device-edit.148398-7') }}
</template>
<el-input v-model="form.serialNumber" :placeholder="$t('device.device-edit.148398-8')"
:disabled="form.status != 1" maxlength="32">
<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-form-item>
<el-form-item v-if="openServerTip">
<template>
<el-alert type="info" show-icon :description="$t('device.device-edit.148398-10')"></el-alert>
</template>
</el-form-item>
<el-form-item v-if="openTip">
<template>
<el-alert type="success" show-icon :description="$t('device.device-edit.148398-11')"></el-alert>
</template>
</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" :disabled="form.status != 1 || form.deviceType === 3">
<template slot="prepend">Version</template>
</el-input>
</el-form-item>
<!-- 设备影子 -->
<el-form-item :label="$t('device.device-edit.148398-15')" prop="isShadow">
<el-switch v-model="form.isShadow" active-text="" inactive-text="" :active-value="1" :inactive-value="0"
:disabled="form.deviceType === 3"></el-switch>
</el-form-item>
<el-form-item v-if="form.deviceType != 4" :label="$t('device.device-edit.148398-16')" prop="deviceStatus">
<el-switch
v-model="deviceStatus"
active-text=""
inactive-text=""
:disabled="form.status == 1 || form.deviceType === 3"
:active-value="1"
:inactive-value="0"
active-color="#F56C6C"
></el-switch>
</el-form-item>
<el-form-item :label="$t('device.device-edit.148398-17')" prop="remark">
<el-input v-model="form.remark" type="textarea" :placeholder="$t('device.device-edit.148398-18')"
rows="1"/>
</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
size="small" style="width: 100%" :disabled="form.deviceType === 3">
<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')" disabled/>
</el-form-item>
<el-form-item :label="$t('device.device-edit.148398-30')" prop="activeTime">
<el-date-picker clearable v-model="form.activeTime" type="date" value-format="yyyy-MM-dd"
:placeholder="$t('device.device-edit.148398-31')" disabled
style="width: 100%"></el-date-picker>
</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')" disabled/>
</el-form-item>
<el-form-item :label="$t('device.device-edit.148398-34')" prop="remark" v-if="form.deviceId != 0">
<dict-tag :options="dict.type.iot_device_status" :value="form.status"
style="display: inline-block; margin-right: 8px"/>
<el-button size="small" @click="handleViewMqtt()">{{ $t('device.device-edit.148398-35') }}</el-button>
<el-button size="small" @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; text-align: center; line-height: 400px">
<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: 50px">
<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('device.device-edit.148398-38') }} {{ $t('device.device-edit.148398-39') }}
</el-button>
<el-button type="primary" @click="submitForm" v-hasPermi="['iot:device:add']" v-show="form.deviceId == 0">
{{ $t('device.device-edit.148398-40') }} {{ $t('device.device-edit.148398-41') }}
</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="calculatedModel" :disabled="form.deviceId == 0" v-if="form.deviceType !== 3" lazy>
<span slot="label"><span style="color: red">* </span>{{ $t('device.device-edit.148398-83') }}</span>
<device-things-model ref="deviceThingsModel" :device="form"/>
</el-tab-pane>
<!-- 历史记录(照搬数据中心-历史记录) -->
<el-tab-pane name="deviceHistoryRecord" :disabled="form.deviceId == 0" v-if="form.deviceType !== 3" lazy>
<span slot="label">{{ $t('device.device-edit.148398-84') }}</span>
<div style="padding-left: 10px">
<device-history-table-panel :device="form" :load-calculated-history-defaults="true" />
</div>
</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')"
lazy
>
<span slot="label">{{ $t('device.device-edit.148398-43') }}</span>
<device-sub ref="deviceSub" :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">
<span slot="label">{{ $t('device.device-edit.148398-79') }}</span>
<OssRecord ref="OssRecord" :device="form"/>
</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="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="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="alertUser" :disabled="form.deviceId == 0" v-if="form.deviceType !== 3">
<span slot="label" v-hasPermi="['iot:device:alert:user:list']">{{ $t('device.device-edit.148398-80') }}</span>
<alert-user ref="alertUser" :device="form"/>
</el-tab-pane>
<el-tab-pane name="deviceAlert" :disabled="form.deviceId == 0">
<span slot="label" v-hasPermi="['iot:alertLog:list', 'iot:device:list']">{{ $t('device.device-edit.148398-81') }}</span>
<device-alert ref="deviceAlert" :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="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="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="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="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="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="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.sipRelationList"/>
</el-tab-pane>
<!-- 用于设置间距 -->
<el-tab-pane disabled>
<span slot="label">
<div style="margin-top: 150px"></div>
</span>
</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-tab-pane name="deviceReturn" disabled>
<span slot="label">
<el-button type="info" size="mini" @click="goBack()">{{
$t('device.device-edit.148398-53')
}}</el-button>
</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; margin-top: -15px; height: 350px; width: 360px; overflow: scroll">
<json-viewer :value="summary" :expand-depth="10" copyable>
<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: 200px; text-align: center; margin-left: 20px; margin-top: -10px">
<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 type="info" @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="150px">
<el-form-item label="clientId" prop="clientId" v-if="this.form.transport == 'MQTT'">
<el-input v-model="listQuery.clientId" disabled style="width: 80%"/>
</el-form-item>
<el-form-item label="username" prop="username" v-if="this.form.transport == 'MQTT'">
<el-input v-model="listQuery.username" disabled style="width: 80%"/>
</el-form-item>
<el-form-item label="passwd" prop="passwd" v-if="this.form.transport == 'MQTT'">
<el-input clearable v-model="listQuery.passwd" disabled style="width: 80%"></el-input>
</el-form-item>
<el-form-item label="subscribeTopic" prop="subscribeTopic" v-if="this.form.transport == 'MQTT'">
<el-input clearable v-model="listQuery.subscribeTopic" disabled style="width: 80%"></el-input>
</el-form-item>
<el-form-item label="reportTopic" prop="reportTopic" v-if="this.form.transport == 'MQTT'">
<el-input clearable v-model="listQuery.reportTopic" disabled style="width: 80%"></el-input>
</el-form-item>
<!-- 注册包 -->
<el-form-item label="enrollPackage" prop="enrollPackage" v-if="this.form.transport == 'TCP'">
<el-input clearable v-model="listQuery.enrollPackage" disabled style="width: 80%"></el-input>
</el-form-item>
<el-form-item label="port" prop="port">
<el-input clearable v-model="listQuery.port" disabled style="width: 80%"></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-dialog title="分配设备" :visible.sync="assignUserOpen" width="800px" append-to-body>
<el-form :model="assignUserQuery" ref="assignUserQueryForm" :inline="true" label-width="80px" @submit.native.prevent>
<el-form-item label="用户名" prop="userName">
<el-input v-model="assignUserQuery.userName" clearable size="small" placeholder="请输入用户名" @keyup.enter.native="handleAssignUserQuery" />
</el-form-item>
<el-form-item label="手机号" prop="phonenumber">
<el-input v-model="assignUserQuery.phonenumber" clearable size="small" placeholder="请输入手机号" @keyup.enter.native="handleAssignUserQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleAssignUserQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetAssignUserQuery">重置</el-button>
</el-form-item>
</el-form>
<el-table v-loading="assignUserLoading" :data="assignUserList" highlight-current-row size="mini" border @current-change="handleAssignUserChange">
<el-table-column label="选择" width="55" align="center">
<template slot-scope="scope">
<input type="radio" :checked="selectedAssignUser && selectedAssignUser.userId === scope.row.userId" name="assignUser" />
</template>
</el-table-column>
<el-table-column label="用户ID" align="center" prop="userId" width="90" />
<el-table-column label="用户名" align="center" prop="userName" />
<el-table-column label="昵称" align="center" prop="nickName" />
<el-table-column label="手机号" align="center" prop="phonenumber" width="120" />
<el-table-column label="部门" align="center" prop="dept.deptName" />
</el-table>
<pagination v-show="assignUserTotal > 0" :total="assignUserTotal" :page.sync="assignUserQuery.pageNum" :limit.sync="assignUserQuery.pageSize" @pagination="getAssignUserList" />
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitAssignUser">确定</el-button>
<el-button @click="assignUserOpen = false">取消</el-button>
</div>
</el-dialog>
</el-card>
</template>
<script>
import JsonViewer from 'vue-json-viewer';
import 'vue-json-viewer/style.css';
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 OssRecord from '@/views/iot/record/record-oss.vue';
import deviceLiveStream from '@/views/components/player/deviceLiveStream';
import sipid from '../sip/sipidGen.vue';
import deviceScada from './device-scada';
import deviceVariable from './device-variable';
import deviceInlineVideo from './device-inline-video';
import deviceFuncLog from './device-functionlog';
import deviceSub from './device-sub';
import deviceThingsModel from './device-things-model.vue';
import DeviceHistoryTablePanel from '@/views/dataCenter/components/DeviceHistoryTablePanel.vue';
import vueQr from 'vue-qr';
import {loadMap} from '@/utils/map.js';
import {
deviceSynchronization,
getDevice,
addDevice,
updateDevice,
generatorDeviceNum,
getMqttConnect,
assignDeviceUser
} from '@/api/iot/device';
import {getDeviceRunningStatus} from '@/api/iot/device';
import {listUser} from '@/api/system/user';
import {getUserId} from '@/utils/auth';
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,
OssRecord,
player,
deviceLiveStream,
deviceSub,
JsonViewer,
vueQr,
channel,
sipid,
deviceScada,
deviceVariable,
instructionParsing,
deviceModbusTask,
deviceInlineVideo,
deviceThingsModel,
DeviceHistoryTablePanel,
},
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 if (val == 0) {
this.form.status = 4;
} else {
this.form.status = this.oldDeviceStatus;
}
},
get() {
if (this.form.status == 2) {
return 1;
}
return 0;
},
},
isSuperAdmin() {
return Number(getUserId()) === 1;
},
},
data() {
return {
// 二维码内容
qrText: 'fastbee',
// 打开设备配置对话框
openSummary: false,
//二维码
openCode: false,
openViewMqtt: false,
// 生成设备编码是否禁用
genDisabled: false,
// 选中选项卡
activeName: 'basic',
//查看mqtt参数
mqttList: [],
// 遮罩层
loading: true,
assignUserOpen: false,
assignUserLoading: false,
assignUserList: [],
assignUserTotal: 0,
selectedAssignUser: null,
assignUserQuery: {
pageNum: 1,
pageSize: 10,
userName: undefined,
phonenumber: undefined,
status: 0,
},
// 设备开始状态
oldDeviceStatus: null,
deviceId: '',
channelId: '',
// 表单参数
form: {
productId: 0,
status: 1,
locationWay: 1,
firmwareVersion: 1.0,
serialNumber: '',
deviceType: 1,
isSimulate: 0,
},
//mqtt参数查看
listQuery: {
clientId: 0,
username: '',
passwd: '',
port: '',
},
openTip: false,
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',
},
],
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: {
openAssignUserDialog() {
this.assignUserOpen = true;
this.selectedAssignUser = null;
this.getAssignUserList();
},
getAssignUserList() {
this.assignUserLoading = true;
listUser(this.assignUserQuery).then((response) => {
this.assignUserList = response.rows;
this.assignUserTotal = response.total;
this.assignUserLoading = false;
}).catch(() => {
this.assignUserLoading = false;
});
},
handleAssignUserQuery() {
this.assignUserQuery.pageNum = 1;
this.getAssignUserList();
},
resetAssignUserQuery() {
this.assignUserQuery = {
pageNum: 1,
pageSize: 10,
userName: undefined,
phonenumber: undefined,
status: 0,
};
this.selectedAssignUser = null;
this.getAssignUserList();
},
handleAssignUserChange(user) {
this.selectedAssignUser = user;
},
submitAssignUser() {
if (!this.selectedAssignUser) {
this.$modal.msgWarning('请选择用户');
return;
}
assignDeviceUser(this.form.deviceId, this.selectedAssignUser.userId).then(() => {
this.$modal.msgSuccess('分配成功');
this.assignUserOpen = false;
this.getDevice(this.form.deviceId);
});
},
/* 连接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') {
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 {
// 字符串拆分为物模型数组 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') {
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(() => {
loadMap().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: '',
firmwareVersion: 1.0,
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();
//刷新页面
this.$router.go(0);
//是否设备设置为禁用状态,则踢出设备
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 + '}';
}
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() {
// 清除旧地图实例
if (this.map) {
this.map.remove();
this.map = null;
}
// 使用Leaflet和高德地图
let lat, lng;
let parsedLat = parseFloat(this.form.latitude);
let parsedLng = parseFloat(this.form.longitude);
// 验证坐标有效性
if (!isNaN(parsedLat) && !isNaN(parsedLng) && parsedLat !== 0 && parsedLng !== 0) {
lat = parsedLat;
lng = parsedLng;
} else {
// 默认使用中国长沙坐标
lat = 28.23;
lng = 112.94;
}
// 创建地图
this.map = L.map('map').setView([lat, lng], 15);
// 添加高德地图图层(国内访问稳定)
L.tileLayer('https://webrd0{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}', {
subdomains: ['1', '2', '3', '4'],
attribution: '&copy; 高德地图',
maxZoom: 18
}).addTo(this.map);
// 添加标记点
this.mk = L.marker([lat, lng]).addTo(this.map);
// 添加popup提示
if (this.form.deviceName) {
this.mk.bindPopup(`<b>${this.form.deviceName}</b><br>${this.form.networkAddress || ''}`).openPopup();
}
},
// 生成随机字母和数字
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;
const params = {
deviceId: this.form.deviceId,
};
getMqttConnect(params).then((response) => {
if (response.code == 200) {
this.listQuery = response.data;
this.loading = false;
}
});
},
},
};
</script>