feat(断路器): 调整后端服务路径、页面添加缓存、断路器连接、主题数据添加缓存

This commit is contained in:
fhysy 2024-07-15 16:52:03 +08:00
parent 1152321c30
commit 17164687b6
7 changed files with 192 additions and 118 deletions

1
.gitignore vendored
View File

@ -2,3 +2,4 @@ node_modules
out
.DS_Store
*.log*
/dist/

View File

@ -8,7 +8,6 @@
http-equiv="Content-Security-Policy"
content="default-src 'self'; connect-src 'self' http://127.0.0.1:8000 http://192.168.1.17:8000 ws://192.168.1.17:8000 ws://127.0.0.1:8000; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:"
/>
<script src="/src/util/config.js"></script>
</head>
<body>

View File

@ -3,9 +3,7 @@ import { RouterView } from "vue-router"
</script>
<template>
<keep-alive :include="['switch', 'about', 'test']">
<router-view></router-view>
</keep-alive>
<RouterView></RouterView>
</template>
<style>

View File

@ -5,12 +5,12 @@
// }
// 手动配置的地址
window.config = {
url: 'http://127.0.0.1:8000',
wsUrl: 'ws://127.0.0.1:8000',
}
// window.config = {
// url: 'http://127.0.0.1:8000',
// wsUrl: 'ws://127.0.0.1:8000',
// }
export const config = {
export default {
url: 'http://127.0.0.1:8000',
wsUrl: 'ws://127.0.0.1:8000',
wsUrl: 'ws://127.0.0.1:8000'
}

View File

@ -1,11 +1,11 @@
import { ElMessage as message } from 'element-plus'
// import storage from 'store'
import { config } from "@renderer/util/config.js"
let receiveMessage = null;
import { reactive } from 'vue';
import config from '@renderer/util/config.js'
let receiveMessage = null
import { reactive } from 'vue'
const socket = reactive({
websocket: null,
connectURL: config.wsUrl+'/ws/log',
connectURL: config.wsUrl + '/ws/log',
// 开启标识
socket_open: false,
// 心跳timer
@ -24,7 +24,7 @@ const socket = reactive({
reconnect_interval: 5 * 1000,
init: (overrideReceiveMessage) => {
if (overrideReceiveMessage) {
receiveMessage = overrideReceiveMessage;
receiveMessage = overrideReceiveMessage
}
if (!('WebSocket' in window)) {
message.warning('浏览器不支持WebSocket')
@ -37,7 +37,7 @@ const socket = reactive({
}
}
socket.websocket.onclose = () => {
console.log("socket连接关闭----------------------")
console.log('socket连接关闭----------------------')
socket.socket_open = false
// 需要重新连接
if (socket.is_reonnect) {
@ -48,7 +48,7 @@ const socket = reactive({
socket.is_reonnect = false
return
}
console.log("socket重连次数" + socket.reconnect_current)
console.log('socket重连次数' + socket.reconnect_current)
// 记录重连次数
socket.reconnect_current++
socket.reconnect()
@ -63,7 +63,7 @@ const socket = reactive({
// socket.heartbeat()
}
// 连接发生错误
socket.websocket.onerror = function () { }
socket.websocket.onerror = function () {}
},
heartbeat: () => {
socket.hearbeat_timer && clearInterval(socket.hearbeat_timer)
@ -85,7 +85,7 @@ const socket = reactive({
message({
type: 'warning',
message: 'socket链接已断开',
duration: 1000,
duration: 1000
})
}
},
@ -101,6 +101,6 @@ const socket = reactive({
socket.close()
}
socket.init(receiveMessage)
},
}
})
export default socket;
export default socket

View File

@ -9,7 +9,11 @@ import Aside from '@renderer/components/Aside.vue'
<el-container >
<Aside width="160px"></Aside>
<el-main>
<router-view/>
<router-view v-slot="{ Component }">
<keep-alive>
<component :is="Component" />
</keep-alive>
</router-view>
</el-main>
</el-container>
</el-container>

View File

@ -10,30 +10,63 @@
label-width="auto"
class="demo-mqttForm"
:rules="mqttRules"
style="padding: 20px; padding-bottom: 0"
>
<el-form-item label="Client ID" prop="clientId" required >
<el-input v-model="mqttForm.clientId" type="text" autocomplete="off" :disabled="connectionState"/>
<el-form-item label="Client ID" prop="clientId" required>
<el-input
v-model="mqttForm.clientId"
type="text"
autocomplete="off"
:disabled="connectionState"
/>
</el-form-item>
<el-form-item label="Host" prop="host" required>
<el-input v-model="mqttForm.host" type="text" autocomplete="off" :disabled="connectionState"/>
<el-input
v-model="mqttForm.host"
type="text"
autocomplete="off"
:disabled="connectionState"
/>
</el-form-item>
<el-form-item label="Port" prop="port" required>
<el-input v-model="mqttForm.port" type="text" autocomplete="off" :disabled="connectionState"/>
<el-input
v-model="mqttForm.port"
type="text"
autocomplete="off"
:disabled="connectionState"
/>
</el-form-item>
<el-form-item label="path" prop="path">
<el-input v-model="mqttForm.path" type="text" autocomplete="off" :disabled="connectionState"/>
<el-input
v-model="mqttForm.path"
type="text"
autocomplete="off"
:disabled="connectionState"
/>
</el-form-item>
<el-form-item label="Username" prop="userName" required>
<el-input v-model="mqttForm.userName" type="text" autocomplete="off" :disabled="connectionState"/>
<el-input
v-model="mqttForm.userName"
type="text"
autocomplete="off"
:disabled="connectionState"
/>
</el-form-item>
<el-form-item label="Password" prop="passWord" required>
<el-input v-model="mqttForm.passWord" type="passWord" autocomplete="off" :disabled="connectionState"/>
<el-input
v-model="mqttForm.passWord"
type="passWord"
autocomplete="off"
:disabled="connectionState"
/>
</el-form-item>
<el-form-item class="btn-box">
<el-button :disabled="!connectionState" type="danger" @click="disconnMqtt">断开</el-button>
<el-button :disabled="!connectionState" type="danger" @click="disconnMqtt"
>断开</el-button
>
<el-button :disabled="connectionState" @click="testMqtt(mqttFormRef)">测试</el-button>
<el-button :disabled="connectionState" type="primary" @click="runMqtt(mqttFormRef)">连接</el-button>
<el-button :disabled="connectionState" type="primary" @click="runMqtt(mqttFormRef)"
>连接</el-button
>
</el-form-item>
</el-form>
</el-collapse-item>
@ -45,7 +78,6 @@
label-width="auto"
class="demo-gatewayForm"
:rules="gatewayRules"
style="padding: 20px; padding-bottom: 0"
>
<el-form-item label="网关" prop="gateway" required>
<el-input v-model="gatewayForm.gateway" type="text" autocomplete="off" />
@ -191,7 +223,7 @@
</el-tabs>
</el-collapse-item>
<el-collapse-item title="功能操作" name="4">
<el-form :model="functionForm" label-width="auto" style="padding: 20px">
<el-form :model="functionForm" label-width="auto">
<el-row>
<el-col :span="12">
<el-form-item label="设备号">
@ -258,13 +290,29 @@
<div class="log-box-operate">
<view class="log-box-operate-item">
<div>mqtt状态</div>
<div v-if="connectionState" style="color: #00ff78;display:flex;alignItems:center">连接</div>
<div v-else @click="runMqtt(mqttFormRef)" style="color: red;display:flex;alignItems:center">断连<el-icon><Refresh /></el-icon></div>
<div v-if="connectionState" style="color: #00ff78; display: flex; alignitems: center">
连接
</div>
<div
v-else
style="color: red; display: flex; alignitems: center"
@click="runMqtt(mqttFormRef)"
>
断连<el-icon><Refresh /></el-icon>
</div>
</view>
<view class="log-box-operate-item">
<div>日志状态</div>
<div v-if="socketStatus" style="color: #00ff78;display:flex;alignItems:center">连接</div>
<div v-else @click="initSocket" style="color: #ff0000;display:flex;alignItems:center">断连<el-icon><Refresh /></el-icon></div>
<div v-if="socketStatus" style="color: #00ff78; display: flex; alignitems: center">
连接
</div>
<div
v-else
style="color: #ff0000; display: flex; alignitems: center"
@click="initSocket"
>
断连<el-icon><Refresh /></el-icon>
</div>
</view>
<view class="log-box-operate-item" @click="toggleIsScroll">
<el-tooltip
@ -276,13 +324,7 @@
>
<el-icon><Unlock /></el-icon>
</el-tooltip>
<el-tooltip
v-else
class="box-item"
effect="dark"
content="开启滚动"
placement="bottom"
>
<el-tooltip v-else class="box-item" effect="dark" content="开启滚动" placement="bottom">
<el-icon><Lock /></el-icon>
</el-tooltip>
</view>
@ -291,21 +333,28 @@
</view>
</div>
</div>
<div class="log-box-main" id="log-box-main">
<div id="log-box-main" class="log-box-main">
<div class="log-list">
<div v-for="(item, index) in logList" :key="index" class="log-item">
<p>{{ item.time }}</p>
<el-icon v-if="item.type == 'subscribe'" style="color: #00ff78;font-weight: bold;margin-right: 8px"><Top /></el-icon>
<el-icon v-else-if="item.type == 'publish'" style="color: red;font-weight: bold;margin-right: 8px"><Bottom /></el-icon>
<el-icon v-else-if="item.type == 'system'" style="font-weight: bold;margin-right: 8px"><Message /></el-icon>
<p>{{item.msg}}</p>
<el-tooltip
class="box-item"
effect="dark"
content="复制"
placement="bottom"
>
<el-icon style="font-weight: bold;cursor: pointer" @click="copyMsg(item.msg)"><DocumentCopy /></el-icon>
<el-icon
v-if="item.type == 'subscribe'"
style="color: #00ff78; font-weight: bold; margin-right: 8px"
><Top
/></el-icon>
<el-icon
v-else-if="item.type == 'publish'"
style="color: red; font-weight: bold; margin-right: 8px"
><Bottom
/></el-icon>
<el-icon v-else-if="item.type == 'system'" style="font-weight: bold; margin-right: 8px"
><Message
/></el-icon>
<p>{{ item.msg }}</p>
<el-tooltip class="box-item" effect="dark" content="复制" placement="bottom">
<el-icon style="font-weight: bold; cursor: pointer" @click="copyMsg(item.msg)"
><DocumentCopy
/></el-icon>
</el-tooltip>
</div>
</div>
@ -316,8 +365,8 @@
<script setup>
import axios from 'axios' // axios
import dayjs from 'dayjs';
import { config } from "@renderer/util/config.js"
import dayjs from 'dayjs'
import config from '@renderer/util/config.js'
import { reactive, ref, onMounted, computed, watch, onUnmounted } from 'vue'
import { ElMessage } from 'element-plus'
@ -380,7 +429,6 @@ const gatewayRules = reactive({
publishTopic: [{ required: true, message: '下行主题不能为空', trigger: 'blur' }]
})
//
const attrList = [
{
@ -541,10 +589,10 @@ const foldChange = (val) => {
//
const disconnMqtt = () => {
axios
.get(config.url+'/mqtt/disconn', {
.get(config.url + '/mqtt/disconn', {
// GET
params: {
clientId:mqttForm.clientId
clientId: mqttForm.clientId
}
})
.then((response) => {
@ -552,10 +600,10 @@ const disconnMqtt = () => {
console.log(response) //
if (response.data.code == 0) {
ElMessage.success('断开成功')
connectionState.value = false;
connectionState.value = false
} else {
if(response.data.code == 60){
connectionState.value = false;
if (response.data.code == 60) {
connectionState.value = false
}
ElMessage.error(response.data.message)
}
@ -573,7 +621,7 @@ const testMqtt = (formEl) => {
formEl.validate((valid) => {
if (valid) {
axios
.get(config.url+'/mqtt/connTest', {
.get(config.url + '/mqtt/connTest', {
// GET
params: mqttForm
})
@ -583,8 +631,8 @@ const testMqtt = (formEl) => {
if (response.data.code == 0) {
ElMessage.success('测试成功')
} else {
if(response.data.code == 60){
connectionState.value = false;
if (response.data.code == 60) {
connectionState.value = false
}
ElMessage.error(response.data.message)
}
@ -605,7 +653,7 @@ const runMqtt = (formEl) => {
formEl.validate((valid) => {
if (valid) {
axios
.get(config.url+'/mqtt/conn', {
.get(config.url + '/mqtt/conn', {
// GET
params: mqttForm
})
@ -614,15 +662,17 @@ const runMqtt = (formEl) => {
console.log(response) //
if (response.data.code == 0) {
ElMessage.success('连接成功')
connectionState.value = true;
activeFold.value = activeFold.value.filter(item => item !== '1')
//
localStorage.setItem('mqttForm', JSON.stringify(mqttForm))
connectionState.value = true
activeFold.value = activeFold.value.filter((item) => item !== '1')
if (!activeFold.value.includes('2')) {
// 1
activeFold.value.unshift('2');
activeFold.value.unshift('2')
}
} else {
if(response.data.code == 60){
connectionState.value = false;
if (response.data.code == 60) {
connectionState.value = false
}
ElMessage.error(response.data.message)
}
@ -645,7 +695,7 @@ const updateGateway = (formEl) => {
if (valid) {
console.log('submit!', gatewayForm)
axios
.get(config.url+'/updateListen', {
.get(config.url + '/updateListen', {
// GET
params: gatewayForm
})
@ -653,10 +703,12 @@ const updateGateway = (formEl) => {
//
console.log(response) //
if (response.data.code == 0) {
//
localStorage.setItem('gatewayForm', JSON.stringify(gatewayForm))
ElMessage.success('更新成功')
} else {
if(response.data.code == 60){
connectionState.value = false;
if (response.data.code == 60) {
connectionState.value = false
}
ElMessage.error(response.data.message)
}
@ -732,21 +784,21 @@ const readAttr = (from) => {
type: 'error'
})
} else {
console.log('验证通过',JSON.parse(attrReadTextrea.value))
console.log('验证通过', JSON.parse(attrReadTextrea.value))
let params = {
deviceSN: attrReadForm.deviceSN,
data: JSON.parse(attrReadTextrea.value)
}
axios
.post(config.url+'/readParam', params)
.post(config.url + '/readParam', params)
.then((response) => {
//
console.log(response) //
if (response.data.code == 0) {
ElMessage.success('指令发送成功')
} else {
if(response.data.code == 60){
connectionState.value = false;
if (response.data.code == 60) {
connectionState.value = false
}
ElMessage.error(response.data.message)
}
@ -826,14 +878,14 @@ const writeAttr = (from) => {
data: JSON.parse(attrWriteTextrea.value)
}
axios
.post(config.url+'/writeParam', params)
.post(config.url + '/writeParam', params)
.then((response) => {
//
if (response.data.code == 0) {
ElMessage.success('指令发送成功')
} else {
if(response.data.code == 60){
connectionState.value = false;
if (response.data.code == 60) {
connectionState.value = false
}
ElMessage.error(response.data.message)
}
@ -881,21 +933,21 @@ const functionWrite = (from) => {
type: 'error'
})
} else {
console.log('验证通过',functionForm.selectAttr)
console.log('验证通过', functionForm.selectAttr)
let params = {
deviceSN: attrReadForm.deviceSN,
data: functionForm.selectAttr
}
axios
.post(config.url+'/writeFunc',params)
.post(config.url + '/writeFunc', params)
.then((response) => {
//
console.log(response) //
if (response.data.code == 0) {
ElMessage.success('指令发送成功')
} else {
if(response.data.code == 60){
connectionState.value = false;
if (response.data.code == 60) {
connectionState.value = false
}
ElMessage.error(response.data.message)
}
@ -913,39 +965,39 @@ const clearLog = () => {
}
const getSocketMeassage = (message) => {
let msg = JSON.parse(message.data);
if(msg.msgType != undefined){
let msg = JSON.parse(message.data)
if (msg.msgType !== undefined) {
logList.value.push({
time:dayjs().format('YYYY-MM-DD HH:mm:ss'),
time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
msg: msg.data,
type: msg.msgType
})
}else{
} else {
logList.value.push({
time:dayjs().format('YYYY-MM-DD HH:mm:ss'),
time: dayjs().format('YYYY-MM-DD HH:mm:ss'),
msg,
type: null
})
}
if(isScroll.value){
setTimeout(()=>{
let div = document.querySelector('#log-box-main');
console.log("div.scrollHeight",div.scrollHeight)
div.scrollTop = div.scrollHeight;
},200)
if (isScroll.value) {
setTimeout(() => {
let div = document.querySelector('#log-box-main')
console.log('div.scrollHeight', div.scrollHeight)
div.scrollTop = div.scrollHeight
}, 200)
}
}
const copyMsg = async (txt) => {
try {
//
await navigator.clipboard.writeText(JSON.stringify(txt));
ElMessage.success('复制成功');
await navigator.clipboard.writeText(JSON.stringify(txt))
ElMessage.success('复制成功')
} catch (err) {
//
ElMessage.error('复制失败')
}
};
}
const toggleIsScroll = () => {
isScroll.value = !isScroll.value
@ -955,15 +1007,22 @@ const initSocket = () => {
socket.init(getSocketMeassage)
}
// socket
const socketStatus = computed(() => {
return socket.socket_open;
return socket.socket_open
})
//
onMounted(() => {
initSocket()
const storedMqttForm = localStorage.getItem('mqttForm')
if (storedMqttForm) {
Object.assign(mqttForm, JSON.parse(storedMqttForm))
}
const storedgatewayForm = localStorage.getItem('gatewayForm')
if (storedgatewayForm) {
Object.assign(gatewayForm, JSON.parse(storedgatewayForm))
}
})
onUnmounted(() => {
@ -977,7 +1036,6 @@ onUnmounted(() => {
height: 100%;
position: relative;
.switch-main {
//padding: 10px;
height: calc(100% - 200px - 60px);
overflow-y: auto;
}
@ -995,16 +1053,16 @@ onUnmounted(() => {
display: flex;
align-items: center;
justify-content: space-between;
.log-box-header{
font-size: 18px;
font-weight: bold;
line-height: 28px;
}
.log-box-operate{
.log-box-operate {
display: flex;
align-items: center;
font-size: 14px;
.log-box-operate-item{
.log-box-operate-item {
cursor: pointer;
display: flex;
align-items: center;
@ -1016,33 +1074,47 @@ onUnmounted(() => {
padding: 10px;
height: 169px;
overflow-y: auto;
.log-item {
font-size: 13px;
user-select: text ;
//line-height: 18px;
user-select: text;
display: flex;
align-items: center;
flex-wrap: wrap;
>p{
> p {
margin-right: 8px;
}
}
}
}
/deep/.el-collapse-item__header {
:deep(.el-form) {
padding: 20px 20px 0;
}
:deep(.el-tabs--border-card > .el-tabs__content) {
padding: 0;
}
:deep(.el-collapse-item__header) {
background-color: #0066cc;
color: #fff;
font-size: 18px;
font-weight: bold;
text-indent: 10px;
height: 40px;
line-height: 40px;
}
/deep/.el-collapse-item__content {
:deep(.el-collapse-item__content) {
padding-bottom: 0;
}
.btn-box {
/deep/.el-form-item__content {
:deep(.el-form-item__content) {
justify-content: end;
width: 100%;
padding: 0;
}
}
}