├── .gitattributes
├── .gitignore
├── .npmrc
├── .prettierrc
├── LICENSE
├── README.md
├── babel.config.js
├── images
├── 20220619224349.png
├── 20220619224729.png
├── 20220628140513.png
├── 20220628140530.png
└── 20220727224540308.png
├── package.json
├── public
├── favicon.ico
├── icon.ico
├── index.html
└── static
│ └── theme.less
├── src
├── App.vue
├── assets
│ ├── font
│ │ ├── font.ttf
│ │ └── iconfont.css
│ ├── logo.png
│ └── robots.png
├── background.js
├── components
│ ├── Header.vue
│ ├── IPAddress.vue
│ └── Side.vue
├── config
│ └── index.js
├── main.js
├── router
│ └── index.js
├── theme
│ ├── cus-theme.less
│ ├── js
│ │ └── theme.js
│ └── variables.less
└── views
│ ├── Dashboard.vue
│ ├── Net.vue
│ └── Setting.vue
├── vue.config.js
└── yarn.lock
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | dist_electron
4 | /dist
5 | /dist_electron
6 |
7 |
8 | # local env files
9 | .env.local
10 | .env.*.local
11 |
12 | # Log files
13 | npm-debug.log*
14 | yarn-debug.log*
15 | yarn-error.log*
16 | pnpm-debug.log*
17 |
18 | # Editor directories and files
19 | .idea
20 | .vscode
21 | *.suo
22 | *.ntvs*
23 | *.njsproj
24 | *.sln
25 | *.sw?
26 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | registry =https://registry.npm.taobao.org
2 | ELECTRON_MIRROR=https://npm.taobao.org/mirrors/electron/
3 | ELECTRON_BUILDER_BINARIES_MIRROR=http://npm.taobao.org/mirrors/electron-builder-binaries/
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "tabWidth": 2,
3 | "useTabs": true,
4 | "singleQuote": true,
5 | "printWidth": 175,
6 | "semi": true,
7 | "trailingComma": "none",
8 | "bracketSpacing": true,
9 | "arrowParens": "avoid",
10 | "htmlWhitespaceSensitivity": "ignore"
11 | }
12 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 jackchou
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 串口调试助手
2 |
3 | > Electron + Vue + node-serialport + Ant Design 实现串口调试助手
4 |
5 | ## 功能
6 |
7 | - [x] 串口通信
8 | - [x] 16 进制发送和显示
9 | - [x] 自动刷新串口列表
10 | - [x] 定时发送信息
11 | - [x] TCP 通信
12 | - [x] UDP 通信
13 | - [x] UDP 通信
14 | - [x] 主题色切换
15 |
16 | ## 下载&&运行
17 |
18 | 点击[下载链接](https://github.com/binkzhou/vue3_serial/releases)
19 |
20 | ## 界面预览
21 |
22 | 
23 |
24 | 
25 |
26 | 
27 |
28 | 
29 |
30 | 
31 |
32 | 
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: ["@vue/cli-plugin-babel/preset"],
3 | };
4 |
--------------------------------------------------------------------------------
/images/20220619224349.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/binkzhou/vue3_serial/5bb504466c0bdb916ebf6227a66be58a554c302f/images/20220619224349.png
--------------------------------------------------------------------------------
/images/20220619224729.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/binkzhou/vue3_serial/5bb504466c0bdb916ebf6227a66be58a554c302f/images/20220619224729.png
--------------------------------------------------------------------------------
/images/20220628140513.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/binkzhou/vue3_serial/5bb504466c0bdb916ebf6227a66be58a554c302f/images/20220628140513.png
--------------------------------------------------------------------------------
/images/20220628140530.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/binkzhou/vue3_serial/5bb504466c0bdb916ebf6227a66be58a554c302f/images/20220628140530.png
--------------------------------------------------------------------------------
/images/20220727224540308.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/binkzhou/vue3_serial/5bb504466c0bdb916ebf6227a66be58a554c302f/images/20220727224540308.png
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "electron-serial",
3 | "version": "0.1.0",
4 | "private": true,
5 | "main": "background.js",
6 | "scripts": {
7 | "lint": "vue-cli-service lint",
8 | "build": "vue-cli-service electron:build",
9 | "serve": "node src/theme/js/theme.js && vue-cli-service electron:serve",
10 | "postinstall": "electron-rebuild;electron-builder install-app-deps",
11 | "postuninstall": "electron-builder install-app-deps"
12 | },
13 | "dependencies": {
14 | "ant-design-vue": "^2.2.8",
15 | "antd-theme-generator": "^1.2.11",
16 | "core-js": "^3.6.5",
17 | "electron": "12",
18 | "iconv-lite": "^0.6.3",
19 | "less": "2.7.3",
20 | "less-loader": "7.3.0",
21 | "serialport": "^9.2.0",
22 | "vue": "^3.2.6",
23 | "vue-router": "^4.0.12"
24 | },
25 | "devDependencies": {
26 | "@vue/cli-plugin-babel": "~4.5.0",
27 | "@vue/cli-plugin-eslint": "~4.5.0",
28 | "@vue/cli-service": "~4.5.0",
29 | "@vue/compiler-sfc": "^3.0.0",
30 | "babel-eslint": "^10.1.0",
31 | "electron-devtools-installer": "3.2.0",
32 | "electron-rebuild": "^3.2.2",
33 | "eslint": "^6.7.2",
34 | "eslint-plugin-vue": "^7.0.0",
35 | "vue-cli-plugin-electron-builder": "^2.1.1"
36 | },
37 | "eslintConfig": {
38 | "root": true,
39 | "env": {
40 | "node": true
41 | },
42 | "extends": [
43 | "plugin:vue/vue3-essential",
44 | "eslint:recommended"
45 | ],
46 | "parserOptions": {
47 | "parser": "babel-eslint"
48 | },
49 | "rules": {}
50 | },
51 | "browserslist": [
52 | "> 1%",
53 | "last 2 versions",
54 | "not dead"
55 | ]
56 | }
57 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/binkzhou/vue3_serial/5bb504466c0bdb916ebf6227a66be58a554c302f/public/favicon.ico
--------------------------------------------------------------------------------
/public/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/binkzhou/vue3_serial/5bb504466c0bdb916ebf6227a66be58a554c302f/public/icon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | <%= htmlWebpackPlugin.options.title %>
9 |
14 |
15 |
16 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
22 |
23 |
34 |
--------------------------------------------------------------------------------
/src/assets/font/font.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/binkzhou/vue3_serial/5bb504466c0bdb916ebf6227a66be58a554c302f/src/assets/font/font.ttf
--------------------------------------------------------------------------------
/src/assets/font/iconfont.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: 'iconfont';
3 | /* Project id 2546196 */
4 | src: url('./font.ttf') format('truetype');
5 | }
6 |
7 | .iconfont {
8 | font-family: 'iconfont' !important;
9 | font-size: 16px;
10 | font-style: normal;
11 | -webkit-font-smoothing: antialiased;
12 | -moz-osx-font-smoothing: grayscale;
13 | }
14 |
15 | .icon-wangluo:before {
16 | content: '\e617';
17 | }
18 |
19 | .icon-jiekou:before {
20 | content: '\e638';
21 | }
22 |
23 | .icon-zuixiaohua:before {
24 | content: '\e650';
25 | }
26 |
27 | .icon-github:before {
28 | content: '\e645';
29 | }
30 |
31 | .icon-Close:before {
32 | content: '\e689';
33 | }
34 |
35 | .icon-window-maximize:before {
36 | content: '\e679';
37 | }
38 | .icon-shezhi:before {
39 | content: '\e64b';
40 | }
41 | .icon-duihao:before {
42 | content: '\eaf1';
43 | }
44 |
--------------------------------------------------------------------------------
/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/binkzhou/vue3_serial/5bb504466c0bdb916ebf6227a66be58a554c302f/src/assets/logo.png
--------------------------------------------------------------------------------
/src/assets/robots.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/binkzhou/vue3_serial/5bb504466c0bdb916ebf6227a66be58a554c302f/src/assets/robots.png
--------------------------------------------------------------------------------
/src/background.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import { app, protocol, BrowserWindow, ipcMain } from 'electron';
4 | import { createProtocol } from 'vue-cli-plugin-electron-builder/lib';
5 | import installExtension, { VUEJS3_DEVTOOLS } from 'electron-devtools-installer';
6 | const isDevelopment = process.env.NODE_ENV !== 'production';
7 |
8 | // Scheme must be registered before the app is ready
9 | protocol.registerSchemesAsPrivileged([{ scheme: 'app', privileges: { secure: true, standard: true } }]);
10 | let win;
11 | async function createWindow() {
12 | // Create the browser window.
13 | win = new BrowserWindow({
14 | width: 900,
15 | height: 580,
16 | minWidth: 900,
17 | minHeight: 580,
18 | useContentSize: false,
19 | frame: false,
20 | show: false,
21 | webPreferences: {
22 | // Use pluginOptions.nodeIntegration, leave this alone
23 | // See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info
24 | nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
25 | contextIsolation: !process.env.ELECTRON_NODE_INTEGRATION
26 | }
27 | });
28 |
29 | if (process.env.WEBPACK_DEV_SERVER_URL) {
30 | // Load the url of the dev server if in development mode
31 | await win.loadURL(process.env.WEBPACK_DEV_SERVER_URL);
32 | if (!process.env.IS_TEST) win.webContents.openDevTools();
33 | } else {
34 | createProtocol('app');
35 | // Load the index.html when not in development
36 | win.loadURL('app://./index.html');
37 | }
38 |
39 | win.on('ready-to-show', function () {
40 | win.show(); // 初始化后再显示
41 | });
42 | }
43 | app.allowRendererProcessReuse = false;
44 | // Quit when all windows are closed.
45 | app.on('window-all-closed', () => {
46 | // On macOS it is common for applications and their menu bar
47 | // to stay active until the user quits explicitly with Cmd + Q
48 | if (process.platform !== 'darwin') {
49 | app.quit();
50 | }
51 | });
52 |
53 | app.on('activate', () => {
54 | // On macOS it's common to re-create a window in the app when the
55 | // dock icon is clicked and there are no other windows open.
56 | if (BrowserWindow.getAllWindows().length === 0) createWindow();
57 | });
58 |
59 | // This method will be called when Electron has finished
60 | // initialization and is ready to create browser windows.
61 | // Some APIs can only be used after this event occurs.
62 | app.on('ready', async () => {
63 | if (isDevelopment && !process.env.IS_TEST) {
64 | // Install Vue Devtools
65 | try {
66 | await installExtension(VUEJS3_DEVTOOLS);
67 | } catch (e) {
68 | console.error('Vue Devtools failed to install:', e.toString());
69 | }
70 | }
71 | createWindow();
72 | });
73 |
74 | // Exit cleanly on request from parent process in development mode.
75 | if (isDevelopment) {
76 | if (process.platform === 'win32') {
77 | process.on('message', data => {
78 | if (data === 'graceful-exit') {
79 | app.quit();
80 | }
81 | });
82 | } else {
83 | process.on('SIGTERM', () => {
84 | app.quit();
85 | });
86 | }
87 | }
88 |
89 | app.on('window-all-closed', () => {
90 | if (process.platform !== 'darwin') {
91 | app.quit();
92 | }
93 | });
94 | ipcMain.on('window-close', function () {
95 | win.close();
96 | });
97 |
98 | ipcMain.on('window-min', function () {
99 | win.minimize();
100 | });
101 |
102 | ipcMain.on('window-max', function () {
103 | if (win.isMaximized()) {
104 | win.unmaximize();
105 | } else {
106 | win.maximize();
107 | }
108 | });
109 |
--------------------------------------------------------------------------------
/src/components/Header.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
10 |
13 |
16 |
17 |
18 |
19 |
37 |
98 |
--------------------------------------------------------------------------------
/src/components/IPAddress.vue:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
21 |
143 |
203 |
--------------------------------------------------------------------------------
/src/components/Side.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
10 |
14 |
18 |
19 |
20 |
29 |
30 |
70 |
--------------------------------------------------------------------------------
/src/config/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @description
3 | * @date 2022-01-12
4 | * @author tudou
5 | * @lastModify tudou 2022-01-12
6 | */
7 | const serialConfig = {
8 | baudRate: [115200, 57600, 38400, 19200, 9600, 4800, 2400, 1800], // 波特率
9 | parity: ['none', 'even', 'mark', 'odd', 'space'], // 校验位
10 | dataBits: [8, 7, 6, 5], // 数据位
11 | stopBits: [1, 2] // 停止位
12 | };
13 |
14 | export default serialConfig;
15 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue';
2 | import router from './router';
3 | import App from './App.vue';
4 | import ant, { message } from 'ant-design-vue';
5 | import 'ant-design-vue/dist/antd.less';
6 | // import 'ant-design-vue/dist/antd.css';
7 | import '@/assets/font/iconfont.css';
8 | const app = createApp(App);
9 | app.config.globalProperties.$message = message;
10 | app.use(ant);
11 | app.use(router);
12 | app.mount('#app');
13 |
--------------------------------------------------------------------------------
/src/router/index.js:
--------------------------------------------------------------------------------
1 | import { createRouter, createWebHashHistory } from 'vue-router';
2 | import Dashboard from '../views/Dashboard.vue';
3 | import Net from '../views/Net.vue';
4 | import Setting from '../views/Setting.vue';
5 |
6 | const routes = [
7 | {
8 | path: '/',
9 | name: 'Dashboard',
10 | component: Dashboard
11 | },
12 | {
13 | path: '/net',
14 | name: 'Net',
15 | component: Net
16 | },
17 | {
18 | path: '/setting',
19 | name: 'Setting',
20 | component: Setting
21 | }
22 | ];
23 |
24 | const router = createRouter({
25 | history: createWebHashHistory(),
26 | routes
27 | });
28 |
29 | export default router;
30 |
--------------------------------------------------------------------------------
/src/theme/cus-theme.less:
--------------------------------------------------------------------------------
1 | //自定义的样式+用到了variables里面的变量+ant的主题样式都可以用
2 | .ant-layout-header {
3 | background-color: @header-back-color;
4 |
5 | .header-item:hover {
6 | background-color: @header-item-hover-color;
7 | }
8 | }
9 | .nav_active {
10 | color: @primary-color !important;
11 | }
12 |
--------------------------------------------------------------------------------
/src/theme/js/theme.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const path = require('path');
3 |
4 | const { generateTheme } = require('antd-theme-generator');
5 | //生成的theme.less文件的位置
6 | const outputFilePath = path.join(__dirname, '../../../public/static/theme.less');
7 | //自定义样式
8 | const cusCssFilePath = path.join(__dirname, '../cus-theme.less');
9 |
10 | generateTheme({
11 | //node_modules中antd的路径
12 | antDir: path.join(__dirname, '../../../node_modules/ant-design-vue'),
13 | //styles对应的目录路径,需要和下面的variables.less在一个文件夹
14 | stylesDir: path.join(__dirname, './src'),
15 | //less变量的入口文件,variables.less里面定义的变量,必须在themeVariables里面定义
16 | varFile: path.join(__dirname, '../variables.less'),
17 | //您要动态更改的变量列表
18 | themeVariables: ['@primary-color', '@header-item-hover-color', '@header-back-color'],
19 | outputFilePath: outputFilePath,
20 | customColorRegexArray: [/^fade\(.*\)$/]
21 | })
22 | .then(() => {
23 | console.log('配置主题成功');
24 | //自定义样式与ant主题样式合并
25 | //读取提取过的ant样式
26 | const themeCss = fs.readFileSync(outputFilePath).toString();
27 | // //读取自定义的CSS
28 | const cusCss = fs.readFileSync(cusCssFilePath).toString();
29 | fs.writeFileSync(outputFilePath, themeCss + cusCss);
30 | //重新覆盖themeCss
31 | console.log(`🌈 主题覆盖成功. OutputFile: ${outputFilePath}`);
32 | })
33 | .catch(() => {
34 | console.log('配置主题失败');
35 | });
36 |
--------------------------------------------------------------------------------
/src/theme/variables.less:
--------------------------------------------------------------------------------
1 | //插件默认主题变量+这些变量必须在themejs里面定义好
2 | @primary-color: #1890ff; // 全局主色
3 | //自定义样式
4 | @header-item-hover-color: blue; //头部项浮动颜色
5 | @header-back-color: #1890ff; //头部底色
6 | @nav-bg: #f3f5f6;
7 | @nav-font-color: rgba(0, 0, 0, 0.85);
8 | @nav-hover-color: #fafafa;
9 | @border-color: #ddd;
10 | @center-bg: #ffffff;
11 | @ant-nav-header: #ffffff;
12 |
--------------------------------------------------------------------------------
/src/views/Dashboard.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
串口号
8 |
9 | {{ item.path }}
10 |
11 |
12 |
13 |
波特率
14 |
15 | {{ item }}
16 |
17 |
18 |
19 |
校验位
20 |
21 | {{ item }}
22 |
23 |
24 |
25 |
26 |
数据位
27 |
28 | {{ item }}bit
29 |
30 |
31 |
32 |
停止位
33 |
34 | {{ item }}bit
35 |
36 |
37 |
41 |
42 |
48 |
49 |
50 |
51 |
52 |
55 |
{{ item.chat === 'roboto' ? '收' : '发' }}→{{ item.content }}
56 |
57 |
58 |
59 |
60 |
61 |
79 |
80 |
81 |
251 |
420 |
--------------------------------------------------------------------------------
/src/views/Net.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
协议
7 |
8 | {{ item.content }}
9 |
10 |
11 |
12 | IP地址
13 |
14 |
15 |
16 |
20 |
24 |
30 |
31 |
40 |
41 |
42 |
43 |
44 |
{{ item.chat === 'roboto' ? '收' : '发' }}→{{ item.content }}
45 |
46 |
47 |
48 |
49 |
连接的客户端
50 |
51 | {{ item.content }}
52 |
53 |
54 |
55 |
56 | 目标主机
57 |
58 |
59 |
63 |
64 |
71 |
72 |
73 |
74 |
75 |
358 |
552 |
--------------------------------------------------------------------------------
/src/views/Setting.vue:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
35 |
67 |
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | pluginOptions: {
3 | electronBuilder: {
4 | nodeIntegration: true,
5 | externals: ['serialport'],
6 | builderOptions: {
7 | productName: '串口调试助手',
8 | win: {
9 | icon: 'public/icon.ico',
10 | artifactName: '${productName}-${version}.${ext}',
11 | target: [
12 | {
13 | target: 'nsis',
14 | arch: ['x64']
15 | }
16 | ]
17 | },
18 | dmg: {
19 | contents: [
20 | {
21 | x: 410,
22 | y: 150,
23 | type: 'link',
24 | path: '/Applications'
25 | },
26 | {
27 | x: 130,
28 | y: 150,
29 | type: 'file'
30 | }
31 | ]
32 | },
33 | linux: {
34 | icon: 'build/electron-icon/icon.png',
35 | target: 'AppImage'
36 | },
37 | mac: {
38 | icon: 'build/electron-icon/icon.icns'
39 | },
40 | nsis: {
41 | oneClick: false,
42 | allowElevation: true,
43 | allowToChangeInstallationDirectory: true,
44 | installerIcon: 'public/icon.ico',
45 | uninstallerIcon: 'public/icon.ico',
46 | installerHeaderIcon: 'public/icon.ico',
47 | createDesktopShortcut: true,
48 | createStartMenuShortcut: true
49 | }
50 | }
51 | }
52 | }
53 | };
54 |
--------------------------------------------------------------------------------