blob: d99b446ca64779e748c4154205ae720ee75d1be1 [file] [log] [blame]
<template>
<div class="upload-page">
<div class="page-header">
<h1>上传种子</h1>
<p class="page-description">分享你的资源,为社区做贡献</p>
</div>
<div class="upload-form">
<el-form
ref="uploadFormRef"
:model="uploadForm"
:rules="formRules"
label-width="120px"
size="large"
>
<!-- 种子文件上传 -->
<el-form-item label="种子文件" prop="torrentFile" required>
<el-upload
ref="torrentUploadRef"
:auto-upload="false"
:limit="1"
accept=".torrent"
:on-change="handleTorrentChange"
:on-remove="handleTorrentRemove"
:before-upload="beforeTorrentUpload"
drag
class="torrent-upload"
>
<el-icon class="el-icon--upload"><UploadFilled /></el-icon>
<div class="el-upload__text">
将 .torrent 文件拖到此处,或<em>点击上传</em>
</div>
<template #tip>
<div class="el-upload__tip">
只能上传 .torrent 文件,且不超过 10MB
</div>
</template>
</el-upload>
</el-form-item>
<!-- 基本信息 -->
<el-form-item label="资源标题" prop="title" required>
<el-input
v-model="uploadForm.title"
placeholder="请输入资源标题"
maxlength="200"
show-word-limit
/>
</el-form-item>
<el-form-item label="资源分类" prop="category" required>
<el-select v-model="uploadForm.category" placeholder="请选择分类">
<el-option label="电影" value="movie" />
<el-option label="电视剧" value="tv" />
<el-option label="音乐" value="music" />
<el-option label="软件" value="software" />
<el-option label="游戏" value="game" />
<el-option label="电子书" value="ebook" />
<el-option label="其他" value="other" />
</el-select>
</el-form-item>
<el-form-item label="子分类" prop="subcategory">
<el-select v-model="uploadForm.subcategory" placeholder="请选择子分类">
<el-option
v-for="sub in getSubcategories(uploadForm.category)"
:key="sub.value"
:label="sub.label"
:value="sub.value"
/>
</el-select>
</el-form-item>
<!-- 详细描述 -->
<el-form-item label="资源描述" prop="description">
<el-input
v-model="uploadForm.description"
type="textarea"
:rows="6"
placeholder="请详细描述资源内容,包括格式、质量、语言等信息"
maxlength="2000"
show-word-limit
/>
</el-form-item>
<!-- 标签 -->
<el-form-item label="标签">
<div class="tags-input">
<el-tag
v-for="tag in uploadForm.tags"
:key="tag"
closable
@close="removeTag(tag)"
class="tag-item"
>
{{ tag }}
</el-tag>
<el-input
v-if="tagInputVisible"
ref="tagInputRef"
v-model="tagInputValue"
size="small"
@keyup.enter="addTag"
@blur="addTag"
class="tag-input"
/>
<el-button
v-else
size="small"
@click="showTagInput"
class="add-tag-btn"
>
+ 添加标签
</el-button>
</div>
</el-form-item>
<!-- 封面图片 -->
<el-form-item label="封面图片">
<el-upload
ref="imageUploadRef"
:auto-upload="false"
:limit="1"
accept="image/*"
:on-change="handleImageChange"
:on-remove="handleImageRemove"
list-type="picture-card"
class="image-upload"
>
<el-icon><Plus /></el-icon>
<template #tip>
<div class="el-upload__tip">
支持 JPG、PNG 格式,建议尺寸 300x400,不超过 5MB
</div>
</template>
</el-upload>
</el-form-item>
<!-- 高级选项 -->
<el-form-item>
<el-collapse>
<el-collapse-item title="高级选项" name="advanced">
<el-form-item label="免费时间">
<el-select v-model="uploadForm.freeTime" placeholder="选择免费时间">
<el-option label="永久免费" value="forever" />
<el-option label="24小时" value="24h" />
<el-option label="48小时" value="48h" />
<el-option label="7天" value="7d" />
<el-option label="30天" value="30d" />
</el-select>
</el-form-item>
<el-form-item label="匿名上传">
<el-switch v-model="uploadForm.anonymous" />
<span class="form-tip">开启后将不显示上传者信息</span>
</el-form-item>
<el-form-item label="允许HR">
<el-switch v-model="uploadForm.allowHR" />
<span class="form-tip">允许此种子参与HR考核</span>
</el-form-item>
</el-collapse-item>
</el-collapse>
</el-form-item>
<!-- 提交按钮 -->
<el-form-item>
<div class="submit-buttons">
<el-button @click="resetForm">重置</el-button>
<el-button type="primary" @click="submitForm" :loading="uploading">
{{ uploading ? '上传中...' : '提交种子' }}
</el-button>
</div>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script>
import { ref, reactive, nextTick } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import {
UploadFilled,
Plus
} from '@element-plus/icons-vue'
export default {
name: 'UploadView',
setup() {
const router = useRouter()
const uploadFormRef = ref(null)
const torrentUploadRef = ref(null)
const imageUploadRef = ref(null)
const tagInputRef = ref(null)
const uploading = ref(false)
const tagInputVisible = ref(false)
const tagInputValue = ref('')
const uploadForm = reactive({
torrentFile: null,
title: '',
category: '',
subcategory: '',
description: '',
tags: [],
coverImage: null,
freeTime: '',
anonymous: false,
allowHR: true
})
const formRules = {
title: [
{ required: true, message: '请输入资源标题', trigger: 'blur' },
{ min: 5, max: 200, message: '标题长度在 5 到 200 个字符', trigger: 'blur' }
],
category: [
{ required: true, message: '请选择资源分类', trigger: 'change' }
],
description: [
{ min: 10, max: 2000, message: '描述长度在 10 到 2000 个字符', trigger: 'blur' }
]
}
const subcategories = {
movie: [
{ label: '动作片', value: 'action' },
{ label: '喜剧片', value: 'comedy' },
{ label: '科幻片', value: 'scifi' },
{ label: '恐怖片', value: 'horror' },
{ label: '剧情片', value: 'drama' }
],
tv: [
{ label: '美剧', value: 'us' },
{ label: '国产剧', value: 'cn' },
{ label: '日韩剧', value: 'asia' },
{ label: '英剧', value: 'uk' },
{ label: '纪录片', value: 'documentary' }
],
music: [
{ label: '流行音乐', value: 'pop' },
{ label: '古典音乐', value: 'classical' },
{ label: '摇滚音乐', value: 'rock' },
{ label: '电子音乐', value: 'electronic' },
{ label: '其他', value: 'other' }
],
software: [
{ label: '操作系统', value: 'os' },
{ label: '办公软件', value: 'office' },
{ label: '开发工具', value: 'dev' },
{ label: '设计软件', value: 'design' },
{ label: '其他', value: 'other' }
],
game: [
{ label: 'PC游戏', value: 'pc' },
{ label: '主机游戏', value: 'console' },
{ label: '手机游戏', value: 'mobile' },
{ label: '其他', value: 'other' }
]
}
const getSubcategories = (category) => {
return subcategories[category] || []
}
const handleTorrentChange = (file) => {
uploadForm.torrentFile = file.raw
// 这里可以解析torrent文件获取基本信息
parseTorrentFile(file.raw)
}
const handleTorrentRemove = () => {
uploadForm.torrentFile = null
}
const beforeTorrentUpload = (file) => {
const isTorrent = file.type === 'application/x-bittorrent' || file.name.endsWith('.torrent')
const isLt10M = file.size / 1024 / 1024 < 10
if (!isTorrent) {
ElMessage.error('只能上传 .torrent 文件!')
return false
}
if (!isLt10M) {
ElMessage.error('种子文件大小不能超过 10MB!')
return false
}
return true
}
const parseTorrentFile = (file) => {
// 这里应该实现torrent文件解析
// 可以使用 parse-torrent 库
console.log('解析种子文件:', file.name)
// 模拟解析结果自动填入表单
if (!uploadForm.title) {
uploadForm.title = file.name.replace('.torrent', '')
}
}
const handleImageChange = (file) => {
uploadForm.coverImage = file.raw
}
const handleImageRemove = () => {
uploadForm.coverImage = null
}
const showTagInput = () => {
tagInputVisible.value = true
nextTick(() => {
tagInputRef.value?.focus()
})
}
const addTag = () => {
const tag = tagInputValue.value.trim()
if (tag && !uploadForm.tags.includes(tag)) {
uploadForm.tags.push(tag)
}
tagInputVisible.value = false
tagInputValue.value = ''
}
const removeTag = (tag) => {
const index = uploadForm.tags.indexOf(tag)
if (index > -1) {
uploadForm.tags.splice(index, 1)
}
}
const submitForm = async () => {
if (!uploadForm.torrentFile) {
ElMessage.error('请上传种子文件')
return
}
try {
await uploadFormRef.value?.validate()
uploading.value = true
// 模拟上传过程
await new Promise(resolve => setTimeout(resolve, 2000))
ElMessage.success('种子上传成功!')
router.push('/torrents')
} catch (error) {
console.error('表单验证失败:', error)
} finally {
uploading.value = false
}
}
const resetForm = () => {
uploadFormRef.value?.resetFields()
uploadForm.torrentFile = null
uploadForm.coverImage = null
uploadForm.tags = []
torrentUploadRef.value?.clearFiles()
imageUploadRef.value?.clearFiles()
}
return {
uploadFormRef,
torrentUploadRef,
imageUploadRef,
tagInputRef,
uploading,
tagInputVisible,
tagInputValue,
uploadForm,
formRules,
getSubcategories,
handleTorrentChange,
handleTorrentRemove,
beforeTorrentUpload,
handleImageChange,
handleImageRemove,
showTagInput,
addTag,
removeTag,
submitForm,
resetForm,
UploadFilled,
Plus
}
}
}
</script>
<style lang="scss" scoped>
.upload-page {
max-width: 800px;
margin: 0 auto;
padding: 24px;
}
.page-header {
text-align: center;
margin-bottom: 32px;
h1 {
font-size: 28px;
font-weight: 600;
color: #2c3e50;
margin: 0 0 8px 0;
}
.page-description {
font-size: 16px;
color: #7f8c8d;
margin: 0;
}
}
.upload-form {
background: #fff;
border-radius: 12px;
padding: 32px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
.torrent-upload {
width: 100%;
:deep(.el-upload-dragger) {
width: 100%;
height: 180px;
border: 2px dashed #d9d9d9;
border-radius: 8px;
&:hover {
border-color: #409eff;
}
}
}
.tags-input {
display: flex;
flex-wrap: wrap;
gap: 8px;
align-items: center;
.tag-item {
margin: 0;
}
.tag-input {
width: 100px;
}
.add-tag-btn {
border: 1px dashed #d9d9d9;
color: #999;
&:hover {
border-color: #409eff;
color: #409eff;
}
}
}
.image-upload {
:deep(.el-upload--picture-card) {
width: 148px;
height: 148px;
}
}
.form-tip {
margin-left: 8px;
font-size: 12px;
color: #909399;
}
.submit-buttons {
display: flex;
gap: 16px;
justify-content: center;
margin-top: 24px;
}
}
@media (max-width: 768px) {
.upload-page {
padding: 16px;
}
.upload-form {
padding: 24px 16px;
}
.submit-buttons {
flex-direction: column;
.el-button {
width: 100%;
}
}
}
</style>