Files
Qbit-Manager/frontend/src/components/AddTorrentDialog.vue
2025-07-18 15:46:07 +08:00

261 lines
6.6 KiB
Vue

<template>
<el-dialog
title="添加种子"
v-model="visible"
width="600px"
@close="resetForm"
>
<el-form
ref="formRef"
:model="form"
:rules="rules"
label-width="100px"
>
<el-form-item label="客户端" prop="clientId">
<el-select v-model="form.clientId" placeholder="选择客户端" style="width: 100%">
<el-option
v-for="client in connectedClients"
:key="client.id"
:label="client.name"
:value="client.id"
/>
</el-select>
</el-form-item>
<el-form-item label="添加方式">
<el-radio-group v-model="addMethod">
<el-radio value="file">种子文件</el-radio>
<el-radio value="magnet">磁力链接</el-radio>
<el-radio value="url">种子URL</el-radio>
</el-radio-group>
</el-form-item>
<!-- 种子文件上传 -->
<el-form-item v-if="addMethod === 'file'" label="种子文件" prop="torrentFile">
<el-upload
ref="uploadRef"
:auto-upload="false"
:show-file-list="true"
:limit="1"
accept=".torrent"
:on-change="handleFileChange"
:on-remove="handleFileRemove"
>
<el-button type="primary">选择文件</el-button>
<template #tip>
<div class="el-upload__tip">
只能上传 .torrent 文件
</div>
</template>
</el-upload>
</el-form-item>
<!-- 磁力链接 -->
<el-form-item v-if="addMethod === 'magnet'" label="磁力链接" prop="magnetLink">
<el-input
v-model="form.magnetLink"
type="textarea"
:rows="3"
placeholder="magnet:?xt=urn:btih:..."
/>
</el-form-item>
<!-- 种子URL -->
<el-form-item v-if="addMethod === 'url'" label="种子URL" prop="torrentUrl">
<el-input
v-model="form.torrentUrl"
placeholder="https://example.com/torrent.torrent"
/>
</el-form-item>
<!-- 可选设置 -->
<el-divider content-position="left">可选设置</el-divider>
<el-form-item label="分类">
<el-input v-model="form.category" placeholder="种子分类" />
</el-form-item>
<el-form-item label="标签">
<el-input v-model="form.tags" placeholder="用逗号分隔多个标签" />
</el-form-item>
<el-form-item label="保存路径">
<el-input v-model="form.savePath" placeholder="自定义保存路径" />
</el-form-item>
<el-form-item label="添加后暂停">
<el-switch v-model="form.paused" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="visible = false">取消</el-button>
<el-button type="primary" @click="submitForm" :loading="submitting">
添加种子
</el-button>
</template>
</el-dialog>
</template>
<script setup>
import { ref, computed, watch } from 'vue'
import { useClientsStore } from '@/stores/clients'
import { torrentsApi } from '@/api/torrents'
import { ElMessage } from 'element-plus'
// Props
const props = defineProps({
modelValue: {
type: Boolean,
default: false
}
})
// Emits
const emit = defineEmits(['update:modelValue', 'success'])
// Stores
const clientsStore = useClientsStore()
// 响应式数据
const visible = ref(false)
const addMethod = ref('file')
const submitting = ref(false)
const formRef = ref()
const uploadRef = ref()
const form = ref({
clientId: '',
torrentFile: null,
magnetLink: '',
torrentUrl: '',
category: '',
tags: '',
savePath: '',
paused: false
})
const rules = {
clientId: [
{ required: true, message: '请选择客户端', trigger: 'change' }
],
torrentFile: [
{ required: true, message: '请选择种子文件', trigger: 'change' }
],
magnetLink: [
{ required: true, message: '请输入磁力链接', trigger: 'blur' },
{ pattern: /^magnet:/, message: '请输入有效的磁力链接', trigger: 'blur' }
],
torrentUrl: [
{ required: true, message: '请输入种子URL', trigger: 'blur' },
{ type: 'url', message: '请输入有效的URL', trigger: 'blur' }
]
}
// 计算属性
const connectedClients = computed(() => clientsStore.connectedClients)
// 监听 modelValue 变化
watch(() => props.modelValue, (newVal) => {
visible.value = newVal
})
watch(visible, (newVal) => {
emit('update:modelValue', newVal)
})
// 监听添加方式变化,重置验证
watch(addMethod, () => {
if (formRef.value) {
formRef.value.clearValidate()
}
})
// 方法
const handleFileChange = (file) => {
form.value.torrentFile = file.raw
}
const handleFileRemove = () => {
form.value.torrentFile = null
}
const submitForm = async () => {
if (!formRef.value) return
try {
// 根据添加方式验证不同字段
const fieldsToValidate = ['clientId']
if (addMethod.value === 'file') fieldsToValidate.push('torrentFile')
if (addMethod.value === 'magnet') fieldsToValidate.push('magnetLink')
if (addMethod.value === 'url') fieldsToValidate.push('torrentUrl')
await formRef.value.validateField(fieldsToValidate)
submitting.value = true
const options = {
category: form.value.category,
tags: form.value.tags,
savePath: form.value.savePath,
paused: form.value.paused
}
let response
if (addMethod.value === 'file') {
response = await torrentsApi.addTorrentFile(form.value.clientId, form.value.torrentFile, options)
} else if (addMethod.value === 'magnet') {
response = await torrentsApi.addMagnetLink(form.value.clientId, form.value.magnetLink, options)
} else if (addMethod.value === 'url') {
response = await torrentsApi.addTorrentUrl(form.value.clientId, form.value.torrentUrl, options)
}
if (response.success) {
ElMessage.success(response.message || '种子添加成功')
visible.value = false
emit('success')
} else {
ElMessage.error(response.error || '添加失败')
}
} catch (error) {
ElMessage.error(`添加种子失败: ${error.message}`)
} finally {
submitting.value = false
}
}
const resetForm = () => {
form.value = {
clientId: '',
torrentFile: null,
magnetLink: '',
torrentUrl: '',
category: '',
tags: '',
savePath: '',
paused: false
}
addMethod.value = 'file'
if (formRef.value) {
formRef.value.resetFields()
}
if (uploadRef.value) {
uploadRef.value.clearFiles()
}
}
</script>
<style scoped>
.el-divider {
margin: 20px 0;
}
.el-upload__tip {
color: #909399;
font-size: 12px;
margin-top: 5px;
}
</style>