blob: 6b154323d469361bb05df306d6f644db67f558af [file] [log] [blame]
<template>
<div class="upload-page">
<div class="upload-container">
<h2>上传种子</h2>
<el-form
ref="uploadFormRef"
:model="uploadForm"
:rules="uploadRules"
label-width="120px"
class="upload-form"
>
<!-- 种子文件上传 -->
<el-form-item label="种子文件" prop="file">
<el-upload
ref="uploadRef"
:auto-upload="false"
:limit="1"
accept=".torrent"
:on-change="handleTorrentChange"
:on-remove="handleTorrentRemove"
:file-list="fileList"
>
<template #trigger>
<el-button type="primary">选择文件</el-button>
</template>
<template #tip>
<div class="el-upload__tip">
只能上传 .torrent 文件
</div>
</template>
</el-upload>
</el-form-item>
<!-- 基本信息 -->
<el-form-item label="标题" prop="title">
<el-input v-model="uploadForm.title" placeholder="请输入种子标题" />
</el-form-item>
<el-form-item label="副标题" prop="subtitle">
<el-input v-model="uploadForm.subtitle" placeholder="请输入副标题(可选)" />
</el-form-item>
<el-form-item label="分类" prop="category">
<el-select v-model="uploadForm.category" placeholder="请选择分类">
<el-option
v-for="category in categories"
:key="category.id"
:label="category.name"
:value="category.slug"
/>
</el-select>
</el-form-item>
<!-- 标签 -->
<el-form-item label="标签" prop="tag">
<el-select
v-model="uploadForm.tag"
multiple
filterable
allow-create
placeholder="请选择或输入标签"
>
<el-option
v-for="tag in availableTags"
:key="tag.id"
:label="tag.name"
:value="tag.name"
/>
</el-select>
</el-form-item>
<!-- 描述信息 -->
<el-form-item label="描述" prop="description">
<el-input
v-model="uploadForm.description"
type="textarea"
:rows="6"
placeholder="请输入种子描述,支持 Markdown 格式"
/>
</el-form-item>
<!-- 匿名发布 -->
<el-form-item>
<el-checkbox v-model="uploadForm.anonymous">匿名发布</el-checkbox>
</el-form-item>
<!-- 提交按钮 -->
<el-form-item>
<el-button type="primary" @click="submitUpload" :loading="uploading">
上传种子
</el-button>
<el-button @click="resetForm">重置表单</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script>
import { ref, reactive, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import { uploadTorrent, getCategories, getTags } from '@/api/torrent'
export default {
name: 'UploadView',
setup() {
const router = useRouter()
const uploadFormRef = ref(null)
const uploadRef = ref(null)
const uploading = ref(false)
const fileList = ref([])
const uploadForm = reactive({
title: '',
subtitle: '',
category: '',
tag: [],
description: '',
anonymous: false,
file: null
})
const uploadRules = {
title: [
{ required: true, message: '请输入种子标题', trigger: 'blur' },
{ min: 3, max: 100, message: '标题长度应在 3 到 100 个字符之间', trigger: 'blur' }
],
category: [
{ required: true, message: '请选择分类', trigger: 'change' }
],
description: [
{ required: true, message: '请输入种子描述', trigger: 'blur' },
{ min: 10, message: '描述至少需要 10 个字符', trigger: 'blur' }
],
file: [
{ required: true, message: '请上传种子文件', trigger: 'change' }
]
}
const categories = ref([])
const availableTags = ref([])
// 获取分类列表
const loadCategories = async () => {
try {
console.log('开始加载分类列表...')
console.log('当前token:', localStorage.getItem('token'))
const response = await getCategories()
console.log('分类列表响应:', response)
if (response && response.data) {
categories.value = response.data
console.log('分类列表加载成功:', categories.value)
} else {
console.warn('分类列表数据为空')
categories.value = []
}
} catch (error) {
console.error('Failed to load categories:', error)
console.error('错误详情:', {
message: error.message,
response: error.response?.data,
status: error.response?.status,
config: error.config
})
// 根据错误类型显示不同的提示
if (error.response?.status === 401) {
ElMessage.error('请先登录')
router.push('/login')
} else if (error.response?.status === 403) {
ElMessage.error('没有权限访问分类列表')
} else if (error.code === 'ERR_NETWORK') {
ElMessage.error('无法连接到服务器,请检查后端服务是否启动')
} else {
ElMessage.error(`获取分类列表失败: ${error.message}`)
}
}
}
// 获取标签列表
const loadTags = async () => {
try {
console.log('开始加载标签列表...')
const response = await getTags()
console.log('标签列表响应:', response)
if (response && response.data) {
availableTags.value = response.data
console.log('标签列表加载成功:', availableTags.value)
} else {
console.warn('标签列表数据为空')
availableTags.value = []
}
} catch (error) {
console.error('Failed to load tags:', error)
console.error('错误详情:', {
message: error.message,
response: error.response?.data,
status: error.response?.status
})
// 如果是网络错误,提供更详细的提示
if (error.code === 'ERR_NETWORK') {
ElMessage.error('无法连接到服务器,请检查后端服务是否启动')
} else {
ElMessage.error(`获取标签列表失败: ${error.message}`)
}
}
}
const handleTorrentChange = (file) => {
if (file) {
uploadForm.file = file.raw
fileList.value = [file]
// 自动校验文件字段
uploadFormRef.value?.validateField('file')
}
}
const handleTorrentRemove = () => {
uploadForm.file = null
fileList.value = []
}
const submitUpload = async () => {
if (!uploadForm.file) {
ElMessage.warning('请先选择种子文件')
return
}
try {
await uploadFormRef.value?.validate()
uploading.value = true
const formData = new FormData()
formData.append('file', uploadForm.file)
formData.append('title', uploadForm.title)
formData.append('subtitle', uploadForm.subtitle || '')
formData.append('category', uploadForm.category)
formData.append('description', uploadForm.description)
formData.append('anonymous', uploadForm.anonymous)
// 处理标签数组
if (uploadForm.tag && uploadForm.tag.length > 0) {
uploadForm.tag.forEach(tag => {
formData.append('tag', tag)
})
}
const response = await uploadTorrent(formData)
ElMessage.success('种子上传成功')
// 根据后端返回的数据跳转到种子详情页
if (response.data && response.data.infoHash) {
router.push(`/torrent/${response.data.infoHash}`)
} else {
router.push('/torrents') // 或者跳转到种子列表页
}
} catch (error) {
console.error('Failed to upload torrent:', error)
// 根据后端返回的错误信息显示不同的提示
let errorMessage = '种子上传失败'
if (error.response?.data?.message) {
errorMessage = error.response.data.message
} else if (error.response?.data?.error) {
errorMessage = error.response.data.error
}
ElMessage.error(errorMessage)
} finally {
uploading.value = false
}
}
const resetForm = () => {
uploadFormRef.value?.resetFields()
uploadRef.value?.clearFiles()
uploadForm.file = null
fileList.value = []
}
// 组件挂载时加载数据
onMounted(() => {
loadCategories()
loadTags()
})
return {
uploadFormRef,
uploadRef,
uploading,
uploadForm,
uploadRules,
categories,
availableTags,
fileList,
handleTorrentChange,
handleTorrentRemove,
submitUpload,
resetForm
}
}
}
</script>
<style lang="scss" scoped>
.upload-page {
max-width: 800px;
margin: 0 auto;
padding: 24px;
}
.upload-container {
background: #fff;
border-radius: 8px;
padding: 24px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
h2 {
margin: 0 0 24px;
padding-bottom: 16px;
border-bottom: 1px solid #eee;
color: #2c3e50;
}
}
.upload-form {
.el-upload {
width: 100%;
}
.el-upload__tip {
line-height: 1.2;
padding: 8px 0;
color: #909399;
}
}
@media (max-width: 768px) {
.upload-page {
padding: 16px;
}
.upload-container {
padding: 16px;
}
:deep(.el-form-item__label) {
float: none;
display: block;
text-align: left;
padding: 0 0 8px;
}
:deep(.el-form-item__content) {
margin-left: 0 !important;
}
}
</style>