🎉使用Tauri+vite+koa2+mysql开发了一款待办效率应用

本文涉及的产品
Serverless 应用引擎 SAE,800核*时 1600GiB*时
性能测试 PTS,5000VUM额度
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
简介: 这是一个基于tauri+vite的应用,它采用了一些最新的前端技术,包括 Tauri、Vue3、Vite5、koa2 和 mysql。它提供了丰富的效率管理工具。

🎉使用Tauri+vite+koa2+mysql开发了一款待办效率应用


## 📝项目概述


这是一个基于tauri+vite的应用,它采用了一些最新的前端技术,包括 Tauri、Vue3、Vite5、koa2 和 mysql。它提供了丰富的效率管理工具。


应用地址:https://kestrel-task.cn


喜欢的可以试试哦,🙏🙏🙏


## 🏆项目预览


![](https://files.mdnice.com/user/1378/751284ec-d4ab-4f7d-be24-9ef68fcd6c7e.png)


![](https://files.mdnice.com/user/1378/865aa7fe-8bc8-4a80-8456-71621e6349fb.png)


![](https://files.mdnice.com/user/1378/1d5ee010-6b62-4194-8697-fe10da4b9aa3.png)


![](https://files.mdnice.com/user/1378/429f947d-afe6-48e4-8f2e-77aaf80fb0f4.png)


![](https://files.mdnice.com/user/1378/377a053c-43e0-4d08-b8a3-308bade71ab4.png)


![](https://files.mdnice.com/user/1378/dfdd94ed-6ecc-4806-8c78-eb998bb15e03.png)


![](https://files.mdnice.com/user/1378/20b13b32-ff27-48db-9c9c-5ff4ee4525be.png)


![](https://files.mdnice.com/user/1378/bb8bc480-6cca-41dc-9782-4cc49d722f14.png)


![](https://files.mdnice.com/user/1378/7817598e-7213-4b2c-91ef-51c01079e218.png)


## 💻技术栈

- **Tauri**: Tauri是一个用于构建现代桌面应用程序的工具,结合了Rust、Vue.js和Web技术,提供了强大的跨平台能力。

- **Vue3**: Vue3是流行的JavaScript框架Vue.js的最新版本,具有更好的性能、更好的TypeScript支持和更多的特性。

- **Vite5**: Vite是一个现代化的构建工具,Vite5是其最新版本,具有快速的冷启动、热模块替换和原生ES模块支持。

- **Koa2**: Koa2是一个基于Node.js的轻量级Web框架,使用异步函数处理中间件,提供了简洁而强大的Web开发体验。

- **MySQL**: MySQL是一个流行的关系型数据库管理系统,具有高性能、可靠性和广泛的应用领域,适用于各种规模的应用程序。


主要包括的功能点实现


## 🔔图标生成

在项目根目录,放上图片为 app-icon.png的图片

然后执行。就能看到图标已经生成了。

```json

npm run tauri icon

```


## 📢配置应用系统托盘

### 新建tray.rs,编写托盘事件。内容如下。

```rust

use tauri::{

   AppHandle, CustomMenuItem, SystemTray, SystemTrayEvent, SystemTrayMenu, SystemTrayMenuItem

};

use tauri::Manager;


// 托盘菜单

pub fn menu() -> SystemTray {

   let quit = CustomMenuItem::new("quit".to_string(), "退出");

   let show = CustomMenuItem::new("show".to_string(), "显示");

   let hide = CustomMenuItem::new("hide".to_string(), "隐藏");

   let tray_menu = SystemTrayMenu::new()

       .add_native_item(SystemTrayMenuItem::Separator)

       .add_item(hide)

       .add_item(show)

       .add_native_item(SystemTrayMenuItem::Separator)

       .add_item(quit);


   SystemTray::new().with_menu(tray_menu)

}


// 托盘事件

pub fn handler(app: &AppHandle, event: SystemTrayEvent) {

   let window = app.get_window("main").unwrap();

   match event {

       SystemTrayEvent::MenuItemClick { id, .. } => match id.as_str() {

           "quit" => {

               std::process::exit(0);

           }

           "show" => {

               window.show().unwrap();

           }

           "hide" => {

               window.hide().unwrap();

           }

           _ => {}

       },

       _ => {}

   }

}


```


### 在main.rs中使用

```rust

use std::{thread,time};

mod tray;


fn main() {

   let context = tauri::generate_context!();

   tauri::Builder::default()

       // .menu(tauri::Menu::os_default(&context.package_info().name)) //配置界面菜单

       .system_tray(tray::menu()) // ✅ 将 `tauri.conf.json` 上配置的图标添加到系统托盘

       .on_system_tray_event(tray::handler) // ✅ 注册系统托盘事件处理程序

       .invoke_handler(tauri::generate_handler![my_custom_command, init_process,close_splashscreen])

       .run(context)

       .expect("error while running tauri application");

}

```



## 🎛️ 接口封装请求

Tauri 是一个框架,它允许开发者使用 Rust 语言来构建轻量级的桌面应用程序,Tauri 提供了一套 API,其中包括了用于处理 HTTP 请求的 http 模块。

tauri.conf.json 文件中进行配置:

```json

{

 "tauri": {

   "allowlist": {

     "http": {

       "all": true,

       "request": true,

       "scope":[

         "http://**",

         "https://**"

       ]

     }

   }

 }

}

```

## 🎵基于API的封装

```js

// http.js


import { fetch, ResponseType, Body } from '@tauri-apps/api/http'


// https://tauri.app/zh-cn/v1/api/js/http#fetch

export const http = (opts = {}) => {

 return new Promise((resolve, reject) => {

   const { url, method, query, data, headers, callback } = opts

   fetch(url, {

     method: method || 'GET',

     headers: {

       'content-type': 'application/json',

       ...headers,

     },

     responseType: ResponseType.JSON,

     timeout: 60000,

     query: query,

     body: Body.json({

       ...data,

     }),

   })

   .then((res) => {

     callback && callback(res)

     resolve(res)

   })

   .catch((e) => {

     reject(e)

   })

 })

}

```


## 😄获取版本号

这个函数通常用于获取应用程序的版本信息

```js

import { getVersion } from '@tauri-apps/api/app'

```

```js

onMounted(async () => {

 appVersion.value = await getVersion()

 getNewVersions()

})

```


## 🙂检查版本更新

这段代码的作用是导入 Tauri 中的更新模块 @tauri-apps/api/updater 中的 checkUpdate 和 installUpdate 函数。checkUpdate 用于检查是否有可用的应用程序更新,而 installUpdate 用于安装应用程序更新。


![](https://files.mdnice.com/user/1378/129e7a70-4520-4219-8629-81f934da8165.png)



```js

import { checkUpdate, installUpdate } from '@tauri-apps/api/updater'

```

```js

 checkUpdate().then(async (res) => {

   const { shouldUpdate, manifest } = res

   if (shouldUpdate) {

     confirm(`发现新版本:${manifest?.version},是否升级?`, { title: '版本更新', type: 'success' }).then(async (res) => {

       try {

         ElMessage.success({

           message: '正在下载更新...',

           duration: 3000,

         })

         installUpdate()

           .then(async (res) => {

             await relaunch()

           })

           .catch((e) => {

           })

       } catch (e) {

         ElMessage.error({

           message: '下载更新失败',

           description: e.toString() || '',

         })

       }

     })

   } else {

    await confirm(`当前版本,已经是最新版本`, { title: '检查更新', type: 'success' ,okLabel: '确定',cancelLabel: '取消'})

   }

 })

```

## 🙃窗口操作

窗口禁用最大化和最小化功能

```json

import { appWindow } from '@tauri-apps/api/window';

```

## 🥰禁用最大化和取消禁用


![](https://files.mdnice.com/user/1378/3383c156-d04b-41af-a4d4-fcf4fda9cfa2.png)


```js

appWindow.setMaximizable(true) //禁用

appWindow.setMaximizable(false) //取消禁用

```

```js

appWindow.setMinimized(true) //禁用

appWindow.setMinimized(false) //取消禁用

```

## 🥰消息提示

### Ask弹窗


![](https://files.mdnice.com/user/1378/a28ccf9c-bee8-4700-aff1-a5f2f3a346aa.png)


![](https://files.mdnice.com/user/1378/0abc8f2b-0afe-4e94-b30b-261a345621cd.png)



![](https://files.mdnice.com/user/1378/0abc8f2b-0afe-4e94-b30b-261a345621cd.png)


```js

import { ask } from '@tauri-apps/api/dialog';

const yes = await ask('确定更新该版本?', '发现新版本');

const yes2 = await ask('确定更新该版本?', { title: '发现新版本', type: 'warning' });

```

如果想要修改按钮的文本,可以使用,okLabel: '确定',cancelLabel: '取消'。


## 😊confirm弹窗


![](https://files.mdnice.com/user/1378/e40ca1d1-1524-4acf-9a47-01d8eaa93607.png)


![](https://files.mdnice.com/user/1378/1e55b937-0f50-4f73-9434-85dcc083450b.png)


```json

import { confirm } from '@tauri-apps/api/dialog';

const confirmed = await confirm('确定更新该版本?', '发现新版本');

const confirmed2 = await confirm('确定更新该版本?', { title: '发现新版本', type: 'warning',okLabel: '确定',cancelLabel: '取消' });

```


## 😝message提示框


![](https://files.mdnice.com/user/1378/fb895d27-9c31-4d02-ae42-13b45e3c4042.png)


![](https://files.mdnice.com/user/1378/b31d92fe-11ba-4971-b6eb-affca3ed7572.png)



```js

import { message } from '@tauri-apps/api/dialog';

await message('确定更新该版本', '发现新版本');

await message('确定更新该版本', { title: '发现新版本', type: 'error',okLabel: '确定',cancelLabel: '取消' });

```


## 🤗open 选择文件弹窗


![](https://files.mdnice.com/user/1378/3a394be3-4732-4664-90ba-3a71285a60cd.png)


```js

import { open } from '@tauri-apps/api/dialog';

// Open a selection dialog for image files

const selected = await open({

 multiple: true,

 filters: [{

   name: 'Image',

   extensions: ['png', 'jpeg']

 }]

});

if (Array.isArray(selected)) {

 // user selected multiple files

} else if (selected === null) {

 // user cancelled the selection

} else {

 // user selected a single file

}

```


## 😐save文件保存弹窗


![](https://files.mdnice.com/user/1378/a64b89b9-5b8c-475e-9531-ac4a9236520f.png)


```js

import { save } from '@tauri-apps/api/dialog';

const filePath = await save({

 filters: [{

   name: 'Image',

   extensions: ['png', 'jpeg']

 }]

});


```

## 😁splashscreen页设置

为什么要设置这个呢,因为`splashscreen` 页面通常用于在应用程序启动时显示一个启动画面或加载动画,以提供用户友好的界面体验。这个页面可以包含应用程序的标志、名称或其他相关信息,帮助用户确认应用程序正在加载。一旦应用程序加载完成,通常会自动关闭 `splashscreen` 页面并显示应用程序的主界面。


#### 🫠tauri.conf.json配置

```json

   "windows": [

     {

       "fullscreen": false,

       "resizable": true,

       "title": "微芒计划",

       "width": 1100,

       "height": 680,

       "minHeight": 600,

       "minWidth": 900,

       "visible": false

     },

     {

       "width": 800,

       "height": 500,

       "minHeight": 500,

       "minWidth": 800,

       "decorations": false,

       "url": "splashscreen.html",

       "label": "splashscreen",

       "resizable": true,

       "fullscreen": false

     }

   ]

```

splashscreen.html要放到public下面,为一个html文件,里面可以写开屏的图片动画或者界面。


### 🙂main.rs编写关闭splashscreen 页面的功能

```rust

// Create the command:

// This command must be async so that it doesn't run on the main thread.

#[tauri::command]

async fn close_splashscreen(window: Window) {

 // Close splashscreen

 window.get_window("splashscreen").expect("no window labeled 'splashscreen' found").close().unwrap();

 // Show main window

 window.get_window("main").expect("no window labeled 'main' found").show().unwrap();

}

```


### 🙃main入口提供给前端使用

```rust

fn main() {

   let context = tauri::generate_context!();

   tauri::Builder::default()

       // .menu(tauri::Menu::os_default(&context.package_info().name)) //配置界面菜单

       .system_tray(tray::menu()) // ✅ 将 `tauri.conf.json` 上配置的图标添加到系统托盘

       .on_system_tray_event(tray::handler) // ✅ 注册系统托盘事件处理程序

       .invoke_handler(tauri::generate_handler![my_custom_command, init_process,close_splashscreen])

       .run(context)

       .expect("error while running tauri application");

}

```


### 🙃在前端调用splashscreen页面

界面加载完成后,关掉

```rust

import { onMounted } from 'vue'

import { invoke } from '@tauri-apps/api/tauri'

onMounted(() => {

 // window.addEventListener('contextmenu', (e) => e.preventDefault(), false)

 document.addEventListener('DOMContentLoaded', () => {

   // This will wait for the window to load, but you could

   // run this function on whatever trigger you want

   setTimeout(() => {

     invoke('close_splashscreen')

   }, 1000)

 })

})

```


🎉结语

感兴趣的可以试试,有不清楚的问题,关于tauri开发方面的问题,也可以一起交流。欢迎加我:zhan_1337608148。一起成长,一起进步。















相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
27天前
|
canal 消息中间件 关系型数据库
Canal作为一款高效、可靠的数据同步工具,凭借其基于MySQL binlog的增量同步机制,在数据同步领域展现了强大的应用价值
【9月更文挑战第1天】Canal作为一款高效、可靠的数据同步工具,凭借其基于MySQL binlog的增量同步机制,在数据同步领域展现了强大的应用价值
179 4
|
1月前
|
SQL 关系型数据库 MySQL
【MySQL】根据binlog日志获取回滚sql的一个开发思路
【MySQL】根据binlog日志获取回滚sql的一个开发思路
|
3天前
|
数据采集 关系型数据库 MySQL
MySQL表约束的种类与应用
在设计数据库时,合理应用各种约束对于创建一个结构化良好且能够有效维护数据完整性的数据库至关重要。每种约束类型都有其特定的应用场景,理解并正确应用这些约束,可以大大提高数据库应用的稳定性和性能。
16 3
|
1月前
|
安全 关系型数据库 MySQL
MySQL:TABLE_SCHEMA及其应用
MySQL:TABLE_SCHEMA及其应用
53 1
|
1月前
|
存储 SQL 运维
运维开发.MySQL.范式与反范式化
运维开发.MySQL.范式与反范式化
41 1
|
28天前
|
SQL 关系型数据库 MySQL
SQL Server、MySQL、PostgreSQL:主流数据库SQL语法异同比较——深入探讨数据类型、分页查询、表创建与数据插入、函数和索引等关键语法差异,为跨数据库开发提供实用指导
【8月更文挑战第31天】SQL Server、MySQL和PostgreSQL是当今最流行的关系型数据库管理系统,均使用SQL作为查询语言,但在语法和功能实现上存在差异。本文将比较它们在数据类型、分页查询、创建和插入数据以及函数和索引等方面的异同,帮助开发者更好地理解和使用这些数据库。尽管它们共用SQL语言,但每个系统都有独特的语法规则,了解这些差异有助于提升开发效率和项目成功率。
110 0
|
2月前
|
SQL 存储 关系型数据库
(五)MySQL索引应用篇:建立索引的正确姿势与使用索引的最佳指南!
在本篇中,则重点讲解索引应用相关的方式方法,例如各索引优劣分析、建立索引的原则、使用索引的指南以及索引失效与索引优化等内容。
290 0
|
2月前
|
存储 关系型数据库 MySQL
MySQL数据库开发进阶:精通数据库表的创建与管理22
【7月更文挑战第22天】数据库的创建与删除,数据表的创建与管理
41 1
|
1月前
|
SQL 数据可视化 关系型数据库
平时MySQL开发时,经常用到的小技巧
MySQL开发过程中常用的一些技巧,包括使用MD5函数、创建带逻辑删除标识和时间戳的表、多行合并为一行、时间差计算、不走索引的查询优化、多表连接更新等操作的SQL语句示例。
53 0
|
2月前
|
数据库
基于PHP+MYSQL开发制作的趣味测试网站源码
基于PHP+MYSQL开发制作的趣味测试网站源码。可在后台提前设置好缘分, 自己手动在数据库里修改数据,数据库里有就会优先查询数据库的信息, 没设置的话第一次查询缘分都是非常好的 95-99,第二次查就比较差 , 所以如果要你女朋友查询你的名字觉得很好 那就得是她第一反应是查和你的缘分, 如果查的是别人,那不好意思,第二个可能是你。
51 3

推荐镜像

更多