- state.collectGallery.slice(0) → splice(0),修复收藏列表数据残留 bug
- action 中 state 引用改为 context.state,遵循 Vuex 规范
- 修复 _searchLocalByLink 中 gid 判空条件(null → undefined)
- 修复 deleteTask splice 后索引跳过下一个元素
- 简化 getShortname 用正则替代繁琐的手动遍历
- 移除 loadWeekUsedAmount 冗余的成功提示弹窗
- 添加 Axios 全局错误拦截器,统一处理网络请求失败
- websocket 初始值 {} → null,修正类型
- resetUndone 硬编码授权码改为从 state 获取
- computed 移除副作用,改用 watch 实现
- HentaiSearch 加载指示器 DOM 操作改为响应式 v-show
- 提取重复的 validateLink 到共享工具函数
- OnlineReader 全量 watch(store.state) → 精准监听 isReading
9.2 KiB
9.2 KiB
LionWebsite 项目分析
项目概述
LionWebsite 是一个基于 Vue 3 + Vite 构建的漫画/Gallery 下载与管理前端应用。用户通过授权码连接后端服务,可以搜索、下载、在线预览来自 exhentai/e-hentai 的漫画 gallery,并管理下载任务。
后端基址: https://downloader.lionwebsite.xyz/
技术栈
| 技术 | 用途 |
|---|---|
Vue 3 (Composition API, <script setup>) |
前端框架 |
| Vite 5 | 构建工具 |
| Element Plus 2.2 | UI 组件库 |
| Vuex 4 | 状态管理 |
| Axios | HTTP 请求 |
| qs | URL 序列化 |
项目结构
D:\WorkSpace\code\Vue\LionWebsite\
├── index.html # 入口 HTML
├── package.json # 依赖声明
├── vite.config.js # Vite 配置(仅 vue 插件 + 0.0.0.0 host)
├── public/ # 静态资源(空)
├── dist/ # 构建产物
└── src/
├── main.js # 应用入口: mount Element Plus + 全局 CSS
├── reset.css # CSS reset
├── App.vue # 根组件: el-container 布局
├── store/
│ └── index.js # Vuex store (所有状态与业务逻辑)
└── components/
├── DashBoard.vue # 仪表盘: 授权、查询、配置、搜索结果弹窗
├── Side.vue # 主列表: Gallery 表格、翻页、分类/排序
├── HentaiSearch.vue# 在线搜索弹窗: 远程搜索 exhentai gallery
└── OnlineReader.vue# 在线预览弹窗: 阅读下载完成的 gallery
组件详解
App.vue (根组件)
- 使用
el-container布局 - 左侧
el-aside(750px) 放置Side组件 - 右侧
el-main放置DashBoard组件
DashBoard.vue — 仪表盘
功能: 授权登录、查询任务、修改授权码、在线搜索入口、节点重连、配置管理
- 授权模块: 输入授权码 → 调用
store.dispatch("validate")→ 记住密码(localStorage) - 查询模块: 支持按链接远程查询或按链接/关键字本地查询
- 操作按钮: 修改授权码、删除本地授权码、夜间模式切换、在线搜索入口、重连节点
- 配置弹窗: 夜间模式(跟随系统)、在线预览分页数、默认分类/排序/显示类型 → 持久化到 localStorage
- 查询结果弹窗: 显示 gallery 详细信息,可选择分辨率提交下载任务
- 缩略图预览: 鼠标悬停 gallery 时在仪表盘显示封面缩略图
- 初始化:
onMounted时从 localStorage 恢复授权码与配置
Side.vue — 主列表
功能: 展示 gallery 表格、分页、分类/排序切换
- 表格: 使用 Element Plus
el-table,列含展开行(详细信息)、名字、操作(下载/收藏/在线看)、进度 - 操作列:
- 下载: 仅当 status==="下载完成" 时可用,直接
window.open下载链接 - 收藏/取消收藏: 调用
collectGallery/disCollectGallery - 在线看: 调用
readOnlineGallery
- 下载: 仅当 status==="下载完成" 时可用,直接
- 分类切换: 我的下载 / 我的收藏 / 全部
- 排序: 名字 / 简洁名字 / 任务创建时间
- 显示类型: 完整名字 / 简洁名字
- 翻页: 首页/上一页/下一页/尾页 + 直接输入页码
- 缩略图悬停: 500ms 防抖后触发缩略图更新
- 空状态提示: 根据分类显示"您未下载过"或"您未收藏过"
HentaiSearch.vue — 在线搜索
功能: 远程搜索 exhentai 上的 gallery
- 输入关键字 → 调用
https://downloader.lionwebsite.xyz/query?keyword=xxx - 支持分页导航(首页/上一页/下一页/尾页),后端返回分页链接
- 每个搜索结果展示: 封面缩略图、名字、上传时间、页数、类型、链接
- 操作: "在线看"直接阅读、"查看详情"查询到本地并打开详情弹窗
- 加载状态: CSS 旋转动画 loading 指示器
OnlineReader.vue — 在线预览
功能: 在弹窗中阅读 gallery 图片
- 分页阅读: 每页显示
lengthPerPage张图片(默认30),支持翻页 - 图片懒加载: 每加载完成一张自动触发加载下一张(
loadImage) - 支持大图预览: 点击图片使用 Element Plus
el-image的preview-src-list - 连续阅读: 翻页滚动体验优化(监听
switch事件) - 页数 < 9 时显示全部页码按钮,>= 9 时只显示输入跳转
Vuex Store 分析 (store/index.js)
Store 是应用的核心,管理所有状态与后端通信。
State 关键字段
| 字段 | 类型 | 说明 |
|---|---|---|
totalGalleryTask |
Array | 所有 gallery 任务 |
chosenGallery |
Object/false | 当前选中的 gallery(待下载) |
collectGallery |
Array | 收藏的 gallery |
downloadGallery |
Array | 分配给当前用户的 gallery |
searchTask |
Array | 本地搜索结果 |
currentTasks |
Array | 当前显示的 tasks(根据分类筛选) |
readingGallery |
Object | 正在阅读的 gallery |
isReading |
Boolean | 是否正在阅读 |
isAuth |
Boolean | 是否已验证 |
AuthCode |
String | 授权码 |
userId |
Number | 用户 ID |
username |
String | 用户名 |
category |
String | 分类: myDownload / myCollect / total |
sortType |
String | 排序: shortName / name / createTime |
galleryNameType |
String | 显示名: shortName / name |
page |
Number | 当前页码 |
length |
Number | 每页条目数 |
websocket |
WebSocket | WebSocket 连接 |
Actions (后端交互)
| Action | 方法 | 端点 | 说明 |
|---|---|---|---|
validate |
POST | /validate |
验证授权码,初始化数据 |
updateGalleryTasks |
GET | /GalleryManage |
获取所有 gallery 任务 |
postGalleryTask |
POST | /GalleryManage |
提交下载任务 |
queryGalleryTask |
GET | /GalleryManage |
按链接查询 gallery |
loadWeekUsedAmount |
GET | /GalleryManage/weekUsedAmount |
查询本周用量 |
collectGallery |
POST | /GalleryManage/collect |
收藏 gallery |
disCollectGallery |
POST | /GalleryManage/disCollect |
取消收藏 |
deleteGallery |
DELETE | /GalleryManage |
删除 gallery |
readOnlineGallery |
POST | /GalleryManage/cache |
缓存并开始在线预览 |
alterAuthCode |
PUT | /AuthCode |
修改授权码 |
reconnect |
POST | /GalleryManage/reconnect |
重连下载节点 |
resetUndone |
POST | /GalleryManage/reset |
重置未完成任务 |
WebSocket 通信
- 端点:
wss://downloader.lionwebsite.xyz/ws/ - 连接后发送:
"DownloaderWebsocket" - 消息类型:
updateTasks: 增量更新任务进度fullUpdate: 触发全量刷新
Getters
| Getter | 说明 |
|---|---|
currentTasks |
返回当前页的 tasks(支持搜索态) |
min |
最小页码(1) |
max |
最大页码 |
辅助函数
getShortname(name): 从 gallery 名中去除中括号/括号内的标签信息confirmCurrentTask(state): 根据 category 切换 currentTaskssortTasks(state): 根据 sortType 排序deleteTask(tasks, key, value): 从多个数组中删除匹配的任务
API 端点汇总
所有请求均需携带 AuthCode 参数:
| 端点 | 用途 |
|---|---|
POST /validate |
授权码验证 |
GET/POST/DELETE /GalleryManage |
任务 CRUD |
GET /GalleryManage/weekUsedAmount |
每周用量查询 |
POST /GalleryManage/collect |
收藏 |
POST /GalleryManage/disCollect |
取消收藏 |
POST /GalleryManage/cache |
缓存 gallery 用于在线预览 |
POST /GalleryManage/reconnect |
重连下载节点 |
POST /GalleryManage/reset |
重置未完成任务 |
GET /GalleryManage/ehThumbnail |
获取缩略图 |
GET /GalleryManage/file/{name}.zip |
下载文件 |
GET /GalleryManage/onlineImage/{i} |
在线预览图片 |
PUT /AuthCode |
修改授权码 |
GET /query |
远程搜索 exhentai |
WS /ws/ |
WebSocket 实时推送 |
特色与关键实现
- 简洁名字处理:
getShortname()使用启发式逻辑从 gallery 完整名中剥离标签 - 防抖缩略图: Side 组件 mouseenter 时 500ms 防抖才更新缩略图
- 夜间模式: 通过 Element Plus 的
darkCSS class 切换,支持跟随系统偏好 - 权限分级: userId===3 的用户(Lion)有额外操作权限(重置任务、查看 downloader)
- 本地持久化: 授权码、分页配置、分类/排序/显示偏好均存 localStorage
- WebSocket 实时更新: 任务进度变化时服务端通过 WebSocket 推送增量更新
- 图片懒加载: 按页加载图片,每加载完成一张自动触发下一张加载
构建与运行
npm run dev # 开发服务器 (0.0.0.0)
npm run build # 生产构建
npm run preview # 预览构建产物
潜在问题/改进点
store/index.js中updateGalleryTasks的 action 引用了未在函数签名中声明的state— 使用了外部模块级变量而非 context.state,这在严格模式下可能引起问题state.websocket在 Vuex 中初始化为{}而非null,检查方式不够严谨getShortname函数逻辑复杂且有多处副作用,可读性较低- 部分错误处理较简略(如
queryGalleries中无网络错误处理) store/index.js中 action 使用全局state变量(而非context.state),可能导致作用域混淆