<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> |