feat: 新增书籍导入和列表接口,完善数据库初始化
1. 新增encoding_rs、regex、chardetng依赖用于文本编码处理 2. 重构数据库初始化逻辑,适配tauri应用数据目录 3. 新增ApiResponse统一返回格式和书籍、章节数据模型 4. 重写import_book和book_list命令实现基础导入和列表功能
This commit is contained in:
parent
5c1be1cdb0
commit
efae900fcf
|
|
@ -488,6 +488,17 @@ dependencies = [
|
||||||
"rand_core",
|
"rand_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chardetng"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "13de944a44b5064ee5d3a5ceccc49a41bfec50f2580e66f82e87703acdb88b53"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"encoding_rs",
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chrono"
|
name = "chrono"
|
||||||
version = "0.4.45"
|
version = "0.4.45"
|
||||||
|
|
@ -1024,6 +1035,15 @@ version = "1.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7"
|
checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "encoding_rs"
|
||||||
|
version = "0.8.35"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "endi"
|
name = "endi"
|
||||||
version = "1.1.1"
|
version = "1.1.1"
|
||||||
|
|
@ -3829,7 +3849,10 @@ checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
|
||||||
name = "stealthreader"
|
name = "stealthreader"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"chardetng",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
"encoding_rs",
|
||||||
|
"regex",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sqlx",
|
"sqlx",
|
||||||
|
|
|
||||||
|
|
@ -36,3 +36,6 @@ sqlx = { version = "0.9.0", features = [
|
||||||
] }
|
] }
|
||||||
chrono = "0.4.45"
|
chrono = "0.4.45"
|
||||||
tauri-plugin-dialog = "2.7.2"
|
tauri-plugin-dialog = "2.7.2"
|
||||||
|
encoding_rs = "0.8.35"
|
||||||
|
regex = "1.13.1"
|
||||||
|
chardetng = "1.0.0"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,25 @@
|
||||||
use tauri_helper::auto_collect_command;
|
use tauri_helper::auto_collect_command;
|
||||||
|
|
||||||
|
use crate::models::ApiResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导入书籍
|
||||||
|
* @param path 书籍文件路径
|
||||||
|
* @returns 导入结果
|
||||||
|
*/
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
#[auto_collect_command]
|
#[auto_collect_command]
|
||||||
pub async fn import_book() -> Result<(), String> {
|
pub async fn import_book(path: String) -> Result<ApiResponse<()>, String> {
|
||||||
Ok(())
|
let content = std::fs::read_to_string(&path).map_err(|e| e.to_string());
|
||||||
}
|
Ok(ApiResponse::success(()))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取书籍列表
|
||||||
|
* @returns 书籍列表
|
||||||
|
*/
|
||||||
|
#[tauri::command]
|
||||||
|
#[auto_collect_command]
|
||||||
|
pub async fn book_list() -> Result<ApiResponse<Vec<()>>, String> {
|
||||||
|
Ok(ApiResponse::success(Vec::new()))
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ pub fn run() {
|
||||||
.plugin(tauri_plugin_dialog::init())
|
.plugin(tauri_plugin_dialog::init())
|
||||||
.setup(|app| {
|
.setup(|app| {
|
||||||
let pool = tauri::async_runtime::block_on(async {
|
let pool = tauri::async_runtime::block_on(async {
|
||||||
init_pool().await.expect("sqlite数据库连接池初始化失败!")
|
init_pool(app.handle()).await.expect("sqlite数据库连接池初始化失败!")
|
||||||
});
|
});
|
||||||
app.manage(pool);
|
app.manage(pool);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
|
|
@ -45,3 +45,36 @@ impl<T> ApiResponse<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
pub struct BookInfo {
|
||||||
|
pub id: i64,
|
||||||
|
pub title: String,
|
||||||
|
pub author: String,
|
||||||
|
pub cover: String,
|
||||||
|
pub total_chapters: i32,
|
||||||
|
pub total_chars: i32,
|
||||||
|
pub introduction: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct Chapter {
|
||||||
|
pub id: i64,
|
||||||
|
pub number: i32,
|
||||||
|
pub title: String,
|
||||||
|
pub content: String,
|
||||||
|
pub char_count: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct Book {
|
||||||
|
pub id: Option<i64>,
|
||||||
|
pub title: String,
|
||||||
|
pub author: String,
|
||||||
|
pub cover: String,
|
||||||
|
pub introduction: String,
|
||||||
|
pub file_path: String,
|
||||||
|
pub total_chapters: i32,
|
||||||
|
pub total_chars: i32,
|
||||||
|
pub chapters: Vec<Chapter>,
|
||||||
|
}
|
||||||
|
|
@ -1,10 +1,50 @@
|
||||||
use sqlx::pool::PoolOptions;
|
use sqlx::sqlite::{SqlitePool, SqlitePoolOptions};
|
||||||
use sqlx::sqlite::{SqliteConnectOptions, SqlitePool, SqlitePoolOptions};
|
use tauri::{AppHandle, Manager};
|
||||||
|
|
||||||
pub async fn init_pool() -> Result<SqlitePool, sqlx::Error> {
|
pub async fn init_pool(app: &AppHandle) -> Result<SqlitePool, sqlx::Error> {
|
||||||
SqlitePoolOptions::new()
|
// 数据库文件路径
|
||||||
|
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 db_url = format!("sqlite:{}", db_path.to_str().unwrap());
|
||||||
|
// 初始化数据库连接池
|
||||||
|
let pool = SqlitePoolOptions::new()
|
||||||
.max_connections(5)
|
.max_connections(5)
|
||||||
.min_connections(1)
|
.min_connections(1)
|
||||||
.connect("sqlite::memory:")
|
.connect(&db_url)
|
||||||
.await
|
.await?;
|
||||||
|
sqlx::query(
|
||||||
|
"
|
||||||
|
CREATE TABLE IF NOT EXISTS books (
|
||||||
|
id INTEGER,
|
||||||
|
title TEXT DEFAULT '',
|
||||||
|
author TEXT DEFAULT '',
|
||||||
|
cover TEXT DEFAULT '',
|
||||||
|
file_path TEXT DEFAULT '',
|
||||||
|
total_chapters INTEGER DEFAULT 0,
|
||||||
|
total_chars INTEGER DEFAULT 0,
|
||||||
|
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
last_read_chapter_id INTEGER DEFAULT 0,
|
||||||
|
last_read_position INTEGER DEFAULT 0,
|
||||||
|
last_read_time TIMESTAMP,
|
||||||
|
PRIMARY KEY (id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS chapters (
|
||||||
|
id INTEGER,
|
||||||
|
book_id INTEGER NOT NULL,
|
||||||
|
chapter_number INTEGER NOT NULL,
|
||||||
|
title TEXT NOT NULL DEFAULT '',
|
||||||
|
content TEXT NOT NULL,
|
||||||
|
total_chars INTEGER DEFAULT 0,
|
||||||
|
FOREIGN KEY (book_id) REFERENCES books ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_chapters_book
|
||||||
|
ON chapters(book_id, chapter_number);
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.execute(&pool)
|
||||||
|
.await?;
|
||||||
|
Ok(pool)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue