feat: 新增设置页面及外观设置功能

添加了设置页面路由、外观设置子页面,支持主题模式切换和自定义窗口背景图片,新增相关 Rust 后端模块、数据库初始化、多语言文案及配置项,更新 Tauri 配置和项目描述。
This commit is contained in:
Yuhang Wu
2026-10-13 11:15:58 +08:00
parent d4257481f4
commit fd47adea1e
24 changed files with 6673 additions and 38 deletions
+2
View File
@@ -0,0 +1,2 @@
pub mod tunnel;
pub mod server;
+11
View File
@@ -0,0 +1,11 @@
use sqlx::SqlitePool;
use tauri::State;
use tauri_helper::auto_collect_command;
use crate::models::{ApiResponse};
#[tauri::command]
#[auto_collect_command]
pub async fn get_server_list(state: State<'_, SqlitePool>) -> Result<ApiResponse<()>, String> {
Ok(ApiResponse::success_empty())
}
View File
+25 -6
View File
@@ -1,14 +1,33 @@
// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
#[tauri::command]
fn greet(name: &str) -> String {
format!("Hello, {}! You've been greeted from Rust!", name)
}
mod commands;
mod models;
mod services;
use tauri::Manager;
use crate::commands::server::get_server_list;
use crate::services::db::init_pool;
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_opener::init())
.invoke_handler(tauri::generate_handler![greet])
.plugin(tauri_plugin_dialog::init()) // 对话框插件
.plugin(tauri_plugin_updater::Builder::new().build()) // 更新插件
.plugin(tauri_plugin_process::init()) // 进程插件(更新后重启)
.plugin(tauri_plugin_prevent_default::Builder::new().build())
.setup(|app| {
let pool = tauri::async_runtime::block_on(async {
init_pool(app.handle())
.await
.expect("sqlite数据库连接池初始化失败!")
});
app.manage(pool);
Ok(())
})
.plugin(tauri_plugin_store::Builder::default().build())
// .invoke_handler(tauri::generate_handler![greet])
.invoke_handler(tauri_helper::tauri_collect_commands!())
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
+50
View File
@@ -0,0 +1,50 @@
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
pub struct PageResult<T> {
pub total: i64,
pub list: Vec<T>,
pub page: i32,
pub page_size: i32,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct ApiResponse<T> {
success: bool,
code: i32,
msg: String,
data: Option<T>,
}
impl<T> ApiResponse<T> {
// 成功响应
pub fn success(data: T) -> Self {
Self {
success: true,
code: 0,
msg: "操作成功".to_string(),
data: Some(data),
}
}
// 错误响应
pub fn error(code: i32, message: &str) -> Self {
Self {
success: false,
code,
msg: message.to_string(),
data: None,
}
}
}
impl ApiResponse<()> {
// 成功响应,数据为空
pub fn success_empty() -> Self {
Self {
success: true,
code: 0,
msg: "操作成功".to_string(),
data: None,
}
}
}
+20
View File
@@ -0,0 +1,20 @@
use sqlx::sqlite::{SqliteConnectOptions, SqlitePool, SqlitePoolOptions};
use tauri::{AppHandle, Manager};
pub async fn init_pool(app: &AppHandle) -> Result<SqlitePool, sqlx::Error> {
// 数据库文件路径
let app_dir = app.path().app_data_dir().expect("无法获取APP数据目录");
std::fs::create_dir_all(&app_dir).unwrap();
let db_path = app_dir.join("reader.db");
// 初始化数据库连接池
let options = SqliteConnectOptions::new()
.filename(&db_path)
.create_if_missing(true);
let pool = SqlitePoolOptions::new()
.max_connections(5)
.min_connections(1)
.connect_with(options)
.await?;
Ok(pool)
}
+1
View File
@@ -0,0 +1 @@
pub mod db;