import BookmarkModel from "db/models/BookmarkModel.js" import CommonError from "utils/error/CommonError.js" class BookmarkService { // 获取用户的所有书签 async getUserBookmarks(userId) { try { if (!userId) { throw new CommonError("用户ID不能为空") } return await BookmarkModel.findAllByUser(userId) } catch (error) { if (error instanceof CommonError) throw error throw new CommonError(`获取用户书签失败: ${error.message}`) } } // 根据ID获取书签 async getBookmarkById(id) { try { if (!id) { throw new CommonError("书签ID不能为空") } const bookmark = await BookmarkModel.findById(id) if (!bookmark) { throw new CommonError("书签不存在") } return bookmark } catch (error) { if (error instanceof CommonError) throw error throw new CommonError(`获取书签失败: ${error.message}`) } } // 创建书签 async createBookmark(data) { try { if (!data.user_id || !data.url) { throw new CommonError("用户ID和URL为必填字段") } // 验证URL格式 if (!this.isValidUrl(data.url)) { throw new CommonError("URL格式不正确") } return await BookmarkModel.create(data) } catch (error) { if (error instanceof CommonError) throw error throw new CommonError(`创建书签失败: ${error.message}`) } } // 更新书签 async updateBookmark(id, data) { try { if (!id) { throw new CommonError("书签ID不能为空") } const bookmark = await BookmarkModel.findById(id) if (!bookmark) { throw new CommonError("书签不存在") } // 如果更新URL,验证格式 if (data.url && !this.isValidUrl(data.url)) { throw new CommonError("URL格式不正确") } return await BookmarkModel.update(id, data) } catch (error) { if (error instanceof CommonError) throw error throw new CommonError(`更新书签失败: ${error.message}`) } } // 删除书签 async deleteBookmark(id) { try { if (!id) { throw new CommonError("书签ID不能为空") } const bookmark = await BookmarkModel.findById(id) if (!bookmark) { throw new CommonError("书签不存在") } return await BookmarkModel.delete(id) } catch (error) { if (error instanceof CommonError) throw error throw new CommonError(`删除书签失败: ${error.message}`) } } // 根据用户和URL查找书签 async findBookmarkByUserAndUrl(userId, url) { try { if (!userId || !url) { throw new CommonError("用户ID和URL不能为空") } return await BookmarkModel.findByUserAndUrl(userId, url) } catch (error) { if (error instanceof CommonError) throw error throw new CommonError(`查找书签失败: ${error.message}`) } } // 检查书签是否存在 async isBookmarkExists(userId, url) { try { if (!userId || !url) { return false } const bookmark = await BookmarkModel.findByUserAndUrl(userId, url) return !!bookmark } catch (error) { return false } } // 批量创建书签 async createBookmarks(userId, bookmarksData) { try { if (!userId || !Array.isArray(bookmarksData) || bookmarksData.length === 0) { throw new CommonError("用户ID和书签数据不能为空") } const results = [] const errors = [] for (const bookmarkData of bookmarksData) { try { const bookmark = await this.createBookmark({ ...bookmarkData, user_id: userId }) results.push(bookmark) } catch (error) { errors.push({ url: bookmarkData.url, error: error.message }) } } return { success: results, errors, total: bookmarksData.length, successCount: results.length, errorCount: errors.length } } catch (error) { if (error instanceof CommonError) throw error throw new CommonError(`批量创建书签失败: ${error.message}`) } } // 批量删除书签 async deleteBookmarks(userId, bookmarkIds) { try { if (!userId || !Array.isArray(bookmarkIds) || bookmarkIds.length === 0) { throw new CommonError("用户ID和书签ID列表不能为空") } const results = [] const errors = [] for (const id of bookmarkIds) { try { const bookmark = await BookmarkModel.findById(id) if (bookmark && bookmark.user_id === userId) { await BookmarkModel.delete(id) results.push(id) } else { errors.push({ id, error: "书签不存在或无权限删除" }) } } catch (error) { errors.push({ id, error: error.message }) } } return { success: results, errors, total: bookmarkIds.length, successCount: results.length, errorCount: errors.length } } catch (error) { if (error instanceof CommonError) throw error throw new CommonError(`批量删除书签失败: ${error.message}`) } } // 获取用户书签统计 async getUserBookmarkStats(userId) { try { if (!userId) { throw new CommonError("用户ID不能为空") } const bookmarks = await BookmarkModel.findAllByUser(userId) // 按标签分组统计 const tagStats = {} bookmarks.forEach(bookmark => { if (bookmark.tags) { const tags = bookmark.tags.split(',').map(tag => tag.trim()) tags.forEach(tag => { tagStats[tag] = (tagStats[tag] || 0) + 1 }) } }) // 按创建时间分组统计 const dateStats = {} bookmarks.forEach(bookmark => { const date = new Date(bookmark.created_at).toISOString().split('T')[0] dateStats[date] = (dateStats[date] || 0) + 1 }) return { total: bookmarks.length, byTag: tagStats, byDate: dateStats, lastUpdated: bookmarks.length > 0 ? bookmarks[0].updated_at : null } } catch (error) { if (error instanceof CommonError) throw error throw new CommonError(`获取书签统计失败: ${error.message}`) } } // 搜索用户书签 async searchUserBookmarks(userId, keyword) { try { if (!userId) { throw new CommonError("用户ID不能为空") } if (!keyword || keyword.trim() === '') { return await this.getUserBookmarks(userId) } const bookmarks = await BookmarkModel.findAllByUser(userId) const searchTerm = keyword.toLowerCase().trim() return bookmarks.filter(bookmark => { return ( bookmark.title?.toLowerCase().includes(searchTerm) || bookmark.description?.toLowerCase().includes(searchTerm) || bookmark.url?.toLowerCase().includes(searchTerm) || bookmark.tags?.toLowerCase().includes(searchTerm) ) }) } catch (error) { if (error instanceof CommonError) throw error throw new CommonError(`搜索书签失败: ${error.message}`) } } // 验证URL格式 isValidUrl(url) { try { new URL(url) return true } catch { return false } } // 获取书签分页 async getBookmarksWithPagination(userId, page = 1, pageSize = 20) { try { if (!userId) { throw new CommonError("用户ID不能为空") } const allBookmarks = await BookmarkModel.findAllByUser(userId) const total = allBookmarks.length const offset = (page - 1) * pageSize const bookmarks = allBookmarks.slice(offset, offset + pageSize) return { bookmarks, pagination: { current: page, pageSize, total, totalPages: Math.ceil(total / pageSize) } } } catch (error) { if (error instanceof CommonError) throw error throw new CommonError(`分页获取书签失败: ${error.message}`) } } } export default BookmarkService export { BookmarkService }