559 lines
15 KiB
Vue
559 lines
15 KiB
Vue
<template>
|
||
<view class="page">
|
||
<!-- 通信模式切换 -->
|
||
<view style="padding-top: 60px;">
|
||
<uni-row :gutter="8">
|
||
<uni-col :span="4" :offset="1">
|
||
<uni-section title="通信模式" titleColor="#fff"></uni-section>
|
||
</uni-col>
|
||
<uni-col :span="10">
|
||
<radio-group @change="onModeChange" style="display:flex;gap:20px;align-items:center;">
|
||
<label style="display:flex;align-items:center;">
|
||
<radio value="serial" :checked="mode === 'serial'" />串口直连
|
||
</label>
|
||
<label style="display:flex;align-items:center;">
|
||
<radio value="tcp" :checked="mode === 'tcp'" />网口转485
|
||
</label>
|
||
</radio-group>
|
||
</uni-col>
|
||
<uni-col :span="6">
|
||
<view class="ant-btn ant-btn-lg" @click="saveMode">
|
||
<text>保存模式</text>
|
||
</view>
|
||
</uni-col>
|
||
</uni-row>
|
||
</view>
|
||
|
||
<!-- RS485 配置(根据模式切换) -->
|
||
<view :style="{ 'paddingTop': '20px' }">
|
||
<!-- 串口模式:显示RS485串口配置 -->
|
||
<view v-if="mode === 'serial'">
|
||
<uni-row :gutter="8">
|
||
<uni-col :span="4" :offset="1">
|
||
<uni-section title="RS485" titleColor="#fff"></uni-section>
|
||
</uni-col>
|
||
<uni-col :span="5">
|
||
<uni-data-select
|
||
placeholder="请选择串口"
|
||
v-model="rs485PathKey"
|
||
@change="rs485Pathchange"
|
||
:localdata="list"
|
||
:clear="false"
|
||
></uni-data-select>
|
||
</uni-col>
|
||
<uni-col :span="5">
|
||
<uni-data-select
|
||
placeholder="请选择波特率"
|
||
v-model="rs485Baudrate"
|
||
:localdata="baudrateList"
|
||
:clear="false"
|
||
></uni-data-select>
|
||
</uni-col>
|
||
<uni-col :span="6">
|
||
<view class="ant-btn ant-btn-lg" @click="rs485Connect" v-if="rs485State == false">
|
||
<text>连接</text>
|
||
</view>
|
||
<view style="color: red;" class="ant-btn ant-btn-lg" @click="rs485Disconnect" v-else>
|
||
<text>断开</text>
|
||
</view>
|
||
<view style="margin-left: 10px;color:red;" class="ant-btn ant-btn-lg" @click="rs485Save">
|
||
<text>保存</text>
|
||
</view>
|
||
</uni-col>
|
||
</uni-row>
|
||
|
||
<!-- RS485 指令发送 -->
|
||
<uni-row :gutter="12" style="margin-top: 10px;">
|
||
<uni-col :span="4" :offset="1">
|
||
<uni-section title="指令" titleColor="#fff"></uni-section>
|
||
</uni-col>
|
||
<uni-col :span="8">
|
||
<view class="uni-form-item uni-column">
|
||
<input type="text" class="uni-input" v-model="cmd_485" placeholder="自定义指令" />
|
||
</view>
|
||
</uni-col>
|
||
<uni-col :span="6">
|
||
<view class="ant-btn ant-btn-lg" @click="send485Data">
|
||
<text>发送</text>
|
||
</view>
|
||
</uni-col>
|
||
</uni-row>
|
||
</view>
|
||
|
||
<!-- TCP模式:显示TCP连接配置 -->
|
||
<view v-if="mode === 'tcp'">
|
||
<uni-row :gutter="8">
|
||
<uni-col :span="4" :offset="1">
|
||
<uni-section title="TCP连接" titleColor="#fff"></uni-section>
|
||
</uni-col>
|
||
<uni-col :span="5">
|
||
<input type="text" class="uni-input" v-model="tcpHost" placeholder="IP地址" />
|
||
</uni-col>
|
||
<uni-col :span="3">
|
||
<input type="number" class="uni-input" v-model="tcpPort" placeholder="端口" />
|
||
</uni-col>
|
||
<uni-col :span="5">
|
||
<view class="ant-btn ant-btn-lg" @click="saveTcpConfig">
|
||
<text>保存参数</text>
|
||
</view>
|
||
</uni-col>
|
||
<uni-col :span="4">
|
||
<view class="ant-btn ant-btn-lg" @click="tcpConnect" v-if="tcpState == false">
|
||
<text>TCP连接</text>
|
||
</view>
|
||
<view style="color: red;" class="ant-btn ant-btn-lg" @click="tcpDisconnect" v-else>
|
||
<text>TCP断开</text>
|
||
</view>
|
||
</uni-col>
|
||
</uni-row>
|
||
|
||
<!-- TCP 指令发送 -->
|
||
<uni-row :gutter="12" style="margin-top: 10px;">
|
||
<uni-col :span="4" :offset="1">
|
||
<uni-section title="指令" titleColor="#fff"></uni-section>
|
||
</uni-col>
|
||
<uni-col :span="8">
|
||
<view class="uni-form-item uni-column">
|
||
<input type="text" class="uni-input" v-model="cmd_tcp" placeholder="TCP自定义指令" />
|
||
</view>
|
||
</uni-col>
|
||
<uni-col :span="6">
|
||
<view class="ant-btn ant-btn-lg" @click="sendTcpData">
|
||
<text>发送</text>
|
||
</view>
|
||
</uni-col>
|
||
</uni-row>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- RS232 串口配置(一直保留) -->
|
||
<view :style="{ 'marginTop': '20px' }">
|
||
<uni-row :gutter="8">
|
||
<uni-col :span="4" :offset="1">
|
||
<uni-section title="RS232" titleColor="#fff"></uni-section>
|
||
</uni-col>
|
||
<uni-col :span="5">
|
||
<uni-data-select
|
||
placeholder="请选择串口"
|
||
v-model="rs232PathKey"
|
||
@change="rs232Pathchange"
|
||
:localdata="list"
|
||
:clear="false"
|
||
></uni-data-select>
|
||
</uni-col>
|
||
<uni-col :span="5">
|
||
<uni-data-select
|
||
:clear="false"
|
||
placeholder="请选择波特率"
|
||
v-model="rs232Baudrate"
|
||
:localdata="baudrateList"
|
||
></uni-data-select>
|
||
</uni-col>
|
||
<uni-col :span="6">
|
||
<view class="ant-btn ant-btn-lg" @click="rs232Connect" v-if="rs232State == false">
|
||
<text>连接</text>
|
||
</view>
|
||
<view style="color: red;" class="ant-btn ant-btn-lg" @click="rs232Disconnect" v-else>
|
||
<text>断开</text>
|
||
</view>
|
||
<view style="margin-left: 10px;color:red;" class="ant-btn ant-btn-lg" @click="rs232Save">
|
||
<text>保存</text>
|
||
</view>
|
||
</uni-col>
|
||
</uni-row>
|
||
|
||
<!-- RS232 指令发送 -->
|
||
<uni-row :gutter="12" style="margin-top: 10px;">
|
||
<uni-col :span="4" :offset="1">
|
||
<uni-section title="指令" titleColor="#fff"></uni-section>
|
||
</uni-col>
|
||
<uni-col :span="8">
|
||
<view class="uni-form-item uni-column">
|
||
<input type="text" class="uni-input" v-model="cmd_232" placeholder="自定义指令" />
|
||
</view>
|
||
</uni-col>
|
||
<uni-col :span="6">
|
||
<view class="ant-btn ant-btn-lg" @click="send232Data">
|
||
<text>发送</text>
|
||
</view>
|
||
</uni-col>
|
||
</uni-row>
|
||
</view>
|
||
|
||
<!-- 快捷控制 -->
|
||
<view :style="{ 'marginTop': '20px' }">
|
||
<uni-row :gutter="12">
|
||
<uni-col :span="4" :offset="1">
|
||
<uni-section title="控制" titleColor="#fff"></uni-section>
|
||
</uni-col>
|
||
<uni-col :span="16">
|
||
<view class="ant-btn ant-btn-lg" @click="open(1)">
|
||
<text>开风机</text>
|
||
</view>
|
||
<view class="ant-btn ant-btn-lg" @click="open(2)">
|
||
<text>开照明</text>
|
||
</view>
|
||
<view class="ant-btn ant-btn-lg" @click="open(3)">
|
||
<text>开真空</text>
|
||
</view>
|
||
<view class="ant-btn ant-btn-lg" @click="open(4)">
|
||
<text>开紫外</text>
|
||
</view>
|
||
<view class="ant-btn ant-btn-lg" @click="open(5)">
|
||
<text>开等离子</text>
|
||
</view>
|
||
</uni-col>
|
||
</uni-row>
|
||
<uni-row :gutter="12">
|
||
<uni-col :span="16" :offset="5">
|
||
<view class="ant-btn ant-btn-lg" @click="close(1)">
|
||
<text>关风机</text>
|
||
</view>
|
||
<view class="ant-btn ant-btn-lg" @click="close(2)">
|
||
<text>关照明</text>
|
||
</view>
|
||
<view class="ant-btn ant-btn-lg" @click="close(3)">
|
||
<text>关真空</text>
|
||
</view>
|
||
<view class="ant-btn ant-btn-lg" @click="close(4)">
|
||
<text>关紫外</text>
|
||
</view>
|
||
<view class="ant-btn ant-btn-lg" @click="close(5)">
|
||
<text>关等离子</text>
|
||
</view>
|
||
</uni-col>
|
||
</uni-row>
|
||
</view>
|
||
|
||
<!-- 快捷读取 -->
|
||
<view :style="{ 'marginTop': '20px' }">
|
||
<uni-row :gutter="12">
|
||
<uni-col :span="4" :offset="1">
|
||
<uni-section title="读取" titleColor="#fff"></uni-section>
|
||
</uni-col>
|
||
<uni-col :span="12">
|
||
<view class="ant-btn ant-btn-lg" @click="temp">
|
||
<text>温湿度</text>
|
||
</view>
|
||
<view class="ant-btn ant-btn-lg" @click="pressure">
|
||
<text>压差</text>
|
||
</view>
|
||
</uni-col>
|
||
</uni-row>
|
||
</view>
|
||
|
||
<!-- 接收数据展示 -->
|
||
<view :style="{ 'marginTop': '20px', 'paddingBottom': '40px' }">
|
||
<uni-row :gutter="12">
|
||
<uni-col :span="4" :offset="1">
|
||
<uni-section title="接收数据" titleColor="#fff"></uni-section>
|
||
</uni-col>
|
||
<uni-col :span="10">
|
||
<view class="receive-item">
|
||
<view v-for="(item, index) in received" :key="index">
|
||
{{ item }}
|
||
</view>
|
||
</view>
|
||
</uni-col>
|
||
<uni-col :span="6">
|
||
<view class="ant-btn ant-btn-lg" @click="clearReceived">
|
||
<text>清空</text>
|
||
</view>
|
||
</uni-col>
|
||
</uni-row>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import storage from '@/utils/storage.js'
|
||
import cmd from '@/utils/cmd.js'
|
||
import tcp485 from '@/utils/tcp485.js'
|
||
export default {
|
||
data() {
|
||
return {
|
||
mode: 'serial',
|
||
tcpHost: '',
|
||
tcpPort: '',
|
||
tcpState: false, // TCP连接状态
|
||
|
||
RS485: undefined,
|
||
received: [],
|
||
list: [],
|
||
baudrateList: [
|
||
{ value: 4800, text: '4800' },
|
||
{ value: 9600, text: '9600' },
|
||
{ value: 19200, text: '19200' },
|
||
{ value: 38400, text: '38400' },
|
||
{ value: 57600, text: '57600' },
|
||
{ value: 115200, text: '115200' },
|
||
],
|
||
rs485State: false,
|
||
rs485Path: '',
|
||
rs485PathKey: '',
|
||
rs485Baudrate: '',
|
||
|
||
RS232: undefined,
|
||
rs232State: false,
|
||
rs232Path: '',
|
||
rs232PathKey: '',
|
||
rs232Baudrate: '',
|
||
|
||
cmd_485: '010300000002C40B',
|
||
cmd_232: '',
|
||
cmd_tcp: '0306000100011828',
|
||
}
|
||
},
|
||
|
||
onLoad() {
|
||
this.mode = storage.get('rs485Mode') || 'serial'
|
||
// 分别读取串口配置和TCP配置
|
||
const rs485Tcp = storage.get('rs485Tcp') || {}
|
||
this.tcpHost = rs485Tcp.host || ''
|
||
this.tcpPort = rs485Tcp.port || ''
|
||
|
||
this.RS485 = getApp().globalData.RS485
|
||
this.RS232 = getApp().globalData.RS232
|
||
this.getDevice()
|
||
},
|
||
onUnload() {
|
||
this.tcpDisconnect()
|
||
if (this.rs232State) this.rs232Disconnect()
|
||
if (this.rs485State) this.rs485Disconnect()
|
||
},
|
||
|
||
methods: {
|
||
// ========== 模式切换 ==========
|
||
onModeChange(e) {
|
||
this.mode = e.detail.value
|
||
},
|
||
saveMode() {
|
||
storage.set('rs485Mode', this.mode)
|
||
uni.showToast({ title: '已保存,重启后生效', icon: 'none' })
|
||
},
|
||
saveTcpConfig() {
|
||
const rs485Tcp = storage.get('rs485Tcp') || {}
|
||
rs485Tcp.host = this.tcpHost
|
||
rs485Tcp.port = this.tcpPort
|
||
storage.set('rs485Tcp', rs485Tcp)
|
||
uni.showToast({ title: 'TCP参数已保存', icon: 'none' })
|
||
},
|
||
|
||
// ========== TCP连接控制 ==========
|
||
async tcpConnect() {
|
||
if (this.tcpState) return
|
||
const host = this.tcpHost || (storage.get('rs485Tcp') || {}).host
|
||
const port = this.tcpPort || (storage.get('rs485Tcp') || {}).port
|
||
if (!host || !port) {
|
||
uni.showToast({ title: '请先填写IP和端口', icon: 'none' })
|
||
return
|
||
}
|
||
tcp485.setHost(host, port)
|
||
try {
|
||
await tcp485.open()
|
||
this.tcpState = true
|
||
// 注册数据回调,收到数据展示在页面
|
||
tcp485.onStartAutoReadData((hexStr) => {
|
||
console.log('autoread:', hexStr)
|
||
this.received.unshift(hexStr)
|
||
})
|
||
uni.showToast({ title: 'TCP连接成功', icon: 'success' })
|
||
} catch (err) {
|
||
console.error('[modbus] TCP连接失败', err)
|
||
uni.showToast({ title: 'TCP连接失败', icon: 'none' })
|
||
}
|
||
},
|
||
tcpDisconnect() {
|
||
if (!this.tcpState) return
|
||
tcp485.stopReadPortData()
|
||
tcp485.close()
|
||
this.tcpState = false
|
||
uni.showToast({ title: 'TCP已断开', icon: 'none' })
|
||
},
|
||
|
||
// ========== RS485串口 ==========
|
||
getDevice() {
|
||
const list = this.RS485.getAllDevices()
|
||
if (list.length) {
|
||
this.list = list.map((i, key) => {
|
||
return { value: key, text: i }
|
||
})
|
||
}
|
||
// 自动连接已保存的串口(从rs485读取,保持原有存储不变)
|
||
let rs485Conf = storage.get('rs485')
|
||
if (rs485Conf && rs485Conf.path) {
|
||
let cur = this.list.find(i => i.text == rs485Conf.path)
|
||
if (cur) {
|
||
this.rs485PathKey = cur.value
|
||
this.rs485Path = rs485Conf.path
|
||
this.rs485Baudrate = rs485Conf.baudrate
|
||
this.rs485Connect()
|
||
}
|
||
}
|
||
let rs232Conf = storage.get('rs232')
|
||
if (rs232Conf && rs232Conf.path) {
|
||
let cur = this.list.find(i => i.text == rs232Conf.path)
|
||
if (cur) {
|
||
this.rs232PathKey = cur.value
|
||
this.rs232Path = rs232Conf.path
|
||
this.rs232Baudrate = rs232Conf.baudrate
|
||
this.rs232Connect()
|
||
}
|
||
}
|
||
},
|
||
rs485Pathchange(e) {
|
||
this.rs485Path = this.list[e].text
|
||
},
|
||
rs232Pathchange(e) {
|
||
this.rs232Path = this.list[e].text
|
||
},
|
||
rs485Save() {
|
||
storage.set('rs485', { path: this.rs485Path, baudrate: this.rs485Baudrate })
|
||
uni.showToast({ title: '保存成功', icon: 'none' })
|
||
},
|
||
rs485Connect() {
|
||
this.RS485.setPath(this.rs485Path)
|
||
this.RS485.setBaudrate(this.rs485Baudrate)
|
||
this.rs485State = this.RS485.open()
|
||
if (this.rs485State) {
|
||
this.RS485.onStartAutoReadData((res) => {
|
||
this.received.unshift(this.RS485.byte2HexString(res))
|
||
})
|
||
}
|
||
},
|
||
rs485Disconnect() {
|
||
this.RS485.stopReadPortData()
|
||
this.RS485.close()
|
||
this.rs485State = false
|
||
},
|
||
rs232Connect() {
|
||
this.RS232.setPath(this.rs232Path)
|
||
this.RS232.setBaudrate(this.rs232Baudrate)
|
||
this.rs232State = this.RS232.open()
|
||
if (this.rs232State) {
|
||
this.RS232.onStartAutoReadData((res) => {
|
||
this.received.unshift(this.RS232.byte2HexString(res))
|
||
})
|
||
}
|
||
},
|
||
rs232Disconnect() {
|
||
this.RS232.stopReadPortData()
|
||
this.RS232.close()
|
||
this.rs232State = false
|
||
},
|
||
rs232Save() {
|
||
storage.set('rs232', { path: this.rs232Path, baudrate: this.rs232Baudrate })
|
||
uni.showToast({ title: '保存成功', icon: 'none' })
|
||
},
|
||
send485Data() {
|
||
this.RS485.sendDataString(this.cmd_485)
|
||
},
|
||
send232Data() {
|
||
this.RS232.sendDataString(this.cmd_232)
|
||
},
|
||
sendTcpData() {
|
||
if (!this.tcpState) {
|
||
uni.showToast({ title: '请先连接TCP', icon: 'none' })
|
||
return
|
||
}
|
||
tcp485.sendDataString(this.cmd_tcp)
|
||
},
|
||
clearReceived() {
|
||
this.received = []
|
||
},
|
||
|
||
// ========== 快捷控制 ==========
|
||
open(key) {
|
||
switch(key) {
|
||
case 1:
|
||
this.RS232.sendDataString('5AA5EE0101')
|
||
break
|
||
case 2:
|
||
this.RS232.sendDataString('5AA5EE0201')
|
||
break
|
||
case 3:
|
||
this.RS232.sendDataString('5AA5EE0301')
|
||
break
|
||
case 4:
|
||
this.RS232.sendDataString('5AA5EE0401')
|
||
break
|
||
case 5:
|
||
this.RS232.sendDataString('5AA5EE0501')
|
||
break
|
||
default:
|
||
break
|
||
}
|
||
},
|
||
close(key) {
|
||
switch(key) {
|
||
case 1:
|
||
this.RS232.sendDataString('5AA5EE0100')
|
||
break
|
||
case 2:
|
||
this.RS232.sendDataString('5AA5EE0200')
|
||
break
|
||
case 3:
|
||
this.RS232.sendDataString('5AA5EE0300')
|
||
break
|
||
case 4:
|
||
this.RS232.sendDataString('5AA5EE0400')
|
||
break
|
||
case 5:
|
||
this.RS232.sendDataString('5AA5EE0500')
|
||
break
|
||
default:
|
||
break
|
||
}
|
||
},
|
||
temp() {
|
||
this.RS485.sendDataString('020300000002C438')
|
||
},
|
||
pressure() {
|
||
this.RS485.sendDataString('01030001000295CB')
|
||
},
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.page{
|
||
color: #fff;
|
||
text-align: left;
|
||
}
|
||
:deep(.uni-select){
|
||
min-height: 40px;
|
||
color: rgba(0, 0, 0, .85);
|
||
}
|
||
.uni-input{
|
||
height: 40px;
|
||
border: 1px solid #d9d9d9;
|
||
background-color: #fff;
|
||
color: rgba(0, 0, 0, .85);
|
||
text-align: left;
|
||
padding: 0 6px;
|
||
white-space: 6px;
|
||
}
|
||
:deep(.uni-section){
|
||
background-color: transparent;
|
||
}
|
||
.page :deep(.uni-section .uni-section-header__content){
|
||
line-height: 20px;
|
||
font-weight: 800;
|
||
text-align: right;
|
||
}
|
||
:deep(.uni-section .uni-section-header){
|
||
padding: 10px;
|
||
}
|
||
.ant-btn:hover,
|
||
.ant-btn:focus,
|
||
.ant-btn:active{
|
||
color: rgba(0, 0, 0, 0.85);
|
||
}
|
||
|
||
.receive-item{
|
||
padding-left: 10px;
|
||
height: 400px;
|
||
overflow-y: auto;
|
||
}
|
||
</style>
|