You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

312 lines
9.8 KiB

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 }