- 添加了对 text/plain 和 application/zip 格式的支持 - 在详情页面增加了 URL 输出调试信息 - 修复了跳转页面时的 URL 和 referer 处理逻辑 - 添加了下载失败时的错误事件推送和提示 - 在前端实现了错误消息的类型区分和显示 - 优化了侧边栏菜单组件的配置参数
158 lines
4.4 KiB
Vue
158 lines
4.4 KiB
Vue
<script setup lang="ts">
|
|
import {ref, onUnmounted} from "vue";
|
|
import {
|
|
file_rename,
|
|
music_rename,
|
|
image_hasTorrent,
|
|
video_hasTorrent,
|
|
video_deduplication,
|
|
torrent_deduplication,
|
|
video_findDeduplication,
|
|
torrent_statistics
|
|
} from "@/api"
|
|
|
|
// 警告项接口
|
|
interface messageItem {
|
|
id: number
|
|
text: string,
|
|
type?: "success" | "error" | "warning" | "info" | "default"
|
|
}
|
|
|
|
interface BtnItem {
|
|
id: number
|
|
title: string
|
|
handle?: () => Promise<{ code: number, message: Array<never> }>
|
|
}
|
|
|
|
const loading = ref(false)
|
|
let eventSource: EventSource // 保存 EventSource 实例
|
|
const status = ref('closed') // 连接状态:closed, connecting, connected
|
|
const messages = ref<messageItem[]>([{id: Date.now(), text: '输出结果'}])
|
|
|
|
const buttons = [
|
|
{id: 0, title: "小说下载"},
|
|
{id: 1, title: "文件重命名", handle: file_rename},
|
|
{id: 2, title: "视频查找重复", handle: video_findDeduplication},
|
|
{id: 3, title: "视频去重", handle: video_deduplication},
|
|
{id: 4, title: "种子去重", handle: torrent_deduplication},
|
|
{id: 5, title: "判断视频是否有torrent", handle: video_hasTorrent},
|
|
{id: 6, title: "判断图片是否有torrent", handle: image_hasTorrent},
|
|
{id: 7, title: "音乐文件重命名", handle: music_rename},
|
|
{id: 8, title: "种子统计", handle: torrent_statistics}
|
|
]
|
|
|
|
|
|
function closeAlert(id: number) {
|
|
console.log(id)
|
|
messages.value = messages.value.filter(item => item.id !== id)
|
|
}
|
|
|
|
const handleClick = async (btnObj: BtnItem) => {
|
|
if (btnObj.title === "断开") return
|
|
if (btnObj.title === "小说下载") {
|
|
connect("http://192.168.1.32:5000/api/book/download")
|
|
return
|
|
}
|
|
loading.value = true
|
|
try {
|
|
if (btnObj.handle == undefined) return
|
|
const res = await btnObj.handle()
|
|
const res_msg = Array.isArray(res.message) ? res.message : [res.message]
|
|
messages.value = res_msg.map((msg: string, index: number) => ({
|
|
id: Date.now() + index, // 简单生成唯一 ID,生产环境建议使用更可靠的 ID 生成器
|
|
text: msg
|
|
}))
|
|
messages.value.push({id: Date.now() + messages.value.length, text: '已完成'})
|
|
messages.value.reverse()
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
const connect = (url: string) => {
|
|
messages.value = []
|
|
if (eventSource) {
|
|
eventSource.close()
|
|
}
|
|
eventSource = new EventSource(url)
|
|
// 连接成功
|
|
eventSource.addEventListener("open", () => {
|
|
console.log('SSE 连接已打开')
|
|
status.value = 'connected'
|
|
})
|
|
// 监听普通消息
|
|
eventSource.addEventListener('message', (event) => {
|
|
messages.value.unshift({id: Date.now() + messages.value.length, text: event.data})
|
|
})
|
|
// 监听关闭事件
|
|
eventSource.addEventListener('close', (event) => {
|
|
messages.value.unshift({id: Date.now() + messages.value.length, text: event.data})
|
|
closeConnection()
|
|
})
|
|
// 错误处理
|
|
// eventSource.addEventListener('error', () => {
|
|
// console.log('连接断开或失败', new Date());
|
|
// // 如果这里也频繁触发,确认了是断连重连
|
|
// if (eventSource.readyState === EventSource.CLOSED) {
|
|
// console.log('状态为 CLOSED');
|
|
// }
|
|
// })
|
|
eventSource.addEventListener('mes_error', (event) => {
|
|
messages.value.unshift({
|
|
id: Date.now() + messages.value.length,
|
|
text: event.data,
|
|
type: "error"
|
|
})
|
|
})
|
|
}
|
|
const closeConnection = () => {
|
|
if (eventSource) {
|
|
eventSource.close()
|
|
// eventSource = null
|
|
status.value = 'closed'
|
|
console.log('SSE 连接已关闭')
|
|
}
|
|
}
|
|
onUnmounted(() => {
|
|
closeConnection()
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<el-main>
|
|
<el-card>
|
|
<template #default>
|
|
<div v-loading="loading" :style="{height: '100%'}">
|
|
<el-alert v-for="item in messages" :key="item.id" :title="item.text"
|
|
:type="item.type?item.type:'primary'"
|
|
@close="closeAlert(item.id)"/>
|
|
</div>
|
|
</template>
|
|
<template #footer>
|
|
<el-button-group>
|
|
<el-button type="primary" v-for="btn in buttons" :key="btn.id"
|
|
@click="handleClick(btn)">
|
|
{{ btn.title }}
|
|
</el-button>
|
|
</el-button-group>
|
|
</template>
|
|
</el-card>
|
|
</el-main>
|
|
</template>
|
|
|
|
<style scoped lang="scss">
|
|
.el-alert + .el-alert {
|
|
margin-top: 20px;
|
|
}
|
|
|
|
:deep(.el-card__footer) {
|
|
display: flex;
|
|
justify-content: center;
|
|
}
|
|
|
|
:deep(.el-card__body) {
|
|
//height: calc(100vh - 211px + 60px);
|
|
height: calc(100vh - 211px);
|
|
}
|
|
</style>
|