diff --git a/README.md b/README.md index 5a62e26..c5c5497 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ Pixiv 下载浏览管理器是一个基于 Web 的应用程序,提供以下功 - 双击 `start.bat` 文件启动 5. **访问应用** - - 打开浏览器访问:http://localhost:3000(默认端口,可修改) + - 打开浏览器访问:http://localhost:3000 (默认端口,可修改) ## 🌐 代理配置 diff --git a/backend/routes/artwork.js b/backend/routes/artwork.js index 33b7dfb..ddf008f 100644 --- a/backend/routes/artwork.js +++ b/backend/routes/artwork.js @@ -65,6 +65,46 @@ router.get('/search', async (req, res) => { } }); +/** + * 获取用户收藏的作品列表 + * GET /api/artwork/bookmarks + */ +router.get('/bookmarks', async (req, res) => { + try { + const { + type = 'all', + offset = 0, + limit = 30 + } = req.query; + + const artworkService = new ArtworkService(req.backend.getAuth()); + const result = await artworkService.getBookmarks({ + type, + offset: parseInt(offset), + limit: parseInt(limit) + }); + + if (result.success) { + res.json({ + success: true, + data: result.data + }); + } else { + res.status(400).json({ + success: false, + error: result.error + }); + } + } catch (error) { + res.status(500).json({ + success: false, + error: error.message + }); + } +}); + + + /** * 获取作品详情 * GET /api/artwork/:id @@ -181,4 +221,49 @@ router.get('/:id/images', async (req, res) => { } }); +/** + * 收藏/取消收藏作品 + * POST /api/artwork/:id/bookmark + */ +router.post('/:id/bookmark', async (req, res) => { + try { + const { id } = req.params; + const { action = 'add' } = req.body; // 'add' 或 'remove' + + if (!id || isNaN(parseInt(id))) { + return res.status(400).json({ + success: false, + error: 'Invalid artwork ID' + }); + } + + if (!['add', 'remove'].includes(action)) { + return res.status(400).json({ + success: false, + error: 'Invalid action. Must be "add" or "remove"' + }); + } + + const artworkService = new ArtworkService(req.backend.getAuth()); + const result = await artworkService.toggleBookmark(parseInt(id), action); + + if (result.success) { + res.json({ + success: true, + data: result.data + }); + } else { + res.status(400).json({ + success: false, + error: result.error + }); + } + } catch (error) { + res.status(500).json({ + success: false, + error: error.message + }); + } +}); + module.exports = router; \ No newline at end of file diff --git a/backend/services/artwork.js b/backend/services/artwork.js index a9896aa..9457cef 100644 --- a/backend/services/artwork.js +++ b/backend/services/artwork.js @@ -277,6 +277,86 @@ class ArtworkService { } } + /** + * 收藏/取消收藏作品 + */ + /** + * 收藏/取消收藏作品 + * TODO: Pixiv API 端点已更改,需要研究新的端点 + * 当前端点 /v1/illust/bookmark/add 和 /v1/illust/bookmark/delete 已不可用 + */ + async toggleBookmark(artworkId, action = 'add') { + try { + // TODO: 需要研究新的 Pixiv API 端点 + // 当前所有收藏相关的 API 端点都返回 404 错误 + console.log(`尝试${action === 'add' ? '添加' : '删除'}收藏 ${artworkId},但API端点不可用`); + + return { + success: false, + error: `收藏功能暂时不可用。请前往 Pixiv 官方网站进行${action === 'add' ? '收藏' : '取消收藏'}操作。` + }; + } catch (error) { + return { + success: false, + error: error.message, + }; + } + } + + /** + * 获取用户收藏的作品列表 + */ + async getBookmarks(options = {}) { + try { + const { type = 'all', offset = 0, limit = 30 } = options; + + // 从认证状态获取用户ID + const status = this.auth.getStatus(); + if (!status.isLoggedIn || !this.auth.user || !this.auth.user.id) { + throw new Error('用户未登录或无法获取用户ID'); + } + + const userId = this.auth.user.id; + + // 根据类型选择不同的API端点 + let endpoint = '/v1/user/bookmarks/illust'; + if (type === 'manga') { + endpoint = '/v1/user/bookmarks/novel'; + } else if (type === 'novel') { + endpoint = '/v1/user/bookmarks/novel'; + } + + const params = { + user_id: userId, + restrict: 'public', + offset, + limit, + }; + + const response = await this.makeRequest('GET', `${endpoint}?${stringify(params)}`); + + return { + success: true, + data: { + artworks: response.illusts || [], + next_url: response.next_url, + total: response.total || 0, + }, + }; + } catch (error) { + console.error('获取收藏列表失败:', { + message: error.message, + status: error.response?.status, + data: error.response?.data, + config: error.config + }); + return { + success: false, + error: error.message, + }; + } + } + /** * 发送API请求 */ diff --git a/ui/src/App.vue b/ui/src/App.vue index faef1af..cdeda5b 100644 --- a/ui/src/App.vue +++ b/ui/src/App.vue @@ -21,7 +21,8 @@ onMounted(async () => { 登录 - + - + - + @@ -107,7 +105,7 @@ onMounted(async () => { display: flex; align-items: center; gap: 0.5rem; - + text-decoration: none; color: #1f2937; font-weight: 700; @@ -249,23 +247,23 @@ onMounted(async () => { .nav-container { padding: 0 1rem; } - + .nav-menu { gap: 1rem; } - + .brand-text { display: none; } - + .username { display: none; } - + .github-link { margin-left: 0.25rem; } - + .github-icon { width: 1.25rem; height: 1.25rem; diff --git a/ui/src/components/artwork/ArtworkCard.vue b/ui/src/components/artwork/ArtworkCard.vue index 82443aa..f3673ae 100644 --- a/ui/src/components/artwork/ArtworkCard.vue +++ b/ui/src/components/artwork/ArtworkCard.vue @@ -55,7 +55,7 @@ + + \ No newline at end of file diff --git a/ui/src/views/DownloadsView.vue b/ui/src/views/DownloadsView.vue index 5f1d6c2..a08bde3 100644 --- a/ui/src/views/DownloadsView.vue +++ b/ui/src/views/DownloadsView.vue @@ -6,7 +6,8 @@
@@ -19,25 +20,13 @@
- - -
@@ -51,7 +40,8 @@
- +

