From dd7504aae7718f56dfa21a2a2fcc93fa07194714 Mon Sep 17 00:00:00 2001 From: sparksfly Date: Sun, 23 Aug 2026 23:32:46 +0800 Subject: [PATCH] =?UTF-8?q?feat(book):=20=E6=B7=BB=E5=8A=A0=E7=AB=A0?= =?UTF-8?q?=E8=8A=82=E6=A0=87=E9=A2=98=E6=A8=A1=E7=B3=8A=E6=90=9C=E7=B4=A2?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 后端接口新增keyword参数支持章节标题模糊查询 2. 前端书籍详情页添加章节搜索输入框,调用更新后的接口 3. 调整章节头部布局适配搜索框 --- src-tauri/src/commands/book.rs | 7 +++++-- src/api/book.ts | 5 +++-- src/views/BookDetail.vue | 33 +++++++++++++++++++++++++++++---- 3 files changed, 37 insertions(+), 8 deletions(-) diff --git a/src-tauri/src/commands/book.rs b/src-tauri/src/commands/book.rs index cfb5add..2a84100 100644 --- a/src-tauri/src/commands/book.rs +++ b/src-tauri/src/commands/book.rs @@ -155,19 +155,22 @@ pub async fn book_detail( pub async fn chapter_page( pool: State<'_, SqlitePool>, book_id: i64, + keyword: String, page: i32, limit: i32, ) -> Result>, String> { let offset = (page - 1) * limit; let total: i64 = - sqlx::query_scalar::<_, i64>("SELECT COUNT(id) FROM chapters WHERE book_id = ?") + sqlx::query_scalar::<_, i64>("SELECT COUNT(id) FROM chapters WHERE book_id = ? AND title LIKE ?") .bind(book_id) + .bind(format!("%{}%", keyword)) .fetch_one(&*pool) .await .map_err(|e| e.to_string())?; let chapters = - sqlx::query_as::<_, Chapters>("SELECT * FROM chapters WHERE book_id = ? LIMIT ?,?") + sqlx::query_as::<_, Chapters>("SELECT * FROM chapters WHERE book_id = ? AND title LIKE ? LIMIT ?,?") .bind(book_id) + .bind(format!("%{}%", keyword)) .bind(offset) .bind(limit) .fetch_all(&*pool) diff --git a/src/api/book.ts b/src/api/book.ts index 6dd4f07..7d0d9c6 100644 --- a/src/api/book.ts +++ b/src/api/book.ts @@ -45,12 +45,13 @@ const BookApi = { /** * 获取书籍章节列表 * @param bookId 书籍ID + * @param keyword 章节标题模糊查询 * @param page 页码 * @param limit 每页数量 * @returns 书籍章节列表 */ - chapters: async (bookId: number, page: number, limit: number) => { - return await invoke>>("chapter_page", { bookId, page, limit }) + chapters: async (bookId: number, keyword: string, page: number, limit: number) => { + return await invoke>>("chapter_page", { bookId, keyword, page, limit }) }, /** * 获取章节详情 diff --git a/src/views/BookDetail.vue b/src/views/BookDetail.vue index 4f189ff..48bae06 100644 --- a/src/views/BookDetail.vue +++ b/src/views/BookDetail.vue @@ -53,8 +53,18 @@
- 章节列表 - 共 {{ total }} 章 +
+ 章节列表 + 共 {{ total }} 章 +
+
@@ -122,6 +132,7 @@ const total = ref(0) const page = ref(1) const limit = ref(50) const loadingChapters = ref(false) +const keyword = ref("") const goBack = () => router.back() @@ -163,7 +174,7 @@ const loadChapters = async () => { loadingChapters.value = true try { const res = await withLoading( - () => BookApi.chapters(bookId.value, page.value, limit.value), + () => BookApi.chapters(bookId.value, keyword.value, page.value, limit.value), "加载章节中..." ) if (res.code === 0) { @@ -304,11 +315,24 @@ onMounted(() => { .chapter-header { flex-shrink: 0; display: flex; - align-items: baseline; + align-items: center; justify-content: space-between; + gap: 12px; margin-bottom: 8px; } +.chapter-header-left { + display: flex; + align-items: baseline; + gap: 8px; + min-width: 0; +} + +.chapter-search { + width: 220px; + flex-shrink: 0; +} + .chapter-name { font-size: 15px; font-weight: 600; @@ -337,6 +361,7 @@ onMounted(() => { display: flex; align-items: center; gap: 10px; + box-sizing: border-box; width: 100%; padding: 8px 10px; border-radius: var(--radius-sm);