重构 store 并修复多个 bug
- 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
This commit is contained in:
parent
e19ae3d802
commit
e25afb7445
BIN
favicon.ico
BIN
favicon.ico
Binary file not shown.
|
Before Width: | Height: | Size: 4.2 KiB |
201
llm_readme.md
Normal file
201
llm_readme.md
Normal file
@ -0,0 +1,201 @@
|
||||
# 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`
|
||||
- **分类切换**: 我的下载 / 我的收藏 / 全部
|
||||
- **排序**: 名字 / 简洁名字 / 任务创建时间
|
||||
- **显示类型**: 完整名字 / 简洁名字
|
||||
- **翻页**: 首页/上一页/下一页/尾页 + 直接输入页码
|
||||
- **缩略图悬停**: 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 切换 currentTasks
|
||||
- `sortTasks(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 实时推送 |
|
||||
|
||||
## 特色与关键实现
|
||||
|
||||
1. **简洁名字处理**: `getShortname()` 使用启发式逻辑从 gallery 完整名中剥离标签
|
||||
2. **防抖缩略图**: Side 组件 mouseenter 时 500ms 防抖才更新缩略图
|
||||
3. **夜间模式**: 通过 Element Plus 的 `dark` CSS class 切换,支持跟随系统偏好
|
||||
4. **权限分级**: userId===3 的用户(Lion)有额外操作权限(重置任务、查看 downloader)
|
||||
5. **本地持久化**: 授权码、分页配置、分类/排序/显示偏好均存 localStorage
|
||||
6. **WebSocket 实时更新**: 任务进度变化时服务端通过 WebSocket 推送增量更新
|
||||
7. **图片懒加载**: 按页加载图片,每加载完成一张自动触发下一张加载
|
||||
|
||||
## 构建与运行
|
||||
|
||||
```bash
|
||||
npm run dev # 开发服务器 (0.0.0.0)
|
||||
npm run build # 生产构建
|
||||
npm run preview # 预览构建产物
|
||||
```
|
||||
|
||||
## 潜在问题/改进点
|
||||
|
||||
1. `store/index.js` 中 `updateGalleryTasks` 的 action 引用了未在函数签名中声明的 `state` — 使用了外部模块级变量而非 context.state,这在严格模式下可能引起问题
|
||||
2. `state.websocket` 在 Vuex 中初始化为 `{}` 而非 `null`,检查方式不够严谨
|
||||
3. `getShortname` 函数逻辑复杂且有多处副作用,可读性较低
|
||||
4. 部分错误处理较简略(如 `queryGalleries` 中无网络错误处理)
|
||||
5. `store/index.js` 中 action 使用全局 `state` 变量(而非 `context.state`),可能导致作用域混淆
|
||||
@ -140,9 +140,10 @@
|
||||
|
||||
<script setup>
|
||||
import store from "../store";
|
||||
import {computed, ref, onMounted} from "vue";
|
||||
import {computed, ref, onMounted, watch} from "vue";
|
||||
import {ElMessage} from "element-plus"
|
||||
import HentaiSearch from "./HentaiSearch.vue";
|
||||
import {validateLink} from "../utils/validate.js";
|
||||
|
||||
//授权码相关
|
||||
let AuthCode = ref("")
|
||||
@ -172,8 +173,6 @@ let realAuthCode = computed(() => {
|
||||
})
|
||||
|
||||
let chosenGallery = computed(() => {
|
||||
param.value = ''
|
||||
targetResolution.value = ''
|
||||
return store.state.chosenGallery
|
||||
})
|
||||
|
||||
@ -192,6 +191,12 @@ let isLion = computed(() => {
|
||||
return store.state.userId === 3
|
||||
})
|
||||
|
||||
// 查询弹窗打开时重置表单
|
||||
watch(chosenGallery, () => {
|
||||
param.value = ''
|
||||
targetResolution.value = ''
|
||||
})
|
||||
|
||||
//重连节点
|
||||
function reconnect(){
|
||||
store.dispatch("reconnect")
|
||||
@ -269,16 +274,6 @@ function validate(){
|
||||
}
|
||||
}
|
||||
|
||||
//验证链接
|
||||
function validateLink(rawLink){
|
||||
if(rawLink.trim() === "")
|
||||
return false
|
||||
if(rawLink.includes("hentai"))
|
||||
return rawLink.includes("/g/")
|
||||
else
|
||||
return false
|
||||
}
|
||||
|
||||
//在线阅读以及展示缩略图
|
||||
function readOnlineGallery(gallery){
|
||||
store.dispatch("readOnlineGallery", gallery)
|
||||
|
||||
@ -4,6 +4,7 @@ import {ref, watch} from "vue";
|
||||
import axios from "axios";
|
||||
import {ElMessage} from "element-plus";
|
||||
import store from "../store/index.js";
|
||||
import {validateLink} from "../utils/validate.js";
|
||||
|
||||
let props = defineProps(['isQuerying'])
|
||||
let emit = defineEmits(['close'])
|
||||
@ -13,6 +14,7 @@ let queryPage = ref({})
|
||||
let galleries = ref([])
|
||||
let param = ref()
|
||||
let isShowUp = ref()
|
||||
let isLoading = ref(false)
|
||||
|
||||
watch(props, () => {
|
||||
isShowUp.value = props.isQuerying
|
||||
@ -27,11 +29,10 @@ function queryGalleries(link) {
|
||||
tempParam = keyword.value
|
||||
}
|
||||
tempParam = tempParam.replace(" ", "+")
|
||||
document.getElementById("loading").style.display = "inline-block";
|
||||
isLoading.value = true
|
||||
|
||||
axios.get("https://downloader.lionwebsite.xyz/query?keyword=" + tempParam)
|
||||
.then((res) => {
|
||||
document.getElementById("loading").style.display = "none";
|
||||
if (res.data.result === "success") {
|
||||
let tempGalleries = JSON.parse(res.data.data)
|
||||
queryPage.value.first = 'first' in res.data ? res.data.first : undefined
|
||||
@ -48,6 +49,8 @@ function queryGalleries(link) {
|
||||
} else {
|
||||
ElMessage({message: res.data.data, type: "error"})
|
||||
}
|
||||
}).finally(() => {
|
||||
isLoading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
@ -59,15 +62,6 @@ function queryRemoteTask(){
|
||||
store.dispatch("queryGalleryTask", param.value)
|
||||
}
|
||||
|
||||
function validateLink(rawLink){
|
||||
if(rawLink.trim() === "")
|
||||
return false
|
||||
if(rawLink.includes("hentai"))
|
||||
return rawLink.includes("/g/")
|
||||
else
|
||||
return false
|
||||
}
|
||||
|
||||
function close(){
|
||||
emit("close")
|
||||
}
|
||||
@ -76,7 +70,7 @@ function close(){
|
||||
<template>
|
||||
<el-dialog title="在线搜索" v-model="isShowUp" top="0" style="margin-bottom: 0" @close="close">
|
||||
<div style="text-align: center">
|
||||
<el-input v-model="keyword"></el-input> <el-button @click="queryGalleries(null)">查询</el-button> <div id="loading"/>
|
||||
<el-input v-model="keyword"></el-input> <el-button @click="queryGalleries(null)">查询</el-button> <div class="loading" v-show="isLoading"/>
|
||||
</div>
|
||||
<el-scrollbar height="75vh" ref="scrollBar">
|
||||
<div style="height: 251px; width: 100%; " v-for="gallery in galleries">
|
||||
@ -113,14 +107,13 @@ function close(){
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
#loading {
|
||||
.loading {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
border: 2px solid #ccc;
|
||||
border-top-color: #3498db;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
display: none;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
|
||||
@ -18,8 +18,8 @@ let lengthPerPage = computed(() => {
|
||||
let readingGallery = computed(() => {
|
||||
return store.state.readingGallery
|
||||
})
|
||||
watch((store.state), (value) => {
|
||||
if(value.isReading && !isReading.value) {
|
||||
watch(() => store.state.isReading, (isReadingVal) => {
|
||||
if(isReadingVal && !isReading.value) {
|
||||
alterPage()
|
||||
isReading.value = true
|
||||
}
|
||||
|
||||
@ -96,7 +96,7 @@
|
||||
|
||||
<script setup>
|
||||
import store from "../store";
|
||||
import {computed, ref} from "vue";
|
||||
import {computed, ref, watch} from "vue";
|
||||
import OnlineReader from "./OnlineReader.vue";
|
||||
|
||||
//输入
|
||||
@ -133,18 +133,24 @@ let min = computed(() => {
|
||||
return store.getters.min
|
||||
})
|
||||
let max = computed(() => {
|
||||
if(targetPage.value > store.getters.max)
|
||||
store.commit("_changePage", store.getters.max)
|
||||
return store.getters.max
|
||||
})
|
||||
let page = computed(() => {
|
||||
targetPage.value = store.state.page
|
||||
return store.state.page
|
||||
})
|
||||
let isLion = computed(() => {
|
||||
return store.state.userId === 3
|
||||
})
|
||||
|
||||
// 同步 store.page → local targetPage,并在 page 超出 max 时修正
|
||||
watch(page, (newPage) => {
|
||||
targetPage.value = newPage
|
||||
})
|
||||
watch(max, (newMax) => {
|
||||
if(targetPage.value > newMax)
|
||||
store.commit("_changePage", newMax)
|
||||
})
|
||||
|
||||
let emptyText = computed(() => {
|
||||
let action = category.value === 'myDownload' ? '下载': '收藏'
|
||||
return '您未' + action + "过"
|
||||
|
||||
@ -5,11 +5,20 @@ import qs from "qs"
|
||||
const BaseUrl = "https://downloader.lionwebsite.xyz/"
|
||||
const GalleryManageUrl = BaseUrl + "GalleryManage"
|
||||
|
||||
// Axios 全局错误处理
|
||||
axios.interceptors.response.use(
|
||||
response => response,
|
||||
error => {
|
||||
ElMessage({message: "网络请求失败: " + (error.message || ""), type: "error"})
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
const actions = {
|
||||
reconnect(context) {
|
||||
axios.post(GalleryManageUrl + "/reconnect", {
|
||||
params: {
|
||||
AuthCode: state.AuthCode
|
||||
AuthCode: context.state.AuthCode
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.data.result === "success") {
|
||||
@ -22,7 +31,7 @@ const actions = {
|
||||
updateGalleryTasks(context){
|
||||
axios.get(GalleryManageUrl, {
|
||||
params:{
|
||||
AuthCode: state.AuthCode,
|
||||
AuthCode: context.state.AuthCode,
|
||||
type: 'all'
|
||||
}
|
||||
}).then((res) => {
|
||||
@ -32,7 +41,7 @@ const actions = {
|
||||
},
|
||||
postGalleryTask(context, data){
|
||||
axios.post(GalleryManageUrl + '?' + qs.stringify({
|
||||
AuthCode: state.AuthCode,
|
||||
AuthCode: context.state.AuthCode,
|
||||
...data
|
||||
}, {indices:false})).then((res) => {
|
||||
if(res.data.result === "success") {
|
||||
@ -52,7 +61,7 @@ const actions = {
|
||||
params:{
|
||||
param: link,
|
||||
type: 'link',
|
||||
AuthCode: state.AuthCode
|
||||
AuthCode: context.state.AuthCode
|
||||
}
|
||||
}).then((res) => {
|
||||
if(res.data.result === 'success')
|
||||
@ -78,12 +87,12 @@ const actions = {
|
||||
})
|
||||
},
|
||||
initWebsocket(context){
|
||||
state.websocket = new WebSocket("wss://downloader.lionwebsite.xyz/ws/")
|
||||
state.websocket.onopen = () => {
|
||||
state.websocket.send("DownloaderWebsocket")
|
||||
context.state.websocket = new WebSocket("wss://downloader.lionwebsite.xyz/ws/")
|
||||
context.state.websocket.onopen = () => {
|
||||
context.state.websocket.send("DownloaderWebsocket")
|
||||
}
|
||||
|
||||
state.websocket.onmessage = (event) => {
|
||||
context.state.websocket.onmessage = (event) => {
|
||||
let message = JSON.parse(event.data)
|
||||
|
||||
switch (message.type){
|
||||
@ -98,19 +107,18 @@ const actions = {
|
||||
loadWeekUsedAmount(context){
|
||||
axios.get(GalleryManageUrl + "/weekUsedAmount", {
|
||||
params: {
|
||||
AuthCode: state.AuthCode
|
||||
AuthCode: context.state.AuthCode
|
||||
}
|
||||
}).then((res) => {
|
||||
if(res.data.result === "success"){
|
||||
context.state.weekUsed = JSON.parse(res.data.data)
|
||||
ElMessage("查询用量成功")
|
||||
}else
|
||||
ElMessage("查询用量失败")
|
||||
})
|
||||
},
|
||||
collectGallery(context, gid){
|
||||
axios.post(GalleryManageUrl + "/collect?" +qs.stringify( {
|
||||
gid, AuthCode:state.AuthCode
|
||||
gid, AuthCode:context.state.AuthCode
|
||||
})).then((res) => {
|
||||
ElMessage(res.data.data)
|
||||
if(res.data.result === 'success')
|
||||
@ -119,7 +127,7 @@ const actions = {
|
||||
},
|
||||
disCollectGallery(context, gid){
|
||||
axios.post(GalleryManageUrl + "/disCollect?" + qs.stringify({
|
||||
gid, AuthCode:state.AuthCode
|
||||
gid, AuthCode:context.state.AuthCode
|
||||
})).then((res) => {
|
||||
ElMessage(res.data.data)
|
||||
if(res.data.result === 'success')
|
||||
@ -129,7 +137,7 @@ const actions = {
|
||||
deleteGallery(context, gid){
|
||||
axios.delete(GalleryManageUrl, {
|
||||
params:{
|
||||
AuthCode:state.AuthCode, gid
|
||||
AuthCode:context.state.AuthCode, gid
|
||||
}}).then((res) => {
|
||||
if(res.data.result === "success"){
|
||||
ElMessage("删除成功")
|
||||
@ -154,11 +162,11 @@ const actions = {
|
||||
})
|
||||
},
|
||||
alterAuthCode(context, AuthCode){
|
||||
axios.put(BaseUrl + "AuthCode?" + qs.stringify({'AuthCode': state.AuthCode, 'newAuthCode': AuthCode}))
|
||||
axios.put(BaseUrl + "AuthCode?" + qs.stringify({'AuthCode': context.state.AuthCode, 'newAuthCode': AuthCode}))
|
||||
.then((res) => {
|
||||
if(res.data.result === 'success') {
|
||||
ElMessage("修改成功")
|
||||
if(localStorage.getItem("auth") === state.AuthCode)
|
||||
if(localStorage.getItem("auth") === context.state.AuthCode)
|
||||
localStorage.setItem("auth", AuthCode)
|
||||
context.state.AuthCode = AuthCode
|
||||
}
|
||||
@ -166,8 +174,8 @@ const actions = {
|
||||
ElMessage(res.data.data)
|
||||
})
|
||||
},
|
||||
resetUndone(){
|
||||
axios.post(GalleryManageUrl + "/reset?AuthCode=big+lion").then((res) => {
|
||||
resetUndone(context){
|
||||
axios.post(GalleryManageUrl + "/reset?AuthCode=" + context.state.AuthCode).then((res) => {
|
||||
ElMessage(res.data.data)
|
||||
})
|
||||
}
|
||||
@ -195,7 +203,7 @@ const mutations = {
|
||||
},
|
||||
_updateGalleryTasks(state, tasks){
|
||||
state.totalGalleryTask.splice(0)
|
||||
state.collectGallery.slice(0)
|
||||
state.collectGallery.splice(0)
|
||||
state.downloadGallery.splice(0)
|
||||
|
||||
tasks.forEach((task) => {
|
||||
@ -281,21 +289,18 @@ const mutations = {
|
||||
},
|
||||
_searchLocalByLink(state, link){
|
||||
let tasks = state.currentTasks
|
||||
let i = 0
|
||||
let gid = null
|
||||
let gid = link.split("/")[4]
|
||||
let name = null
|
||||
|
||||
gid = link.split("/")[4]
|
||||
|
||||
if(gid === null)
|
||||
for (i = 0; i < tasks.length; i++) {
|
||||
if(gid === undefined)
|
||||
for (let i = 0; i < tasks.length; i++) {
|
||||
if (tasks[i].link === link) {
|
||||
state.page = Math.floor(i / state.length) + 1
|
||||
name = tasks[i].name
|
||||
break
|
||||
}
|
||||
}
|
||||
else for (i = 0; i < tasks.length; i++)
|
||||
else for (let i = 0; i < tasks.length; i++)
|
||||
if (tasks[i].gid === gid) {
|
||||
state.page = Math.floor(i / state.length) + 1
|
||||
name = state.sortType === "shortName" ? tasks[i].shortName: tasks[i].name
|
||||
@ -382,7 +387,7 @@ const mutations = {
|
||||
}
|
||||
|
||||
const state = {
|
||||
websocket: {}, //websocket
|
||||
websocket: null, //websocket
|
||||
|
||||
totalGalleryTask: [], //存放数据的数组
|
||||
chosenGallery: false, //准备下载
|
||||
@ -459,37 +464,11 @@ function getShortname(name){
|
||||
console.log(name)
|
||||
return null
|
||||
}
|
||||
if (name.includes("[")) {
|
||||
let lastIndex = name.lastIndexOf("[")
|
||||
name = name.substring(0, lastIndex)
|
||||
while (name.includes("[") && name.includes("]") && name.indexOf("[") < name.indexOf("]")) {
|
||||
let start = name.indexOf("[")
|
||||
let end = name.indexOf("]") + 1
|
||||
let temp = name.substring(start, end)
|
||||
temp = name.replace(temp, "")
|
||||
if(temp.trim() === ""){
|
||||
name = name.replace("[", "").replace("]", "")
|
||||
break
|
||||
}
|
||||
else
|
||||
name = temp
|
||||
}
|
||||
while (name.includes("(") && name.includes(")") && name.indexOf("(") < name.indexOf(")")) {
|
||||
let start = name.indexOf("(")
|
||||
let end = name.indexOf(")") + 1
|
||||
let temp = name.substring(start, end)
|
||||
temp = name.replace(temp, "")
|
||||
if(temp.trim() === ""){
|
||||
name = name.replace("(", "").replace(")", "")
|
||||
break
|
||||
}
|
||||
else
|
||||
name = temp
|
||||
}
|
||||
return name.trim()
|
||||
} else {
|
||||
return name
|
||||
}
|
||||
if (!name.includes("[")) return name
|
||||
|
||||
// 截取最后一个 [ 之前的部分,然后移除所有 [...] 和 (...) 标签
|
||||
name = name.substring(0, name.lastIndexOf("["))
|
||||
return name.replace(/\s*\[[^\]]*\]\s*/g, '').replace(/\s*\([^\)]*\)\s*/g, '').trim()
|
||||
}
|
||||
|
||||
function confirmCurrentTask(state){
|
||||
@ -530,6 +509,7 @@ function deleteTask(tasks, key, value){
|
||||
for(let i=0; i<tasks[j].length; i++)
|
||||
if(tasks[j][i][key] === value){
|
||||
tasks[j].splice(i, 1)
|
||||
i--
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
8
src/utils/validate.js
Normal file
8
src/utils/validate.js
Normal file
@ -0,0 +1,8 @@
|
||||
export function validateLink(rawLink){
|
||||
if(rawLink.trim() === "")
|
||||
return false
|
||||
if(rawLink.includes("hentai"))
|
||||
return rawLink.includes("/g/")
|
||||
else
|
||||
return false
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user