feat(project): 初始化项目结构和配置
- 添加.gitignore和.flaskenv环境配置文件 - 创建Flask应用基础架构,包括models、services、utils模块 - 配置数据库模型User和Setting,集成SQLAlchemy和Alembic迁移 - 添加前端Vue项目结构,包含Element Plus组件库 - 配置前后端API路由和蓝prints模块 - 实现书籍下载服务BookService功能模块 - 添加代码规范配置.editorconfig、.oxfmtrc.json、.oxlintrc.json - 配置VSCode推荐插件和前端构建工具链 - 实现文件服务FileService和相关业务逻辑
This commit is contained in:
@@ -0,0 +1,147 @@
|
||||
<script setup lang="ts">
|
||||
import {ref, onUnmounted} from "vue";
|
||||
import {
|
||||
files_rename,
|
||||
music_rename,
|
||||
image_hasTorrent,
|
||||
video_hasTorrent,
|
||||
video_deduplication,
|
||||
torrent_deduplication,
|
||||
video_findDeduplication,
|
||||
torrent_statistics
|
||||
} from "@/api"
|
||||
|
||||
// 警告项接口
|
||||
interface messageItem {
|
||||
id: number
|
||||
text: string
|
||||
}
|
||||
|
||||
interface BtnItem {
|
||||
id: number
|
||||
title: string
|
||||
handle?: () => Promise<any>
|
||||
}
|
||||
|
||||
let 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: files_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://localhost:5000/api/book/download")
|
||||
return
|
||||
}
|
||||
loading.value = true
|
||||
try {
|
||||
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", (event) => {
|
||||
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', (event) => {
|
||||
console.log('连接断开或失败', new Date());
|
||||
// 如果这里也频繁触发,确认了是断连重连
|
||||
if (eventSource.readyState === EventSource.CLOSED) {
|
||||
console.log('状态为 CLOSED');
|
||||
}
|
||||
})
|
||||
}
|
||||
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="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>
|
||||
Reference in New Issue
Block a user