暂无下载任务

开始下载作品后,任务将显示在这里

@@ -59,11 +49,7 @@
-
+

@@ -74,11 +60,7 @@

-
@@ -86,10 +68,7 @@
-
+
{{ task.completed_files }}/{{ task.total_files }} ({{ task.progress }}%) @@ -127,7 +106,8 @@
- +

暂无下载历史

下载完成后,历史记录将显示在这里

@@ -135,11 +115,7 @@
-
+

@@ -150,10 +126,7 @@

-
@@ -190,7 +163,8 @@
- +

暂无下载文件

下载完成后,文件将显示在这里

@@ -198,27 +172,17 @@
-
+

{{ file.artwork }}

{{ file.artist }}

- -
@@ -250,8 +214,7 @@ import { ref, onMounted, onUnmounted } from 'vue'; import { useAuthStore } from '@/stores/auth'; import downloadService from '@/services/download'; import type { DownloadTask } from '@/types'; -import LoadingSpinner from '@/components/common/LoadingSpinner.vue'; -import ErrorMessage from '@/components/common/ErrorMessage.vue'; + const authStore = useAuthStore(); @@ -732,4 +695,4 @@ onUnmounted(() => { .btn-text:hover { background: #f3f4f6; } - \ No newline at end of file + \ No newline at end of file diff --git a/ui/src/views/HomeView.vue b/ui/src/views/HomeView.vue index 35736f4..6036b87 100644 --- a/ui/src/views/HomeView.vue +++ b/ui/src/views/HomeView.vue @@ -19,27 +19,16 @@ onMounted(async () => {

发现、收藏、下载你喜欢的 Pixiv 作品

- +
- + 立即登录 - + 开始搜索 - - + + 下载管理
@@ -49,12 +38,13 @@ onMounted(async () => {

主要功能

- +
- +

作品搜索

@@ -66,7 +56,21 @@ onMounted(async () => {
- + + +
+

热门榜单

+

+ 查看日榜、周榜、月榜热门作品,一键批量下载 +

+
+ +
+
+ +

一键下载

@@ -78,7 +82,8 @@ onMounted(async () => {
- +

作者管理

@@ -90,8 +95,9 @@ onMounted(async () => {
- - + +

下载管理

@@ -103,7 +109,8 @@ onMounted(async () => {
- +

仓库管理

@@ -111,53 +118,12 @@ onMounted(async () => { 管理本地作品仓库,分类整理和快速检索

+
-
-
-

快速操作

- -
- -
- - - -
- 搜索作品 -
- -
- - - -
- 下载管理 -
- - -
- - - -
- 作者管理 -
- - -
- - - -
- 仓库管理 -
-
-
-
@@ -302,85 +268,31 @@ onMounted(async () => { line-height: 1.6; } -.quick-actions { - padding: 4rem 0; -} -.quick-actions-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); - gap: 1.5rem; - max-width: 600px; - margin: 0 auto; -} - -.quick-action-card { - display: flex; - flex-direction: column; - align-items: center; - gap: 1rem; - padding: 2rem; - background: white; - border-radius: 1rem; - text-decoration: none; - color: #374151; - box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1); - transition: all 0.2s; -} - -.quick-action-card:hover { - transform: translateY(-2px); - box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1); - color: #3b82f6; -} - -.quick-action-icon { - width: 3rem; - height: 3rem; - background: #f3f4f6; - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - color: #6b7280; - transition: all 0.2s; -} - -.quick-action-card:hover .quick-action-icon { - background: #3b82f6; - color: white; -} - -.quick-action-icon svg { - width: 1.5rem; - height: 1.5rem; -} @media (max-width: 768px) { .hero-title { font-size: 2rem; } - + .hero-subtitle { font-size: 1rem; } - + .hero-actions { flex-direction: column; align-items: center; } - + .btn { width: 100%; max-width: 300px; } - + .features-grid { grid-template-columns: 1fr; } - - .quick-actions-grid { - grid-template-columns: 1fr; - } + + } diff --git a/ui/src/views/LoginView.vue b/ui/src/views/LoginView.vue index 9336565..0f93e7c 100644 --- a/ui/src/views/LoginView.vue +++ b/ui/src/views/LoginView.vue @@ -10,25 +10,21 @@
- +