<template>
|
<div style="width: 100%; height: 100%; display: flex; justify-content: center;align-items: center;" >
|
<div class="serial-port-config">
|
<h3>串口配置</h3>
|
<div class="control-group">
|
<label for="port-select">选择串口:</label>
|
<select id="port-select" v-model="serialPortStore.selectedPort" @focus="listPorts">
|
<option v-for="port in availablePorts" :key="port" :value="port">{{ port }}</option>
|
</select>
|
<button @click="listPorts">刷新</button>
|
</div>
|
<div class="control-group">
|
<label for="baud-rate-select">波特率:</label>
|
<select id="baud-rate-select" v-model="serialPortStore.baudRate">
|
<option v-for="rate in baudRates" :key="rate" :value="rate">{{ rate }}</option>
|
</select>
|
</div>
|
<div class="control-group">
|
<button @click="togglePortConnection">{{ serialPortStore.isConnected ? '关闭串口' : '打开串口' }}</button>
|
</div>
|
<p v-if="connectionStatus">状态: {{ connectionStatus }}</p>
|
</div>
|
</div>
|
</template>
|
|
<script setup lang="ts">
|
import { ref, onMounted, watch } from 'vue';
|
import { invoke } from '@tauri-apps/api/core';
|
import { useSerialPortStore } from '../store/serialPort';
|
|
const emit = defineEmits(['connection-change']);
|
|
const serialPortStore = useSerialPortStore();
|
|
const availablePorts = ref<string[]>([]);
|
// const selectedPort = ref<string | null>(null);
|
const baudRates = ref<number[]>([9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600]);
|
// const baudRate = ref<number>(115200); // Default baud rate
|
// const isConnected = ref<boolean>(false);
|
const connectionStatus = ref<string>('');
|
|
// List available serial ports
|
async function listPorts() {
|
try {
|
const ports: string[] = await invoke('list_serial_ports');
|
availablePorts.value = ports;
|
if (!serialPortStore.selectedPort && ports.length > 0) {
|
serialPortStore.setSelectedPort(ports[0]);
|
}
|
} catch (error) {
|
console.error('Error listing serial ports:', error);
|
connectionStatus.value = `错误: ${error}`;
|
}
|
}
|
|
// Open or close the serial port
|
async function togglePortConnection() {
|
if (serialPortStore.isConnected) {
|
// Close port
|
try {
|
await invoke('close_serial_port');
|
serialPortStore.setConnectionStatus(false);
|
connectionStatus.value = '串口已关闭';
|
console.log('Serial port closed');
|
emit('connection-change', false);
|
} catch (error) {
|
console.error('Error closing serial port:', error);
|
connectionStatus.value = `错误: ${error}`;
|
}
|
} else {
|
// Open port
|
if (!serialPortStore.selectedPort) {
|
connectionStatus.value = '请选择一个串口';
|
return;
|
}
|
try {
|
const result:string = await invoke('open_serial_port', { appHandle: null, portName: serialPortStore.selectedPort, baudRate: serialPortStore.baudRate }); // appHandle 在 Tauri 中是隐式传递的,这里只是为了匹配 Rust 函数签名
|
console.log("打开串口:",result);
|
serialPortStore.setConnectionStatus(true);
|
connectionStatus.value = `已连接到 ${serialPortStore.selectedPort} @ ${serialPortStore.baudRate} bps`;
|
console.log(`Connected to ${serialPortStore.selectedPort} @ ${serialPortStore.baudRate} bps`);
|
emit('connection-change', true);
|
} catch (error) {
|
console.error('Error opening serial port:', error);
|
serialPortStore.setConnectionStatus(false);
|
connectionStatus.value = `错误: ${error}`;
|
}
|
}
|
}
|
|
// Automatically list ports when the component mounts
|
onMounted(() => {
|
listPorts();
|
});
|
|
// Watch for changes in selectedPort or baudRate and emit them
|
watch([() => serialPortStore.selectedPort, () => serialPortStore.baudRate, () => serialPortStore.isConnected], () => {
|
// You might want to emit these values to a parent component or a global state manager
|
// For now, we'll just log them.
|
console.log('Selected Port:', serialPortStore.selectedPort);
|
console.log('Baud Rate:', serialPortStore.baudRate);
|
console.log('Is Connected:', serialPortStore.isConnected);
|
});
|
</script>
|
|
<style scoped>
|
.serial-port-config {
|
padding: 20px;
|
border: 1px solid #ccc;
|
border-radius: 8px;
|
margin-bottom: 20px;
|
width:300px;
|
height: 260px;
|
background-color: #f9f9f9;
|
}
|
|
.control-group {
|
margin-bottom: 15px;
|
display: flex;
|
align-items: center;
|
gap: 10px;
|
}
|
|
.control-group label {
|
font-weight: bold;
|
min-width: 80px;
|
text-align: right;
|
}
|
|
.control-group select,
|
.control-group input[type="number"] {
|
padding: 8px;
|
border: 1px solid #ddd;
|
border-radius: 4px;
|
flex-grow: 1;
|
}
|
|
.control-group button {
|
padding: 8px 15px;
|
background-color: #007bff;
|
color: white;
|
border: none;
|
border-radius: 4px;
|
cursor: pointer;
|
transition: background-color 0.3s ease;
|
}
|
|
.control-group button:hover {
|
background-color: #0056b3;
|
}
|
|
p {
|
margin-top: 10px;
|
font-size: 0.9em;
|
color: #555;
|
}
|
</style>
|