Compare commits
3 Commits
455833c9d4
...
e4122162ba
| Author | SHA1 | Date | |
|---|---|---|---|
| e4122162ba | |||
| 974dc89292 | |||
| 611cb0c6d7 |
108
README.md
Normal file
108
README.md
Normal file
@@ -0,0 +1,108 @@
|
||||
# frost-mqtt-client
|
||||
|
||||
一个使用 AI 开发的多功能 MQTT 桌面客户端,基于 Electron + Vue 3 + Naive UI 构建。
|
||||
|
||||
## 功能特性
|
||||
|
||||
- **多服务器管理**:支持添加、编辑、删除多个 MQTT 服务器配置,数据持久化到本地。
|
||||
- **灵活连接**:支持 `mqtt://`、`mqtts://`、`ws://`、`wss://` 多种协议,可配置用户名、密码、客户端 ID、Keep Alive、Clean Session 等。
|
||||
- **主题订阅**:支持 QoS 0/1/2 多级订阅,通配符主题(如 `sensor/+/temperature`),可单个或批量订阅/取消订阅。
|
||||
- **消息发布**:向指定主题发布消息,支持设置 QoS 和 Retain 标志,内置 JSON 格式化。
|
||||
- **消息中心**:实时显示接收和发送的消息,支持按主题过滤、清空日志,自动 JSON 美化。
|
||||
- **仪表盘概览**:展示服务器总数、连接数、订阅主题数、消息总数等关键指标,以及当前服务器状态。
|
||||
- **本地持久化**:服务器配置、订阅主题、消息记录、发布历史均自动保存到本地用户数据目录。
|
||||
|
||||
## 技术栈
|
||||
|
||||
- [Electron](https://www.electronjs.org/)
|
||||
- [Vue 3](https://vuejs.org/)
|
||||
- [Vite](https://vitejs.dev/)
|
||||
- [electron-vite](https://electron-vite.org/)
|
||||
- [Naive UI](https://www.naiveui.com/)
|
||||
- [MQTT.js](https://github.com/mqttjs/MQTT.js)
|
||||
|
||||
## 项目结构
|
||||
|
||||
```
|
||||
frost-mqtt-client/
|
||||
├── app/ # Electron 应用源码
|
||||
│ ├── src/
|
||||
│ │ ├── main/ # 主进程
|
||||
│ │ │ ├── index.js # 应用入口
|
||||
│ │ │ ├── ipc-handlers.js # IPC 通信处理
|
||||
│ │ │ └── mqtt-manager.js # MQTT 连接与数据管理
|
||||
│ │ ├── preload/ # 预加载脚本
|
||||
│ │ └── renderer/ # 渲染进程
|
||||
│ │ └── src/
|
||||
│ │ ├── components/ # 公共组件
|
||||
│ │ ├── stores/ # Pinia 状态管理
|
||||
│ │ ├── views/ # 页面视图
|
||||
│ │ └── App.vue # 根组件
|
||||
│ ├── package.json
|
||||
│ └── electron.vite.config.mjs
|
||||
├── design/ # 设计稿页面
|
||||
└── README.md
|
||||
```
|
||||
|
||||
## 环境要求
|
||||
|
||||
- [Node.js](https://nodejs.org/) 18+
|
||||
- [pnpm](https://pnpm.io/) 8+
|
||||
|
||||
## 安装依赖
|
||||
|
||||
```bash
|
||||
$ cd app
|
||||
$ pnpm install
|
||||
```
|
||||
|
||||
## 开发运行
|
||||
|
||||
```bash
|
||||
$ cd app
|
||||
$ pnpm dev
|
||||
```
|
||||
|
||||
## 构建打包
|
||||
|
||||
```bash
|
||||
$ cd app
|
||||
|
||||
# Windows
|
||||
$ pnpm build:win
|
||||
|
||||
# macOS
|
||||
$ pnpm build:mac
|
||||
|
||||
# Linux
|
||||
$ pnpm build:linux
|
||||
```
|
||||
|
||||
打包后的安装包会输出到 `app/dist` 目录。
|
||||
|
||||
## 默认配置
|
||||
|
||||
首次启动时,应用会自动创建一个示例服务器:
|
||||
|
||||
- **名称**:EMQX 公共测试
|
||||
- **地址**:`broker.emqx.io`
|
||||
- **端口**:`1883`
|
||||
- **协议**:`mqtt`
|
||||
|
||||
你也可以在左侧服务器列表中点击「添加服务器」按钮,配置自己的 MQTT Broker。
|
||||
|
||||
## 使用说明
|
||||
|
||||
1. 在左侧边栏选择或添加 MQTT 服务器。
|
||||
2. 在「仪表盘」页面点击「连接服务器」。
|
||||
3. 切换到「主题订阅」页面,添加并订阅感兴趣的主题。
|
||||
4. 在「消息中心」页面可发布消息并实时查看收发日志。
|
||||
5. 所有配置和消息记录会自动保存,下次打开即可继续使用。
|
||||
|
||||
## 数据存储
|
||||
|
||||
应用数据(服务器配置、订阅主题、消息记录等)存储在系统的用户数据目录下:
|
||||
|
||||
- **Windows**:`%APPDATA%\frost-mqtt-client\frost-mqtt-data.json`
|
||||
- **macOS**:`~/Library/Application Support/frost-mqtt-client/frost-mqtt-data.json`
|
||||
- **Linux**:`~/.config/frost-mqtt-client/frost-mqtt-data.json`
|
||||
@@ -1,30 +0,0 @@
|
||||
# frost-mqtt-client
|
||||
|
||||
An Electron application with Vue
|
||||
|
||||
## Project Setup
|
||||
|
||||
### Install
|
||||
|
||||
```bash
|
||||
$ pnpm install
|
||||
```
|
||||
|
||||
### Development
|
||||
|
||||
```bash
|
||||
$ pnpm dev
|
||||
```
|
||||
|
||||
### Build
|
||||
|
||||
```bash
|
||||
# For windows
|
||||
$ pnpm build:win
|
||||
|
||||
# For macOS
|
||||
$ pnpm build:mac
|
||||
|
||||
# For Linux
|
||||
$ pnpm build:linux
|
||||
```
|
||||
@@ -110,6 +110,9 @@ class MqttManager {
|
||||
password: '',
|
||||
keepAlive: 60,
|
||||
cleanSession: true,
|
||||
connectTimeout: 10000,
|
||||
reconnect: true,
|
||||
reconnectInterval: 5000,
|
||||
status: 'disconnected',
|
||||
topics: [
|
||||
{ id: 'topic_default_001', topic: 'sensor/+/temperature', qos: 1, subscribed: false },
|
||||
@@ -175,6 +178,9 @@ class MqttManager {
|
||||
password: config.password || '',
|
||||
keepAlive: config.keepAlive || 60,
|
||||
cleanSession: config.cleanSession !== false,
|
||||
connectTimeout: config.connectTimeout ?? 10000,
|
||||
reconnect: config.reconnect !== false,
|
||||
reconnectInterval: config.reconnectInterval ?? 5000,
|
||||
status: 'disconnected',
|
||||
topics: [],
|
||||
};
|
||||
@@ -205,6 +211,9 @@ class MqttManager {
|
||||
username: config.username || '',
|
||||
keepAlive: config.keepAlive || 60,
|
||||
cleanSession: config.cleanSession !== false,
|
||||
connectTimeout: config.connectTimeout ?? server.connectTimeout ?? 10000,
|
||||
reconnect: config.reconnect !== false,
|
||||
reconnectInterval: config.reconnectInterval ?? server.reconnectInterval ?? 5000,
|
||||
});
|
||||
|
||||
if (config.password) {
|
||||
@@ -254,8 +263,8 @@ class MqttManager {
|
||||
password: server.password || undefined,
|
||||
keepalive: server.keepAlive,
|
||||
clean: server.cleanSession,
|
||||
reconnectPeriod: 5000,
|
||||
connectTimeout: 10000,
|
||||
reconnectPeriod: 0,
|
||||
connectTimeout: server.connectTimeout,
|
||||
};
|
||||
|
||||
try {
|
||||
@@ -265,6 +274,8 @@ class MqttManager {
|
||||
client.on('connect', () => {
|
||||
server.status = 'connected';
|
||||
this.notify('status-change', { id, status: 'connected' });
|
||||
// 只在首次连接成功后,再根据配置启用自动重连
|
||||
client.options.reconnectPeriod = server.reconnect ? server.reconnectInterval : 0;
|
||||
// 自动订阅已有主题
|
||||
server.topics.forEach((t) => {
|
||||
this._doSubscribe(id, t.topic, { qos: t.qos });
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup>
|
||||
import { ref, watch } from 'vue';
|
||||
import { NModal, NForm, NFormItem, NGrid, NFormItemGi, NInput, NInputNumber, NSelect, NSwitch, NButton, useMessage } from 'naive-ui';
|
||||
import { NModal, NForm, NGrid, NFormItemGi, NInput, NInputNumber, NSelect, NSwitch, NButton, useMessage } from 'naive-ui';
|
||||
import { useMqttStore } from '../stores/mqtt.js';
|
||||
|
||||
const props = defineProps({
|
||||
@@ -24,6 +24,9 @@ const form = ref({
|
||||
password: '',
|
||||
keepAlive: 60,
|
||||
cleanSession: true,
|
||||
connectTimeout: 10000,
|
||||
reconnect: true,
|
||||
reconnectInterval: 5000,
|
||||
});
|
||||
|
||||
const rules = {
|
||||
@@ -57,6 +60,9 @@ watch(
|
||||
password: '',
|
||||
keepAlive: props.editServer.keepAlive || 60,
|
||||
cleanSession: props.editServer.cleanSession !== false,
|
||||
connectTimeout: props.editServer.connectTimeout ?? 10000,
|
||||
reconnect: props.editServer.reconnect !== false,
|
||||
reconnectInterval: props.editServer.reconnectInterval ?? 5000,
|
||||
};
|
||||
} else {
|
||||
isEdit.value = false;
|
||||
@@ -70,6 +76,9 @@ watch(
|
||||
password: '',
|
||||
keepAlive: 60,
|
||||
cleanSession: true,
|
||||
connectTimeout: 10000,
|
||||
reconnect: true,
|
||||
reconnectInterval: 5000,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -187,9 +196,42 @@ async function handleSave() {
|
||||
/>
|
||||
</n-form-item-gi>
|
||||
</n-grid>
|
||||
<n-form-item label="Clean Session">
|
||||
<n-switch v-model:value="form.cleanSession" />
|
||||
</n-form-item>
|
||||
<n-grid
|
||||
:cols="2"
|
||||
:x-gap="12"
|
||||
>
|
||||
<n-form-item-gi label="Clean Session">
|
||||
<n-switch v-model:value="form.cleanSession" />
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi label="自动重连">
|
||||
<n-switch v-model:value="form.reconnect" />
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi
|
||||
label="连接超时 (毫秒)"
|
||||
path="connectTimeout"
|
||||
>
|
||||
<n-input-number
|
||||
v-model:value="form.connectTimeout"
|
||||
:min="1000"
|
||||
:max="120000"
|
||||
:step="1000"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</n-form-item-gi>
|
||||
<n-form-item-gi
|
||||
label="重连间隔 (毫秒)"
|
||||
path="reconnectInterval"
|
||||
>
|
||||
<n-input-number
|
||||
v-model:value="form.reconnectInterval"
|
||||
:min="1000"
|
||||
:max="300000"
|
||||
:step="1000"
|
||||
:disabled="!form.reconnect"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</n-form-item-gi>
|
||||
</n-grid>
|
||||
</n-form>
|
||||
<template #footer>
|
||||
<div style="display: flex; justify-content: flex-end; gap: 8px">
|
||||
|
||||
@@ -54,7 +54,7 @@ function handleDelete(server) {
|
||||
<div class="sidebar-logo">F</div>
|
||||
<div>
|
||||
<div class="sidebar-title">Frost MQTT Client</div>
|
||||
<div class="sidebar-subtitle">多服务器 MQTT 客户端</div>
|
||||
<div class="sidebar-subtitle">多功能 MQTT 客户端</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -813,7 +813,7 @@
|
||||
<div class="sidebar-logo">F</div>
|
||||
<div>
|
||||
<div class="sidebar-title">Frost MQTT Client</div>
|
||||
<div class="sidebar-subtitle">多服务器管理客户端</div>
|
||||
<div class="sidebar-subtitle">多功能 MQTT 客户端</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user