mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-09-08 01:06:41 +08:00
style: Update CustomRuleCard.vue to include rule name field
This commit is contained in:
@@ -26,15 +26,20 @@ const ruleInfo = ref<CustomRule>({
|
|||||||
publish_time: '',
|
publish_time: '',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 规则名称
|
||||||
|
const ruleName = ref('')
|
||||||
|
|
||||||
// 打开详情弹窗
|
// 打开详情弹窗
|
||||||
function openRuleInfoDialog() {
|
function openRuleInfoDialog() {
|
||||||
ruleInfo.value = props.rule
|
ruleInfo.value = props.rule
|
||||||
|
ruleName.value = props.rule.name
|
||||||
ruleInfoDialog.value = true
|
ruleInfoDialog.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存详情数据
|
// 保存详情数据
|
||||||
function saveRuleInfo() {
|
function saveRuleInfo() {
|
||||||
ruleInfoDialog.value = false
|
ruleInfoDialog.value = false
|
||||||
|
ruleInfo.value.name = ruleName.value
|
||||||
emit('change', ruleInfo.value)
|
emit('change', ruleInfo.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,7 +68,7 @@ function onClose() {
|
|||||||
<VForm>
|
<VForm>
|
||||||
<VRow>
|
<VRow>
|
||||||
<VCol cols="12">
|
<VCol cols="12">
|
||||||
<VTextField v-model="ruleInfo.name" label="规则名称" />
|
<VTextField v-model="ruleName" label="规则名称" />
|
||||||
</VCol>
|
</VCol>
|
||||||
<VCol cols="12">
|
<VCol cols="12">
|
||||||
<VTextField v-model="ruleInfo.include" placeholder="关键字/正则表达式" label="包含" />
|
<VTextField v-model="ruleInfo.include" placeholder="关键字/正则表达式" label="包含" />
|
||||||
|
|||||||
@@ -1,2 +1,239 @@
|
|||||||
<script setup lang="ts"></script>
|
<script lang="ts" setup>
|
||||||
<template></template>
|
import draggable from 'vuedraggable'
|
||||||
|
import { copyToClipboard } from '@/@core/utils/navigator'
|
||||||
|
import { FilterRuleGroup } from '@/api/types'
|
||||||
|
import FilterRuleCard from '@/components/cards/FilterRuleCard.vue'
|
||||||
|
import { useToast } from 'vue-toast-notification'
|
||||||
|
import ImportCodeDialog from '@/components/dialog/ImportCodeDialog.vue'
|
||||||
|
|
||||||
|
// 输入参数
|
||||||
|
const props = defineProps({
|
||||||
|
group: {
|
||||||
|
type: Object as PropType<FilterRuleGroup>,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// 规则卡片类型
|
||||||
|
interface FilterCard {
|
||||||
|
// 优先级
|
||||||
|
pri: string
|
||||||
|
// 已选规则
|
||||||
|
rules: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提示框
|
||||||
|
const $toast = useToast()
|
||||||
|
|
||||||
|
// 定义触发的自定义事件
|
||||||
|
const emit = defineEmits(['close', 'change'])
|
||||||
|
|
||||||
|
// 规则详情弹窗
|
||||||
|
const groupInfoDialog = ref(false)
|
||||||
|
|
||||||
|
// 规则详情
|
||||||
|
const groupInfo = ref<FilterRuleGroup>({
|
||||||
|
name: '',
|
||||||
|
rule_string: '',
|
||||||
|
media_type: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
// 规则组名称
|
||||||
|
const groupName = ref('')
|
||||||
|
|
||||||
|
// 媒体类型字典
|
||||||
|
const mediaTypeItems = [
|
||||||
|
{ title: '通用', value: '' },
|
||||||
|
{ title: '电影', value: '电影' },
|
||||||
|
{ title: '电视剧', value: '电视剧' },
|
||||||
|
]
|
||||||
|
|
||||||
|
// 规则组规则卡片列表
|
||||||
|
const filterRuleCards = ref<FilterCard[]>([])
|
||||||
|
|
||||||
|
// 导入代码弹窗
|
||||||
|
const importCodeDialog = ref(false)
|
||||||
|
|
||||||
|
// 导入的代码
|
||||||
|
const importCodeString = ref('')
|
||||||
|
|
||||||
|
// 更新规则卡片的值
|
||||||
|
function updateFilterCardValue(pri: string, rules: string[]) {
|
||||||
|
const card = filterRuleCards.value.find(card => card.pri === pri)
|
||||||
|
if (card) card.rules = rules
|
||||||
|
}
|
||||||
|
|
||||||
|
// 移除卡片
|
||||||
|
function filterCardClose(pri: string) {
|
||||||
|
// 将pri对应的卡片从列表中删除,并更新剩余卡片的序号
|
||||||
|
const updatedCards = filterRuleCards.value
|
||||||
|
.filter(card => card.pri !== pri)
|
||||||
|
.map((card, index) => {
|
||||||
|
card.pri = (index + 1).toString()
|
||||||
|
return card
|
||||||
|
})
|
||||||
|
// 更新 filterRuleCards.value
|
||||||
|
filterRuleCards.value = updatedCards
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分享规则
|
||||||
|
function shareRules() {
|
||||||
|
// 有值才处理
|
||||||
|
if (filterRuleCards.value.length === 0) return
|
||||||
|
|
||||||
|
// 将卡片规则接装为字符串
|
||||||
|
const value = filterRuleCards.value
|
||||||
|
.filter(card => card.rules.length > 0)
|
||||||
|
.map(card => card.rules.join('&'))
|
||||||
|
.join('>')
|
||||||
|
|
||||||
|
// 复制到剪贴板
|
||||||
|
try {
|
||||||
|
copyToClipboard(value)
|
||||||
|
$toast.success('优先级规则已复制到剪贴板')
|
||||||
|
} catch (error) {
|
||||||
|
$toast.error('优先级规则复制失败!')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导入规则
|
||||||
|
async function importRules() {
|
||||||
|
importCodeString.value = ''
|
||||||
|
importCodeDialog.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听导入代码变化
|
||||||
|
watchEffect(() => {
|
||||||
|
if (!importCodeString.value) return
|
||||||
|
// 导入代码需要以空格开头和结束,没有则拼接
|
||||||
|
if (!importCodeString.value.startsWith(' ')) importCodeString.value = ` ${importCodeString.value}`
|
||||||
|
if (!importCodeString.value.endsWith(' ')) importCodeString.value = `${importCodeString.value} `
|
||||||
|
// 将导入的代码转换为规则卡片
|
||||||
|
const groups = importCodeString.value.split('>')
|
||||||
|
filterRuleCards.value = groups.map((group: string, index: number) => {
|
||||||
|
return {
|
||||||
|
pri: (index + 1).toString(),
|
||||||
|
rules: group.split('&'),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// 增加卡片
|
||||||
|
function addFilterCard() {
|
||||||
|
// 优先级
|
||||||
|
const pri = (filterRuleCards.value.length + 1).toString()
|
||||||
|
|
||||||
|
// 新卡片
|
||||||
|
const newCard: FilterCard = { pri, rules: [] }
|
||||||
|
|
||||||
|
// 添加到列表
|
||||||
|
filterRuleCards.value.push(newCard)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据列表的拖动顺序更新优先级
|
||||||
|
function dragOrderEnd() {
|
||||||
|
filterRuleCards.value.map((card, index) => {
|
||||||
|
card.pri = (index + 1).toString()
|
||||||
|
return card
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打开详情弹窗
|
||||||
|
function opengroupInfoDialog() {
|
||||||
|
groupInfo.value = props.group
|
||||||
|
groupName.value = props.group.name
|
||||||
|
if (props.group.rule_string) {
|
||||||
|
filterRuleCards.value = props.group.rule_string.split('>').map((group: string, index: number) => {
|
||||||
|
return {
|
||||||
|
pri: (index + 1).toString(),
|
||||||
|
rules: group.split('&'),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
groupInfoDialog.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存详情数据
|
||||||
|
function savegroupInfo() {
|
||||||
|
groupInfoDialog.value = false
|
||||||
|
groupInfo.value.name = groupName.value
|
||||||
|
// 更新到 groupInfo的rule_string
|
||||||
|
groupInfo.value.rule_string = filterRuleCards.value
|
||||||
|
.filter(card => card.rules.length > 0)
|
||||||
|
.map(card => card.rules.join('&'))
|
||||||
|
.join('>')
|
||||||
|
emit('change', groupInfo.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按钮点击
|
||||||
|
function onClose() {
|
||||||
|
emit('close')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<VCard variant="tonal" @click="opengroupInfoDialog">
|
||||||
|
<DialogCloseBtn @click="onClose" />
|
||||||
|
<VCardText class="flex justify-space-between align-center gap-3">
|
||||||
|
<div class="align-self-start">
|
||||||
|
<h5 class="text-h6 mb-1">{{ props.group.name }}</h5>
|
||||||
|
<div class="text-body-1 mb-3">{{ props.group.media_type || '通用' }}</div>
|
||||||
|
</div>
|
||||||
|
</VCardText>
|
||||||
|
</VCard>
|
||||||
|
<VDialog v-model="groupInfoDialog" scrollable max-width="80rem">
|
||||||
|
<VCard :title="`${props.group.name} - 配置`" class="rounded-t">
|
||||||
|
<DialogCloseBtn v-model="groupInfoDialog" />
|
||||||
|
<VDivider />
|
||||||
|
<VCardText>
|
||||||
|
<VRow>
|
||||||
|
<VCol cols="12" md="6">
|
||||||
|
<VTextField v-model="groupName" label="规则组名称" />
|
||||||
|
</VCol>
|
||||||
|
<VCol cols="12" md="6">
|
||||||
|
<VSelect v-model="groupInfo.media_type" label="适用媒体类型" :items="mediaTypeItems" />
|
||||||
|
</VCol>
|
||||||
|
</VRow>
|
||||||
|
</VCardText>
|
||||||
|
<VCardText>
|
||||||
|
<draggable
|
||||||
|
v-model="filterRuleCards"
|
||||||
|
handle=".cursor-move"
|
||||||
|
item-key="pri"
|
||||||
|
tag="div"
|
||||||
|
@end="dragOrderEnd"
|
||||||
|
:component-data="{ 'class': 'grid gap-3 grid-filterrule-card' }"
|
||||||
|
>
|
||||||
|
<template #item="{ element }">
|
||||||
|
<FilterRuleCard
|
||||||
|
:pri="element.pri"
|
||||||
|
:maxpri="filterRuleCards.length.toString()"
|
||||||
|
:rules="element.rules"
|
||||||
|
@changed="updateFilterCardValue"
|
||||||
|
@close="filterCardClose(element.pri)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</draggable>
|
||||||
|
<div class="text-center" v-if="filterRuleCards.length == 0">请添加或导入规则</div>
|
||||||
|
</VCardText>
|
||||||
|
<VCardActions class="pt-3">
|
||||||
|
<VBtn color="primary" variant="tonal" @click="addFilterCard">
|
||||||
|
<VIcon icon="mdi-plus" />
|
||||||
|
</VBtn>
|
||||||
|
<VBtn color="success" variant="tonal" @click="importRules">
|
||||||
|
<VIcon icon="mdi-import" />
|
||||||
|
</VBtn>
|
||||||
|
<VBtn color="info" variant="tonal" @click="shareRules">
|
||||||
|
<VIcon icon="mdi-share" />
|
||||||
|
</VBtn>
|
||||||
|
<VSpacer />
|
||||||
|
<VBtn @click="savegroupInfo" variant="elevated" prepend-icon="mdi-content-save" class="px-5"> 确定 </VBtn>
|
||||||
|
</VCardActions>
|
||||||
|
</VCard>
|
||||||
|
</VDialog>
|
||||||
|
<VDialog v-model="importCodeDialog" width="60rem" scrollable>
|
||||||
|
<ImportCodeDialog v-model="importCodeString" title="导入优先级规则" @close="importCodeDialog = false" />
|
||||||
|
</VDialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|||||||
@@ -22,8 +22,9 @@ const $toast = useToast()
|
|||||||
|
|
||||||
// 种子优先规则下拉框
|
// 种子优先规则下拉框
|
||||||
const TorrentPriorityItems = [
|
const TorrentPriorityItems = [
|
||||||
{ title: '站点优先', value: 'site' },
|
{ title: '站点排序优先', value: 'site' },
|
||||||
{ title: '做种数优先', value: 'seeder' },
|
{ title: '站点上传量优先', value: 'upload' },
|
||||||
|
{ title: '资源做种数优先', value: 'seeder' },
|
||||||
]
|
]
|
||||||
|
|
||||||
// 加载自定义规则
|
// 加载自定义规则
|
||||||
@@ -105,6 +106,12 @@ function removeFilterRuleGroup(rule: FilterRuleGroup) {
|
|||||||
if (index !== -1) filterRuleGroups.value.splice(index, 1)
|
if (index !== -1) filterRuleGroups.value.splice(index, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 规则组变化时赋值
|
||||||
|
function changeRuleGroup(group: FilterRuleGroup) {
|
||||||
|
const index = filterRuleGroups.value.findIndex(item => item.name === group.name)
|
||||||
|
if (index !== -1) filterRuleGroups.value[index] = group
|
||||||
|
}
|
||||||
|
|
||||||
// 查询种子优先规则
|
// 查询种子优先规则
|
||||||
async function queryTorrentPriority() {
|
async function queryTorrentPriority() {
|
||||||
try {
|
try {
|
||||||
@@ -181,10 +188,10 @@ onMounted(() => {
|
|||||||
handle=".cursor-move"
|
handle=".cursor-move"
|
||||||
item-key="name"
|
item-key="name"
|
||||||
tag="div"
|
tag="div"
|
||||||
:component-data="{ 'class': 'grid gap-3 grid-filterrule-card' }"
|
:component-data="{ 'class': 'grid gap-3 grid-app-card' }"
|
||||||
>
|
>
|
||||||
<template #item="{ element }">
|
<template #item="{ element }">
|
||||||
<FilterRuleGroupCard :filterrule="element" @close="removeFilterRuleGroup(element)" />
|
<FilterRuleGroupCard :group="element" @close="removeFilterRuleGroup(element)" @change="changeRuleGroup" />
|
||||||
</template>
|
</template>
|
||||||
</draggable>
|
</draggable>
|
||||||
</VCardText>
|
</VCardText>
|
||||||
|
|||||||
Reference in New Issue
Block a user