😎增加前端mqtt
This commit is contained in:
parent
ca55fb82cf
commit
6ae7f54cdc
@ -32,6 +32,8 @@
|
||||
"echarts-gl": "^2.0.9",
|
||||
"echarts-wordcloud": "^2.1.0",
|
||||
"element-plus": "^2.7.6",
|
||||
"ezuikit": "^1.0.0",
|
||||
"ezuikit-js": "^8.0.5",
|
||||
"gcoord": "^1.0.6",
|
||||
"js-cookie": "^3.0.5",
|
||||
"js-table2excel": "^1.1.2",
|
||||
@ -39,6 +41,7 @@
|
||||
"lodash-es": "^4.17.21",
|
||||
"mitt": "^3.0.1",
|
||||
"monaco-editor": "^0.50.0",
|
||||
"mqtt": "^4.3.8",
|
||||
"nprogress": "^0.2.0",
|
||||
"ol": "^9.2.4",
|
||||
"pinia": "^2.1.7",
|
||||
|
||||
424
Web/src/views/elive/index.vue
Normal file
424
Web/src/views/elive/index.vue
Normal file
@ -0,0 +1,424 @@
|
||||
<template>
|
||||
<div class="sys-video-container">
|
||||
<el-container>
|
||||
<el-header>视频监控(萤石云云直播)</el-header>
|
||||
<el-container>
|
||||
<el-aside width="200px">
|
||||
<el-tree :data="data" :props="defaultProps" @node-click="handleNodeClick" />
|
||||
</el-aside>
|
||||
|
||||
<el-main>
|
||||
<div class="updateToken" props="ezviz_video">
|
||||
<ul>
|
||||
<li>
|
||||
<el-span>密匙串:</el-span>
|
||||
<el-input
|
||||
placeholder="密匙"
|
||||
show-word-limit
|
||||
type="text"
|
||||
id="txt_token"
|
||||
title="每周更新(开放平台,云直播,轻应用,代码示例)"
|
||||
v-model="ezviz_video.ezvizToken"
|
||||
@keyup.enter="update_Token"
|
||||
class="token_input"
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<el-span>视频流:</el-span>
|
||||
<el-input
|
||||
placeholder="萤石云视频流地址"
|
||||
show-word-limit
|
||||
type="text"
|
||||
id="txt_url"
|
||||
title="密匙对应的视频流地址(高清后缀.h.live)"
|
||||
v-model="ezviz_video.ezvizUrl"
|
||||
@keyup.enter="update_Token"
|
||||
class="token_input"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="video">
|
||||
<div class="video-item">
|
||||
<div class="item">
|
||||
<div class="home" ref="viewtoolOne">
|
||||
<div id="video-container">等待加载...</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-main>
|
||||
</el-container>
|
||||
</el-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!--
|
||||
库:https://github.com/Ezviz-OpenBiz/EZUIKit-JavaScript-npm
|
||||
安装:npm install ezuikit-js 或 pnpm add ezuikit-js
|
||||
-->
|
||||
<script lang="ts" setup name="video">
|
||||
import { reactive, ref, onMounted, nextTick, beforeDestroy } from 'vue';
|
||||
import EZUIKit from 'ezuikit-js'; //页面引用
|
||||
//import { ElNotification } from 'element-plus';
|
||||
//import { Search,ChatDotSquare,TopRight,Star,Operation,Setting,Connection,Discount,Open,Delete,Position,View,CopyDocument,DocumentChecked,VideoCamera} from '@element-plus/icons-vue';
|
||||
import mittBus from '/@/utils/mitt'; //事件总线mitt 解决打包后错误Uncaught (in promise) ReferenceError: Cannot access 'oe' before initialization
|
||||
|
||||
let ezvizPlayOne = ref(null);
|
||||
let ezvizPlayTwo = ref(null);
|
||||
let ezvizPlayThree = ref(null);
|
||||
let ezvizPlayFour = ref(null);
|
||||
let viewtoolOne = ref();
|
||||
let viewtoolTwo = ref();
|
||||
let viewtoolThree = ref();
|
||||
let viewtoolFour = ref();
|
||||
|
||||
interface Tree {
|
||||
label: string;
|
||||
children?: Tree[];
|
||||
}
|
||||
|
||||
const defaultProps = {
|
||||
children: 'children',
|
||||
label: 'label',
|
||||
};
|
||||
|
||||
const handleNodeClick = (data: Tree) => {
|
||||
console.log(data);
|
||||
};
|
||||
|
||||
// 更新token
|
||||
function update_Token(e) {
|
||||
//ezviz_video.ezvizToken=e.target.value;
|
||||
console.log(e.target.value);
|
||||
autoVideoOne('video-container');
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
autoVideoOne('video-container');
|
||||
//console.log('https://open.ys7.com/console/ezuikit/template/detail.html?themeId=pcLive&editing=false');
|
||||
});
|
||||
|
||||
// 测试 ezopen://open.ys7.com/G39444019/1.live 和 at.3bvmj4ycamlgdwgw1ig1jruma0wpohl6-48zifyb39c-13t5am6-yukyi86mz
|
||||
// 备用 ezopen://open.ys7.com/AA2615287/1.live 和 ra.5k88qgc34vgr9yva7rlub985blo9ph7k-92q0bl2r4r-0aygaog-5cofhebpm
|
||||
const ezviz_video = reactive({
|
||||
ezvizToken: 'ra.5k88qgc34vgr9yva7rlub985blo9ph7k-92q0bl2r4r-0aygaog-5cofhebpm', //需要修改每周(开放平台,云直播,轻应用,代码示例中找)演示设备
|
||||
ezvizUrl: 'ezopen://open.ys7.com/AA2615287/1.live', //高清直播拼接字符串 cosnt url = `ezopen://${item.identifyingCode}@open.ys7.com/${item.imei}/${item.channelNo}.hd.live`
|
||||
// 回放地址ezopen://open.ys7.com/AA2615287/1.rec
|
||||
});
|
||||
|
||||
// beforeDestroy(()=>{
|
||||
// ezvizPlayOne.value && ezvizPlayOne.value.stop() //销毁并停止直播视频
|
||||
// console.log('beforeDestroy');
|
||||
// });
|
||||
|
||||
// 监控1,参数https://blog.csdn.net/weixin_53791978/article/details/126489296
|
||||
function autoVideoOne(params) {
|
||||
// 获取父节点的宽高
|
||||
let divW = viewtoolOne.value.clientWidth;
|
||||
let divH = viewtoolOne.value.clientHeight;
|
||||
if (ezvizPlayOne.value != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取萤石token
|
||||
ezvizPlayOne.value = new EZUIKit.EZUIKitPlayer({
|
||||
autoplay: true, // 默认播放
|
||||
// 视频播放包括元素
|
||||
id: 'video-container', //DIV容器
|
||||
// 萤石token,https://open.ys7.com/console/ezuikit/template/detail.html?themeId=pcLive&editing=false中查询实例代码
|
||||
accessToken: ezviz_video.ezvizToken, //"ra.bl9n4hmb3c7w4fk6bbuumtmdcbbo66w0-3k7nal0q6y-0lp00m5-fi61isesz",
|
||||
// ezopen://open.ys7.com/${设备序列号}/{通道号}.live
|
||||
url: ezviz_video.ezvizUrl, //"ezopen://open.ys7.com/AA2615287/1.live", // 播放地址
|
||||
template: 'standard', // pcLive,simple - 极简版;standard-标准版;security - 安防版(预览回放);voice-语音版;theme-可配置主题;
|
||||
useHardDev: true, // 开启高性能模式 依赖需高于7.7.x 截止到2023.11.7 建议保持最新版本为7.7.6
|
||||
// header: ['capturePicture', 'zoom'], // 如果templete参数不为simple,该字段将被覆盖
|
||||
//plugin: ['talk'], // 加载插件,talk-对讲
|
||||
// 视频下方底部控件
|
||||
//footer: ["talk", "broadcast", "hd", "fullScreen"], // 如果template参数不为simple,该字段将被覆盖
|
||||
footer: ['talk', 'hd', 'fullScreen'], // 如果template参数不为simple,该字段将被覆盖
|
||||
//audio: 0, // 是否默认开启声音 0 - 关闭 1 - 开启
|
||||
// openSoundCallBack: data => console.log("开启声音回调", data),
|
||||
// closeSoundCallBack: data => console.log("关闭声音回调", data),
|
||||
// startSaveCallBack: data => console.log("开始录像回调", data),
|
||||
// stopSaveCallBack: data => console.log("录像回调", data),
|
||||
// capturePictureCallBack: data => console.log("截图成功回调", data),
|
||||
// fullScreenCallBack: data => console.log("全屏回调", data),
|
||||
// getOSDTimeCallBack: data => console.log("获取OSDTime回调", data),
|
||||
width: divW,
|
||||
height: divH,
|
||||
handleError: (err: any) => {
|
||||
if (err.type === 'handleRunTimeInfoError' && err.data.nErrorCode === 5) {
|
||||
console.log('加密设备密码错误');
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const data: Tree[] = [
|
||||
{
|
||||
label: '节点A',
|
||||
children: [
|
||||
{
|
||||
label: '菜单A-1',
|
||||
children: [
|
||||
{
|
||||
label: '菜单A-1-1',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '节点B',
|
||||
children: [
|
||||
{
|
||||
label: '菜单B-1',
|
||||
children: [
|
||||
{
|
||||
label: '菜单B-1-1',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '菜单B-2',
|
||||
children: [
|
||||
{
|
||||
label: '菜单B-2-1',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '节点C',
|
||||
children: [
|
||||
{
|
||||
label: '菜单C-1',
|
||||
children: [
|
||||
{
|
||||
label: '菜单C-1-1',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '菜单C-2',
|
||||
children: [
|
||||
{
|
||||
label: '菜单C-2-1',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.sys-video-container {
|
||||
overflow: hidden;
|
||||
height: 100vh;
|
||||
}
|
||||
.common-layout {
|
||||
background-color: #ecf5ff;
|
||||
}
|
||||
|
||||
.el-header {
|
||||
text-align: center;
|
||||
height: 45px;
|
||||
line-height: 45px;
|
||||
font-size: 22px;
|
||||
background-color: #eee;
|
||||
padding: 5px auto;
|
||||
}
|
||||
.el-aside {
|
||||
text-align: center;
|
||||
padding: 4px auto;
|
||||
overflow: hidden;
|
||||
}
|
||||
.el-aside .el-form {
|
||||
text-align: center;
|
||||
padding: 2px auto;
|
||||
margin: 4px;
|
||||
}
|
||||
.el-aside .el-button {
|
||||
margin: 2px;
|
||||
}
|
||||
.el-aside .el-input {
|
||||
font-size: 14px;
|
||||
padding: 2px;
|
||||
}
|
||||
.el-aside .el-card {
|
||||
margin: 10px 0 10px auto;
|
||||
}
|
||||
.el-aside .el-card .el-button {
|
||||
width: 90px;
|
||||
}
|
||||
.el-form-item {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.el-main {
|
||||
background-color: #111;
|
||||
padding: 4px;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.recvs {
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
width: 100%;
|
||||
height: 800px;
|
||||
}
|
||||
.rev_title {
|
||||
width: 100%;
|
||||
display: block;
|
||||
font-style: italic;
|
||||
color: #999;
|
||||
font-size: 14px;
|
||||
background-color: #fafafa;
|
||||
padding: 2px 4px;
|
||||
line-height: 25px;
|
||||
}
|
||||
.rev_conts {
|
||||
width: 100%;
|
||||
word-wrap: break-word;
|
||||
line-height: 1.5em;
|
||||
padding: 4px;
|
||||
line-height: 30px;
|
||||
} /*缩进text-indent:2em;*/
|
||||
.recvfontsize {
|
||||
text-align: center;
|
||||
display: block;
|
||||
padding-top: 4px;
|
||||
}
|
||||
.el-color-picker {
|
||||
margin-left: 4px;
|
||||
}
|
||||
.recv_count {
|
||||
text-align: left;
|
||||
}
|
||||
.recv_count p {
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
.header {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
margin: -10px auto 10px auto;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 16px;
|
||||
margin-top: 10px auto 20px auto;
|
||||
padding: 5px 0px 5px 0;
|
||||
}
|
||||
|
||||
.el-col {
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.el-input {
|
||||
font-size: 13px;
|
||||
}
|
||||
.el-card {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.el-card__body {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.el-select {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.text-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.sub-btn {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.updateToken {
|
||||
display: block;
|
||||
line-height: 30px;
|
||||
align: left;
|
||||
background: rgb(250, 250, 250, 0.2);
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.token_input {
|
||||
width: 90%;
|
||||
}
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
.w80 {
|
||||
width: 80px;
|
||||
}
|
||||
.w100 {
|
||||
width: 100px;
|
||||
}
|
||||
.log {
|
||||
font-size: 14px;
|
||||
color: #fff;
|
||||
background-color: black;
|
||||
}
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
#ch1,
|
||||
#ch2,
|
||||
#ch3,
|
||||
#ch4,
|
||||
#ch5 {
|
||||
width: 120px;
|
||||
}
|
||||
.el-tag {
|
||||
padding: auto 4px;
|
||||
margin: 5px;
|
||||
min-width: 60px;
|
||||
}
|
||||
|
||||
el-tree span {
|
||||
line-height: 50px;
|
||||
}
|
||||
|
||||
.video {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
|
||||
.video-item {
|
||||
display: flex;
|
||||
padding: 5px;
|
||||
overflow: hidden;
|
||||
|
||||
.item {
|
||||
flex: 1;
|
||||
|
||||
min-height: 40%;
|
||||
width: 100%;
|
||||
margin: 0 5px;
|
||||
background-color: #000000;
|
||||
color: #fff;
|
||||
border-radius: 2px;
|
||||
|
||||
.home {
|
||||
width: 100%;
|
||||
height: 70vh;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
marigin: 0;
|
||||
aspect-ratio: 16/9; /* 设置任意宽高任意一项即可 然后使用aspect-ratio元素 动态设置比例 */
|
||||
text-align: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
823
Web/src/views/mqttx/index.vue
Normal file
823
Web/src/views/mqttx/index.vue
Normal file
@ -0,0 +1,823 @@
|
||||
<template>
|
||||
<div class="mqtt-box">
|
||||
<h1 class="header">MQTTX在线测试客户端</h1>
|
||||
<el-card :model="connection">
|
||||
<h1>连接参数(Configuration)</h1>
|
||||
<el-form label-position="top" :model="connection">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item prop="host" label="协议|主机|端口">
|
||||
<el-input v-model="connection.host" :disabled="connSuccess" type="password" show-password>
|
||||
<template #prepend>
|
||||
<el-select v-model="connection.protocol" class="w80" :disabled="connSuccess" @change="handleProtocolChange">
|
||||
<el-option label="ws://" value="ws"></el-option>
|
||||
<el-option label="wss://" value="wss"></el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
<template #append>
|
||||
<el-input v-model.number="connection.port" type="number" class="w80" :disabled="connSuccess" placeholder="8083/8084"></el-input>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="0">
|
||||
<el-form-item prop="clientId" label="标识(Client ID)唯一性">
|
||||
<el-input v-model="connection.clientId"> </el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="0">
|
||||
<el-form-item prop="username" label="账号(Username)">
|
||||
<el-input v-model="connection.username"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="0">
|
||||
<el-form-item prop="password" label="密码(Password)">
|
||||
<el-input v-model="connection.password" type="password" show-password></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-form-item prop="regpacket" label="设备包名(Regpacket)">
|
||||
<el-input v-model="connection.repacket" :disabled="connSuccess" @input="syncdhtreg" @change="init_topic"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-form-item prop="dhtRegpack" label="共享传感器(dhtRegpacket)">
|
||||
<el-input v-model="connection.dhtRegpack" :disabled="connSuccess" @change="init_topic"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8" class="text-right">
|
||||
<el-button
|
||||
type="primary"
|
||||
:icon="Setting"
|
||||
size="default"
|
||||
class="sub-btn"
|
||||
:disabled="client.connected"
|
||||
@click="createConnection"
|
||||
:loading="btnLoadingType === 'connect'"
|
||||
:style="{ display: client.connected ? 'none' : '' }"
|
||||
>
|
||||
{{ client.connected ? '已连接(Connected)' : '连接(Connect)' }}
|
||||
</el-button>
|
||||
<el-button v-if="client.connected" type="warning" size="default" :icon="Discount" @click="destroyConnection" :loading="btnLoadingType === 'disconnect'"> 断开(Disconnect) </el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="hover">
|
||||
<h1>订阅(Subscribe)</h1>
|
||||
<el-form label-position="top" :model="subscription">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="topic" label="订阅主题(Topic)">
|
||||
<el-input v-model="connection.subTopics" :disabled="subscribedSuccess" type="password" show-password></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-form-item prop="qos" label="订阅质量(QoS)">
|
||||
<el-select v-model="subscription.qos" :disabled="subscribedSuccess">
|
||||
<el-option v-for="qos in qosList" :key="qos" :label="qos == 0 ? '0 至多一次' : qos == 1 ? '1 至少一次' : '2 仅仅一次'" :value="qos"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8" class="text-right">
|
||||
<el-button
|
||||
type="primary"
|
||||
:icon="Connection"
|
||||
size="default"
|
||||
class="sub-btn"
|
||||
:style="{ display: subscribedSuccess ? 'none' : '' }"
|
||||
:loading="btnLoadingType === 'subscribe'"
|
||||
:disabled="!client.connected || subscribedSuccess"
|
||||
@click="doSubscribe"
|
||||
>
|
||||
{{ subscribedSuccess ? '已订阅(Subscribed)' : '订阅(Subscribe)' }}
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="subscribedSuccess"
|
||||
type="warning"
|
||||
:icon="Discount"
|
||||
size="default"
|
||||
class="sub-btn"
|
||||
:loading="btnLoadingType === 'unsubscribe'"
|
||||
:disabled="!client.connected"
|
||||
@click="doUnSubscribe"
|
||||
>
|
||||
取消(Unsubscribe)
|
||||
</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="hover">
|
||||
<h1>发布(Publish)</h1>
|
||||
<el-form label-position="top" :model="publish">
|
||||
<el-row :gutter="30">
|
||||
<el-col :span="8">
|
||||
<el-form-item prop="topic" label="发布主题(Topic)">
|
||||
<el-input v-model="connection.pubTopic" type="password" show-password></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-form-item prop="qos" label="发布质量(QoS)">
|
||||
<el-select v-model="publish.qos">
|
||||
<el-option v-for="qos in qosList" :key="qos" :label="qos == 0 ? '0 至多一次' : qos == 1 ? '1 至少一次' : '2 仅仅一次'" :value="qos"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-form-item prop="retain" label="发布保留(Retain)">
|
||||
<el-select v-model="publish.retain">
|
||||
<el-option value="false" label="false 不保留"></el-option>
|
||||
<el-option value="true" label="true 不保留"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="30">
|
||||
<el-col :span="16">
|
||||
<el-form-item prop="payload" label="操作指令(Payload)">
|
||||
<el-input v-model="publish.payload" clearable maxlength="64" show-word-limit>
|
||||
<!--<template #prepend>
|
||||
<el-button :icon="Operation" />
|
||||
</template> -->
|
||||
<template #append>
|
||||
<el-select v-model="publish.payload" placeholder="选择指令" style="width: 115px">
|
||||
<el-option label="状态查询" value="55 AA AA AA AA 91 CF" />
|
||||
<el-option label="全部打开" value="55 AA AA AA AA 81 A4 01" />
|
||||
<el-option label="全部关闭" value="55 AA AA AA AA 81 A4 00" />
|
||||
<el-option label="一路开关" value="55 AA AA AA AA 81 BA 01" />
|
||||
<el-option label="二路开关" value="55 AA AA AA AA 81 BA 02" />
|
||||
<el-option label="三路开关" value="55 AA AA AA AA 81 BA 03" />
|
||||
<el-option label="四路开关" value="55 AA AA AA AA 81 BA 04" />
|
||||
</el-select>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8" class="text-right">
|
||||
<el-button
|
||||
type="success"
|
||||
:icon="Position"
|
||||
size="default"
|
||||
class="sub-btn"
|
||||
:loading="btnLoadingType === 'publish'"
|
||||
:disabled="!client.connected"
|
||||
@click="doPublish(publish.payload, connection.pubTopic)"
|
||||
>
|
||||
发布(Publish)
|
||||
</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="hover">
|
||||
<h1>
|
||||
<el-button @click="clsmsg" type="Success" size="default" :icon="Delete" title="点击清空历史记录">接收(Receive)</el-button>
|
||||
<el-tag size="default" title="接收次数">收 {{ recvnum }}</el-tag>
|
||||
<el-tag size="default" :title="dht_tm">{{ dht_wsd }}</el-tag>
|
||||
<el-tag size="default" title="设备已工作时长">{{ parseInt(runSeconds) }} 秒</el-tag>
|
||||
<el-button
|
||||
type="success"
|
||||
title="关闭一路"
|
||||
:disabled="!connection.onlineStatus | !client.connected"
|
||||
v-if="connection.ch1_Status"
|
||||
icon="ele-Check"
|
||||
size="default"
|
||||
id="ch1"
|
||||
v-preventReClick="2000"
|
||||
@click="switchLight('55 AA AA AA AA 81 01 00')"
|
||||
>关闭</el-button
|
||||
>
|
||||
<el-button
|
||||
type="warning"
|
||||
title="打开一路"
|
||||
:disabled="!connection.onlineStatus | !client.connected"
|
||||
v-else="!connection.ch1_Status"
|
||||
icon="ele-CloseBold"
|
||||
size="default"
|
||||
id="ch1"
|
||||
v-preventReClick="2000"
|
||||
@click="switchLight('55 AA AA AA AA 81 01 01')"
|
||||
>打开</el-button
|
||||
>
|
||||
<el-button
|
||||
type="success"
|
||||
title="关闭二路"
|
||||
:disabled="!connection.onlineStatus | !client.connected"
|
||||
v-if="connection.ch2_Status"
|
||||
icon="ele-Check"
|
||||
size="default"
|
||||
id="ch2"
|
||||
v-preventReClick="2000"
|
||||
@click="switchLight('55 AA AA AA AA 81 02 00')"
|
||||
>关闭</el-button
|
||||
>
|
||||
<el-button
|
||||
type="warning"
|
||||
title="打开二路"
|
||||
:disabled="!connection.onlineStatus | !client.connected"
|
||||
v-else="!connection.ch2_Status"
|
||||
icon="ele-CloseBold"
|
||||
size="default"
|
||||
id="ch2"
|
||||
v-preventReClick="2000"
|
||||
@click="switchLight('55 AA AA AA AA 81 02 01')"
|
||||
>打开</el-button
|
||||
>
|
||||
<el-button
|
||||
type="success"
|
||||
title="关闭三路"
|
||||
:disabled="!connection.onlineStatus | !client.connected"
|
||||
v-if="connection.ch3_Status"
|
||||
icon="ele-Check"
|
||||
size="default"
|
||||
id="ch3"
|
||||
v-preventReClick="2000"
|
||||
@click="switchLight('55 AA AA AA AA 81 03 00')"
|
||||
>关闭</el-button
|
||||
>
|
||||
<el-button
|
||||
type="warning"
|
||||
title="打开三路"
|
||||
:disabled="!connection.onlineStatus | !client.connected"
|
||||
v-else="!connection.ch3_Status"
|
||||
icon="ele-CloseBold"
|
||||
size="default"
|
||||
id="ch3"
|
||||
v-preventReClick="2000"
|
||||
@click="switchLight('55 AA AA AA AA 81 03 01')"
|
||||
>打开</el-button
|
||||
>
|
||||
<el-button
|
||||
type="success"
|
||||
title="关闭四路"
|
||||
:disabled="!connection.onlineStatus | !client.connected"
|
||||
v-if="connection.ch4_Status"
|
||||
icon="ele-Check"
|
||||
size="default"
|
||||
id="ch4"
|
||||
v-preventReClick="2000"
|
||||
@click="switchLight('55 AA AA AA AA 81 04 00')"
|
||||
>关闭</el-button
|
||||
>
|
||||
<el-button
|
||||
type="warning"
|
||||
title="打开四路"
|
||||
:disabled="!connection.onlineStatus | !client.connected"
|
||||
v-else="!connection.ch4_Status"
|
||||
icon="ele-CloseBold"
|
||||
size="default"
|
||||
id="ch4"
|
||||
v-preventReClick="2000"
|
||||
@click="switchLight('55 AA AA AA AA 81 04 01')"
|
||||
>打开</el-button
|
||||
>
|
||||
<el-button
|
||||
type="danger"
|
||||
title="四路全部关闭"
|
||||
:disabled="!connection.onlineStatus | !client.connected"
|
||||
v-if="connection.all_Status"
|
||||
icon="ele-SwitchButton"
|
||||
size="default"
|
||||
id="ch5"
|
||||
@click="switchLight('55 AA AA AA AA 81 A4 00')"
|
||||
>全关</el-button
|
||||
>
|
||||
<el-button
|
||||
type="success"
|
||||
title="四路全部打开"
|
||||
:disabled="!connection.onlineStatus | !client.connected"
|
||||
v-else="!connection.all_Status"
|
||||
icon="ele-Switch"
|
||||
size="default"
|
||||
id="ch5"
|
||||
@click="switchLight('55 AA AA AA AA 81 A4 01')"
|
||||
>全开</el-button
|
||||
>
|
||||
|
||||
<el-alert v-if="!client.connected || !connection.onlineStatus" title="网络服务断开或设备离线!" center type="warning" effect="light" />
|
||||
</h1>
|
||||
<!-- 绑定接收日志,只读 -->
|
||||
<el-col :span="24">
|
||||
<el-input type="textarea" :rows="8" id="recv" v-model="receivedMessages" readonly class="log"></el-input>
|
||||
</el-col>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="mqttx">
|
||||
import { reactive, ref, onMounted, nextTick } from 'vue';
|
||||
import { Search, ChatDotSquare, TopRight, Star, Operation, Setting, Connection, Discount, Open, Delete, Position } from '@element-plus/icons-vue';
|
||||
import * as MQTT from 'mqtt/dist/mqtt.min'; // 针对4.3.7版本的引用方法。5.7.x会提示错误 (import * as MQTT from "mqtt")
|
||||
import mittBus from '/@/utils/mitt'; // 事件总线mitt 解决打包后错误Uncaught (in promise) ReferenceError: Cannot access 'oe' before initialization
|
||||
|
||||
// vue 3 + vite use MQTT.js refer to https://github.com/mqttjs/MQTT.js/issues/1269
|
||||
// https://github.com/mqttjs/MQTT.js#qos
|
||||
const qosList = [0, 1, 2]; // 质量
|
||||
const now = new Date();
|
||||
const recvnum = ref(0);
|
||||
const dht_wd = ref(0); // 温度、湿度
|
||||
const dht_sd = ref(0);
|
||||
const dht_tm = ref(''); // 同步时间
|
||||
const dht_wsd = ref('温度0℃,湿度0%');
|
||||
const runSeconds = ref(0); // 工作时长
|
||||
|
||||
// mqtt客户端变量 let或const
|
||||
const client = ref({
|
||||
connected: false, //未连接
|
||||
} as MQTT.MqttClient);
|
||||
|
||||
const receivedMessages = ref('');
|
||||
const subscribedSuccess = ref(false); //订阅成功标志
|
||||
const connSuccess = ref(false); //连接成功标志
|
||||
const btnLoadingType = ref('');
|
||||
const retryTimes = ref(0); //重连次数
|
||||
|
||||
/**
|
||||
* this demo uses EMQX Public MQTT Broker (https://www.emqx.com/en/mqtt/public-mqtt5-broker), here are the details:
|
||||
* 参考https://github.com/emqx/MQTT-Client-Examples
|
||||
* 方法https://github.com/mqttjs/MQTT.js
|
||||
* Broker host: broker.emqx.io
|
||||
* WebSocket port: 8083
|
||||
* WebSocket over TLS/SSL port: 8084
|
||||
* ws -> 8083; wss -> 8084
|
||||
* By default, EMQX allows clients to connect without authentication.
|
||||
* https://docs.emqx.com/en/enterprise/v4.4/advanced/auth.html#anonymous-login
|
||||
|
||||
* for more options and details, please refer to https://github.com/mqttjs/MQTT.js#mqttclientstreambuilder-options
|
||||
*/
|
||||
const connection = reactive({
|
||||
protocol: 'ws',
|
||||
host: 'broker.emqx.io',
|
||||
// ws -> 8083; wss -> 8084
|
||||
port: 8083,
|
||||
clientId: 'emqx_vue3_' + Math.random().toString(16).substring(2, 8),
|
||||
username: '',
|
||||
password: '',
|
||||
repacket: 'd1ca1ff51f04', //注册包(改为您的注册包)
|
||||
dhtRegpack: 'd1ca1ff51f04', //温度注册包(可以相同可以共享传感器)
|
||||
mqttToken: '0804d4c44c1f1bd11dea461481f19868', //授权TOKEN自己约定
|
||||
keepalive: 30,
|
||||
clean: true, //清除 clean session
|
||||
connectTimeout: 30 * 1000, // ms 超时毫秒
|
||||
reconnectPeriod: 5000, // ms 重连毫秒
|
||||
resubscribe: true, //重新订阅
|
||||
//定义您自己的主题
|
||||
subTopic: 'mqtt/admintnet/#0#/out',
|
||||
willTopic: 'mqtt/admintnet/#0#/will',
|
||||
dhtTopic: 'mqtt/admintnet/#0#/dht',
|
||||
pubTopic: 'mqtt/admintnet/#0#/into',
|
||||
subTopics: [],
|
||||
pubPayload: '{"msg":"hellow vue3 mqtt."}',
|
||||
onlineStatus: false,
|
||||
ch1_Status: false,
|
||||
ch2_Status: false,
|
||||
ch3_Status: false,
|
||||
ch4_Status: false,
|
||||
all_Status: false,
|
||||
isAC: null, //强电true
|
||||
});
|
||||
// 初始化主题
|
||||
const init_topic = () => {
|
||||
let st = 'mqtt/admintnet/#0#/out'; //订阅主题
|
||||
let pt = 'mqtt/admintnet/#0#/into'; //发布主题
|
||||
let ptbody = '{"token":"{0}","cmd":"{1}","cmdpara":"{2}","clientid":"{3}"}';
|
||||
let wt = 'mqtt/admintnet/#0#/will'; //遗嘱主题
|
||||
let dh = 'mqtt/admintnet/#0#/dht'; //温湿度
|
||||
connection.subTopic = st.replace('#0#', connection.repacket);
|
||||
connection.willTopic = wt.replace('#0#', connection.repacket);
|
||||
connection.dhtTopic = dh.replace('#0#', connection.dhtRegpack); //温湿度
|
||||
connection.pubTopic = pt.replace('#0#', connection.repacket);
|
||||
connection.subTopics = [connection.subTopic, connection.willTopic, connection.dhtTopic];
|
||||
connection.pubPayload = ptbody;
|
||||
//console.log(connection.subTopics);
|
||||
};
|
||||
|
||||
// 默认注册包同步和传感器包名一致,反之不动
|
||||
const syncdhtreg = () => {
|
||||
connection.dhtRegpack = connection.repacket;
|
||||
};
|
||||
|
||||
// 字符串替换模拟 string.format(str,ar1,arn)
|
||||
const stringFormat = (formatted, args) => {
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
let regexp = new RegExp('\\{' + i + '\\}', 'gi');
|
||||
formatted = formatted.replace(regexp, args[i]);
|
||||
}
|
||||
return formatted;
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
init_topic();
|
||||
nextTick(() => {});
|
||||
});
|
||||
|
||||
// topic & QoS for MQTT subscribing 订阅主题(多个)
|
||||
const subscription = ref({
|
||||
topic: `$(connection.subTopics.value)`,
|
||||
qos: 0 as MQTT.QoS,
|
||||
});
|
||||
|
||||
// topic, QoS & payload for publishing message 发布主题
|
||||
const publish = ref({
|
||||
topic: `${connection.pubTopic}`,
|
||||
qos: 0 as MQTT.QoS,
|
||||
retain: false, //保留否
|
||||
payload: '55 AA AA AA AA 91 CF', //'{ "msg": "Hello, I am browser." }',
|
||||
});
|
||||
|
||||
const initData = () => {
|
||||
client.value = {
|
||||
connected: false,
|
||||
} as MQTT.MqttClient;
|
||||
retryTimes.value = 0;
|
||||
btnLoadingType.value = '';
|
||||
subscribedSuccess.value = false;
|
||||
};
|
||||
|
||||
const handleOnReConnect = () => {
|
||||
retryTimes.value++;
|
||||
connection.clientId = 'emqx_vue3_' + Math.random().toString(16).substring(2, 8);
|
||||
console.log(retryTimes.value, '重试次数');
|
||||
if (retryTimes.value > 5) {
|
||||
try {
|
||||
client.value.end(); //重连超过5次断开
|
||||
initData();
|
||||
console.log('connection maxReconnectTimes limit, stop retry');
|
||||
appmessage(now.toLocaleString() + '|超出重连接次数,停止重试' + retryTimes.value);
|
||||
} catch (error) {
|
||||
console.log('handleOnReConnect catch error:', error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* if protocol is "ws", connectUrl = "ws://broker.emqx.io:8083/mqtt"
|
||||
* if protocol is "wss", connectUrl = "wss://broker.emqx.io:8084/mqtt"
|
||||
*
|
||||
* /mqtt: MQTT-WebSocket uniformly uses /path as the connection path,
|
||||
* which should be specified when connecting, and the path used on EMQX is /mqtt.
|
||||
*
|
||||
* for more details about "mqtt.connect" method & options,
|
||||
* please refer to https://github.com/mqttjs/MQTT.js#mqttconnecturl-options
|
||||
*/
|
||||
// create MQTT connection 创建连接
|
||||
const createConnection = () => {
|
||||
try {
|
||||
btnLoadingType.value = 'connect';
|
||||
const { protocol, host, port, ...options } = connection;
|
||||
const connectUrl = `${protocol}://${host}:${port}/mqtt`; //组成新的连接字符串
|
||||
console.log(connectUrl, '连接地址');
|
||||
client.value = MQTT.connect(connectUrl, options);
|
||||
if (client.value.on) {
|
||||
// https://github.com/mqttjs/MQTT.js#event-connect
|
||||
client.value.on('connect', () => {
|
||||
//v5.x reconnect
|
||||
btnLoadingType.value = '';
|
||||
connSuccess.value = true; //client.value.connected;
|
||||
console.log('connection successful', client.value.connected);
|
||||
appmessage(now.toLocaleString() + '|连接服务成功');
|
||||
});
|
||||
|
||||
// https://github.com/mqttjs/MQTT.js#event-reconnect 重连回调
|
||||
client.value.on('reconnect', handleOnReConnect);
|
||||
// https://github.com/mqttjs/MQTT.js#event-error
|
||||
client.value.on('error', (error) => {
|
||||
console.log('connection error:', error);
|
||||
appmessage(now.toLocaleString() + '|发生错误:' + error);
|
||||
});
|
||||
|
||||
// https://github.com/mqttjs/MQTT.js#event-message 接收消息,处理方法单独定义
|
||||
client.value.on('message', (topic: string, message) => {
|
||||
//处理方法
|
||||
recvnum.value++; //接收次数累计
|
||||
doAction(topic, message); //处理
|
||||
receivedMessages.value = receivedMessages.value.concat(
|
||||
//拼接字符串输出
|
||||
now.toLocaleString() + ' ' + `${topic}\r\n` + message.toString() + '\r\n'
|
||||
);
|
||||
// console.log(now.toLocaleString()+`收到消息: ${message} from topic: ${topic}`);
|
||||
//滚动此方法可行
|
||||
nextTick(() => {
|
||||
setTimeout(() => {
|
||||
syncBottom(); //滚动到底部
|
||||
}, 50);
|
||||
});
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
btnLoadingType.value = '';
|
||||
console.log('mqtt.connect error:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 处理事件
|
||||
const doAction = (t, msg) => {
|
||||
let res = JSON.parse(msg.toString()); //必须规范的json格式否则出错,双引号不能是单引号;;;后不安全但强大 eval('(' + message.toString() + ')'); //JSON.parse(message.toString());//json对象
|
||||
|
||||
// 消息不能带''否则错误
|
||||
let regp = res.regpacket; // 接收的注册包
|
||||
let regs = connection.repacket; // 订阅的注册包
|
||||
let isOK = regp == regs ? true : false; // 是不是本设备的消息
|
||||
if (!isOK || regp == null) {
|
||||
return; // 不是丢弃
|
||||
}
|
||||
|
||||
if (t == connection.dhtTopic) {
|
||||
// 温湿度
|
||||
let rp = res.regpacket;
|
||||
let wd = res.temperature;
|
||||
let sd = res.humidity;
|
||||
let sj = res.time;
|
||||
let sc = res.runsec;
|
||||
if (rp != connection.dhtRegpack) {
|
||||
// 来自订阅的温湿度包
|
||||
return;
|
||||
}
|
||||
if (rp != null) {
|
||||
dht_wd.value = wd; // 实际应用时替换此3个变量即可
|
||||
dht_sd.value = sd;
|
||||
dht_tm.value = '更新时间:' + sj;
|
||||
runSeconds.value = sc;
|
||||
dht_wsd.value = '温度:' + dht_wd.value + '℃,湿度:' + dht_sd.value + '%';
|
||||
//state.option.title.text="实时温湿度变化趋势图(运行"+parseInt(sc)+"秒)";
|
||||
//updatechart(false);//实时数据(这种方法是实时推送,如果用 定时器 是定时显示的)updatewsd_time(false)
|
||||
}
|
||||
}
|
||||
if (t == connection.willTopic) {
|
||||
// 遗嘱
|
||||
if (res.redata == 'offline') {
|
||||
connection.onlineStatus = false;
|
||||
} else {
|
||||
connection.onlineStatus = true;
|
||||
}
|
||||
}
|
||||
if (t == connection.subTopic) {
|
||||
let rp0 = res.regpacket;
|
||||
if (rp0 != undefined) {
|
||||
if (rp0 == regs) {
|
||||
op(res.redata); // 该设备执行指令其他放弃
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 处理开关状态(自定义的指令,需要修改为您自己的指令)
|
||||
const op = (cmd: any) => {
|
||||
if (cmd == '55 AA AA AA AA 82 01 01') {
|
||||
connection.ch1_Status = true;
|
||||
}
|
||||
if (cmd == '55 AA AA AA AA 82 01 00') {
|
||||
connection.ch1_Status = false;
|
||||
}
|
||||
if (cmd == '55 AA AA AA AA 82 02 01') {
|
||||
connection.ch2_Status = true;
|
||||
}
|
||||
if (cmd == '55 AA AA AA AA 82 02 00') {
|
||||
connection.ch2_Status = false;
|
||||
}
|
||||
if (cmd == '55 AA AA AA AA 82 03 01') {
|
||||
connection.ch3_Status = true;
|
||||
}
|
||||
if (cmd == '55 AA AA AA AA 82 03 00') {
|
||||
connection.ch3_Status = false;
|
||||
}
|
||||
if (cmd == '55 AA AA AA AA 82 04 01') {
|
||||
connection.ch4_Status = true;
|
||||
}
|
||||
if (cmd == '55 AA AA AA AA 82 04 00') {
|
||||
connection.ch4_Status = false;
|
||||
}
|
||||
if (cmd == '55 AA AA AA AA 82 A4 01') {
|
||||
connection.ch1_Status = true;
|
||||
connection.ch2_Status = true;
|
||||
connection.ch3_Status = true;
|
||||
connection.ch4_Status = true;
|
||||
}
|
||||
if (cmd == '55 AA AA AA AA 82 A4 00') {
|
||||
connection.ch1_Status = false;
|
||||
connection.ch2_Status = false;
|
||||
connection.ch3_Status = false;
|
||||
connection.ch4_Status = false;
|
||||
}
|
||||
if (cmd == '55 AA AA AA AA 84 AC 01') {
|
||||
connection.isAC = true;
|
||||
}
|
||||
if (cmd == '55 AA AA AA AA 84 AC 00') {
|
||||
connection.isAC = false;
|
||||
}
|
||||
if (connection.ch1_Status && connection.ch2_Status && connection.ch3_Status && connection.ch4_Status) {
|
||||
connection.all_Status = true;
|
||||
}
|
||||
if (!connection.ch1_Status && !connection.ch2_Status && !connection.ch3_Status && !connection.ch4_Status) {
|
||||
connection.all_Status = false;
|
||||
}
|
||||
if (cmd == '55 AA AA AA AA 84 AC 01') {
|
||||
connection.isAC = true;
|
||||
}
|
||||
if (cmd == '55 AA AA AA AA 84 AC 00') {
|
||||
connection.isAC = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 自动同步滚动(建议延时执行)textarea:any=null
|
||||
const syncBottom = () => {
|
||||
const textarea = document.getElementById('recv');
|
||||
if (textarea) {
|
||||
textarea.scrollTop = textarea.scrollHeight - 30;
|
||||
}
|
||||
};
|
||||
|
||||
// subscribe topic 开始订阅
|
||||
// https://github.com/mqttjs/MQTT.js#mqttclientsubscribetopictopic-arraytopic-object-options-callback
|
||||
const doSubscribe = () => {
|
||||
btnLoadingType.value = 'subscribe';
|
||||
const { topic, qos } = subscription.value;
|
||||
console.log(connection.subTopics, '订阅主题');
|
||||
client.value.subscribe(connection.subTopics, { qos }, (error: Error, granted: mqtt.ISubscriptionGrant[]) => {
|
||||
btnLoadingType.value = '';
|
||||
if (error) {
|
||||
console.log('subscribe error:', error);
|
||||
return;
|
||||
}
|
||||
subscribedSuccess.value = true; //订阅成功
|
||||
// 连接成功,发布首个问询指令
|
||||
switchLight('55 AA AA AA AA 91 CF'); //发送首页问询指令
|
||||
console.log('订阅成功subscribe successfully:', granted);
|
||||
});
|
||||
};
|
||||
|
||||
// unsubscribe topic 取消订阅
|
||||
// https://github.com/mqttjs/MQTT.js#mqttclientunsubscribetopictopic-array-options-callback
|
||||
const doUnSubscribe = () => {
|
||||
btnLoadingType.value = 'unsubscribe';
|
||||
const { topic, qos } = subscription.value;
|
||||
client.value.unsubscribe(connection.subTopics, { qos }, (error) => {
|
||||
btnLoadingType.value = '';
|
||||
subscribedSuccess.value = false;
|
||||
if (error) {
|
||||
console.log('unsubscribe error:', error);
|
||||
return;
|
||||
}
|
||||
console.log(`unsubscribed topic: ${topic}`);
|
||||
});
|
||||
};
|
||||
|
||||
// publish message发布消息
|
||||
// https://github.com/mqttjs/MQTT.js#mqttclientpublishtopic-message-options-callback
|
||||
const doPublish = (b, t) => {
|
||||
//btnLoadingType.value = "publish";
|
||||
const { topic, qos, payload, retain } = publish.value;
|
||||
//console.log(t+b,"发布内容")
|
||||
let paybody = stringFormat(connection.pubPayload, [connection.mqttToken, b ?? publish.value.payload, '', connection.clientId]); //标准格式payload
|
||||
client.value.publish(t ?? connection.pubTopic, paybody, { qos }, (error) => {
|
||||
nextTick(() => {
|
||||
// 测试延时
|
||||
setTimeout(() => {
|
||||
btnLoadingType.value = '';
|
||||
}, 50);
|
||||
});
|
||||
if (error) {
|
||||
appmessage(now.toLocaleString() + '|发布消息错误.' + error);
|
||||
console.log('publish error:', error);
|
||||
return;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 消息追加消息框
|
||||
const appmessage = (msg) => {
|
||||
receivedMessages.value = receivedMessages.value.concat(
|
||||
// 拼接字符串输出
|
||||
msg + '\r\n'
|
||||
);
|
||||
};
|
||||
|
||||
// 开关
|
||||
const switchLight = (cmd) => {
|
||||
if (!client.value.connected) {
|
||||
appmessage('尚未连接到服务!');
|
||||
return;
|
||||
}
|
||||
let paybody = stringFormat(connection.pubPayload, [connection.mqttToken, cmd ?? publish.value.payload, '', connection.clientId]);
|
||||
const { topic, qos, payload, retain } = publish.value;
|
||||
//console.log(t+b,"发布内容")
|
||||
client.value.publish(connection.pubTopic, paybody, { qos }, retain, (error) => {
|
||||
btnLoadingType.value = '';
|
||||
if (error) {
|
||||
console.log('publish error:', error);
|
||||
return;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// disconnect 端口连接
|
||||
// https://github.com/mqttjs/MQTT.js#mqttclientendforce-options-callback
|
||||
const destroyConnection = () => {
|
||||
if (client.value.connected) {
|
||||
btnLoadingType.value = 'disconnect';
|
||||
try {
|
||||
client.value.end(false, () => {
|
||||
initData();
|
||||
connSuccess.value = false;
|
||||
//console.log("断开成功 disconnected successfully");
|
||||
appmessage(now.toLocaleString() + '|连接已断开.');
|
||||
});
|
||||
} catch (error) {
|
||||
btnLoadingType.value = '';
|
||||
console.log('断开错误 disconnect error:', error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 端口随协议而改变
|
||||
const handleProtocolChange = (value: string) => {
|
||||
connection.port = value === 'wss' ? 8084 : 8083;
|
||||
};
|
||||
|
||||
// 清空消息框
|
||||
const clsmsg = () => {
|
||||
receivedMessages.value = '';
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.mqtt-box {
|
||||
max-width: 100%;
|
||||
padding: 4px;
|
||||
margin: 10px auto 0 auto;
|
||||
}
|
||||
|
||||
.header {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
margin: -12px auto 8px auto;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 16px;
|
||||
margin-top: 10px auto 20px auto;
|
||||
padding: 5px 0px 5px 0;
|
||||
}
|
||||
|
||||
.el-col {
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.el-input {
|
||||
font-size: 13px;
|
||||
}
|
||||
.el-card {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.el-card__body {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.el-select {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.text-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.sub-btn {
|
||||
margin-top: 20px;
|
||||
width: 160px;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
.w80 {
|
||||
width: 80px;
|
||||
}
|
||||
.w100 {
|
||||
width: 100px;
|
||||
}
|
||||
.log {
|
||||
font-size: 14px;
|
||||
color: #fff;
|
||||
background-color: black;
|
||||
}
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
#ch1,
|
||||
#ch2,
|
||||
#ch3,
|
||||
#ch4,
|
||||
#ch5 {
|
||||
width: 120px;
|
||||
}
|
||||
.el-tag {
|
||||
padding: auto 4px;
|
||||
margin: 5px;
|
||||
min-width: 60px;
|
||||
}
|
||||
</style>
|
||||
Loading…
Reference in New Issue
Block a user