mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-09-07 00:36:41 +08:00
feat(settings): AccountSettingRule
- 增加防抖。 - `card` 从父组件获取到的值改为深复制,解决 `card` 内修改数据,会直接导致在父组件中同步更新的问题。 - 修复 规则id与name 只缺少一项时,仍能正常确定的问题。 - 保存前增加一次检查,避免通过分享导入的规则存在重名与空名引发的错误。
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
import { CustomRule } from '@/api/types'
|
import { CustomRule } from '@/api/types'
|
||||||
import { useToast } from 'vue-toast-notification'
|
import { useToast } from 'vue-toast-notification'
|
||||||
import filter_svg from '@images/svg/filter.svg'
|
import filter_svg from '@images/svg/filter.svg'
|
||||||
|
import { cloneDeep } from 'lodash'
|
||||||
|
|
||||||
// 输入参数
|
// 输入参数
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -37,50 +38,41 @@ const ruleInfo = ref<CustomRule>({
|
|||||||
publish_time: '',
|
publish_time: '',
|
||||||
})
|
})
|
||||||
|
|
||||||
// 规则ID
|
|
||||||
const ruleId = ref('')
|
|
||||||
|
|
||||||
// 规则名称
|
|
||||||
const ruleName = ref('')
|
|
||||||
|
|
||||||
// 打开详情弹窗
|
// 打开详情弹窗
|
||||||
function openRuleInfoDialog() {
|
function openRuleInfoDialog() {
|
||||||
ruleInfo.value = props.rule
|
// 深复制
|
||||||
ruleId.value = props.rule.id
|
ruleInfo.value = cloneDeep(props.rule)
|
||||||
ruleName.value = props.rule.name
|
|
||||||
ruleInfoDialog.value = true
|
ruleInfoDialog.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存详情数据
|
// 保存详情数据
|
||||||
function saveRuleInfo() {
|
function saveRuleInfo() {
|
||||||
// 有空值
|
// 有空值
|
||||||
if (!ruleId.value && !ruleName.value) {
|
if (!ruleInfo.value.id || !ruleInfo.value.name) {
|
||||||
if (!ruleId.value && ruleName.value) {
|
if (!ruleInfo.value.id && ruleInfo.value.name) {
|
||||||
$toast.error('规则ID不能为空')
|
$toast.error('规则ID不能为空')
|
||||||
}
|
}
|
||||||
if (ruleId.value && !ruleName.value) {
|
if (ruleInfo.value.id && !ruleInfo.value.name) {
|
||||||
$toast.error('规则名称不能为空')
|
$toast.error('规则名称不能为空')
|
||||||
}
|
}
|
||||||
if (!ruleId.value && !ruleName.value) {
|
if (!ruleInfo.value.id && !ruleInfo.value.name) {
|
||||||
$toast.error('规则ID和规则名称不能为空')
|
$toast.error('规则ID和规则名称不能为空')
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// ID已存在
|
// ID已存在
|
||||||
if (ruleId.value !== props.rule.id && props.rules.find(rule => rule.id === ruleId.value)) {
|
if (ruleInfo.value.id !== props.rule.id && props.rules.find(rule => rule.id === ruleInfo.value.id)) {
|
||||||
$toast.error(`规则ID【${ruleId.value}】已存在,请替换`)
|
$toast.error(`规则ID【${ruleInfo.value.id}】已存在,请替换`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 规则名称已存在
|
// 规则名称已存在
|
||||||
if (ruleName.value !== props.rule.name && props.rules.find(rule => rule.name === ruleName.value)) {
|
if (ruleInfo.value.name !== props.rule.name && props.rules.find(rule => rule.name === ruleInfo.value.name)) {
|
||||||
$toast.error(`规则名称【${ruleName.value}】已存在,请替换`)
|
$toast.error(`规则名称【${ruleInfo.value.name}】已存在,请替换`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 保存数据
|
// 保存数据
|
||||||
ruleInfoDialog.value = false
|
ruleInfoDialog.value = false
|
||||||
ruleInfo.value.id = ruleId.value
|
emit('change', ruleInfo.value, props.rule.id)
|
||||||
ruleInfo.value.name = ruleName.value
|
|
||||||
emit('change', ruleInfo.value)
|
|
||||||
emit('done')
|
emit('done')
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,7 +99,7 @@ function onClose() {
|
|||||||
<VImg :src="filter_svg" cover class="mt-7" max-width="3rem" />
|
<VImg :src="filter_svg" cover class="mt-7" max-width="3rem" />
|
||||||
</VCardText>
|
</VCardText>
|
||||||
</VCard>
|
</VCard>
|
||||||
<VDialog v-model="ruleInfoDialog" scrollable max-width="40rem" persistent >
|
<VDialog v-model="ruleInfoDialog" scrollable max-width="40rem" persistent>
|
||||||
<VCard :title="`${props.rule.id} - 配置`" class="rounded-t">
|
<VCard :title="`${props.rule.id} - 配置`" class="rounded-t">
|
||||||
<DialogCloseBtn v-model="ruleInfoDialog" />
|
<DialogCloseBtn v-model="ruleInfoDialog" />
|
||||||
<VDivider />
|
<VDivider />
|
||||||
@@ -116,7 +108,7 @@ function onClose() {
|
|||||||
<VRow>
|
<VRow>
|
||||||
<VCol cols="12" md="6">
|
<VCol cols="12" md="6">
|
||||||
<VTextField
|
<VTextField
|
||||||
v-model="ruleId"
|
v-model="ruleInfo.id"
|
||||||
label="规则ID"
|
label="规则ID"
|
||||||
placeholder="必填;不可与其他规则ID重名"
|
placeholder="必填;不可与其他规则ID重名"
|
||||||
hint="字符与数字组合,不能含空格"
|
hint="字符与数字组合,不能含空格"
|
||||||
@@ -126,7 +118,7 @@ function onClose() {
|
|||||||
</VCol>
|
</VCol>
|
||||||
<VCol cols="12" md="6">
|
<VCol cols="12" md="6">
|
||||||
<VTextField
|
<VTextField
|
||||||
v-model="ruleName"
|
v-model="ruleInfo.name"
|
||||||
label="规则名称"
|
label="规则名称"
|
||||||
placeholder="必填;不可与其他规则名称重名"
|
placeholder="必填;不可与其他规则名称重名"
|
||||||
hint="使用别名便于区分规则"
|
hint="使用别名便于区分规则"
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import FilterRuleCard from '@/components/cards/FilterRuleCard.vue'
|
|||||||
import { useToast } from 'vue-toast-notification'
|
import { useToast } from 'vue-toast-notification'
|
||||||
import ImportCodeDialog from '@/components/dialog/ImportCodeDialog.vue'
|
import ImportCodeDialog from '@/components/dialog/ImportCodeDialog.vue'
|
||||||
import filter_group_svg from '@images/svg/filter-group.svg'
|
import filter_group_svg from '@images/svg/filter-group.svg'
|
||||||
|
import { cloneDeep } from 'lodash'
|
||||||
|
|
||||||
// 输入参数
|
// 输入参数
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -53,9 +54,6 @@ const groupInfo = ref<FilterRuleGroup>({
|
|||||||
category: props.group?.category,
|
category: props.group?.category,
|
||||||
})
|
})
|
||||||
|
|
||||||
// 规则组名称
|
|
||||||
const groupName = ref('')
|
|
||||||
|
|
||||||
// 媒体类型字典
|
// 媒体类型字典
|
||||||
const mediaTypeItems = [
|
const mediaTypeItems = [
|
||||||
{ title: '通用', value: '' },
|
{ title: '通用', value: '' },
|
||||||
@@ -88,15 +86,12 @@ function updateFilterCardValue(pri: string, rules: string[]) {
|
|||||||
|
|
||||||
// 移除卡片
|
// 移除卡片
|
||||||
function filterCardClose(pri: string) {
|
function filterCardClose(pri: string) {
|
||||||
// 将pri对应的卡片从列表中删除,并更新剩余卡片的序号
|
filterRuleCards.value = filterRuleCards.value
|
||||||
const updatedCards = filterRuleCards.value
|
|
||||||
.filter(card => card.pri !== pri)
|
.filter(card => card.pri !== pri)
|
||||||
.map((card, index) => {
|
.map((card, index) => {
|
||||||
card.pri = (index + 1).toString()
|
card.pri = (index + 1).toString()
|
||||||
return card
|
return card
|
||||||
})
|
})
|
||||||
// 更新 filterRuleCards.value
|
|
||||||
filterRuleCards.value = updatedCards
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 分享规则
|
// 分享规则
|
||||||
@@ -163,8 +158,8 @@ function dragOrderEnd() {
|
|||||||
|
|
||||||
// 打开详情弹窗
|
// 打开详情弹窗
|
||||||
function opengroupInfoDialog() {
|
function opengroupInfoDialog() {
|
||||||
groupInfo.value = props.group
|
// 深复制
|
||||||
groupName.value = props.group.name
|
groupInfo.value = cloneDeep(props.group)
|
||||||
if (props.group.rule_string) {
|
if (props.group.rule_string) {
|
||||||
filterRuleCards.value = props.group.rule_string.split('>').map((group: string, index: number) => {
|
filterRuleCards.value = props.group.rule_string.split('>').map((group: string, index: number) => {
|
||||||
return {
|
return {
|
||||||
@@ -177,26 +172,25 @@ function opengroupInfoDialog() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 保存详情数据
|
// 保存详情数据
|
||||||
function savegroupInfo() {
|
function saveGroupInfo() {
|
||||||
// 为空
|
// 为空
|
||||||
if (!groupName.value) {
|
if (!groupInfo.value.name) {
|
||||||
$toast.error('规则组名称不能为空')
|
$toast.error('规则组名称不能为空')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 重名判断
|
// 重名判断
|
||||||
if (props.groups.some(item => item.name === groupName.value && item !== props.group)) {
|
if (props.groups.some(item => item.name === groupInfo.value.name && item !== props.group)) {
|
||||||
$toast.error(`规则组名称【${groupName.value}】已存在,请替换`)
|
$toast.error(`规则组名称【${groupInfo.value.name}】已存在,请替换`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 保存
|
// 保存
|
||||||
groupInfoDialog.value = false
|
groupInfoDialog.value = false
|
||||||
groupInfo.value.name = groupName.value
|
|
||||||
// 更新到 groupInfo的rule_string
|
// 更新到 groupInfo的rule_string
|
||||||
groupInfo.value.rule_string = filterRuleCards.value
|
groupInfo.value.rule_string = filterRuleCards.value
|
||||||
.filter(card => card.rules.length > 0)
|
.filter(card => card.rules.length > 0)
|
||||||
.map(card => card.rules.join('&'))
|
.map(card => card.rules.join('&'))
|
||||||
.join('>')
|
.join('>')
|
||||||
emit('change', groupInfo.value)
|
emit('change', groupInfo.value, props.group.name)
|
||||||
emit('done')
|
emit('done')
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,7 +220,7 @@ function onClose() {
|
|||||||
<VImg :src="filter_group_svg" cover class="mt-10" max-width="3rem" />
|
<VImg :src="filter_group_svg" cover class="mt-10" max-width="3rem" />
|
||||||
</VCardText>
|
</VCardText>
|
||||||
</VCard>
|
</VCard>
|
||||||
<VDialog v-model="groupInfoDialog" scrollable max-width="80rem" persistent >
|
<VDialog v-model="groupInfoDialog" scrollable max-width="80rem" persistent>
|
||||||
<VCard :title="`${props.group.name} - 配置`" class="rounded-t">
|
<VCard :title="`${props.group.name} - 配置`" class="rounded-t">
|
||||||
<DialogCloseBtn v-model="groupInfoDialog" />
|
<DialogCloseBtn v-model="groupInfoDialog" />
|
||||||
<VDivider />
|
<VDivider />
|
||||||
@@ -234,7 +228,7 @@ function onClose() {
|
|||||||
<VRow>
|
<VRow>
|
||||||
<VCol cols="12" md="6">
|
<VCol cols="12" md="6">
|
||||||
<VTextField
|
<VTextField
|
||||||
v-model="groupName"
|
v-model="groupInfo.name"
|
||||||
label="规则组名称"
|
label="规则组名称"
|
||||||
placeholder="必填;不可与其他规则组重名"
|
placeholder="必填;不可与其他规则组重名"
|
||||||
hint="自定义规则组名称"
|
hint="自定义规则组名称"
|
||||||
@@ -297,7 +291,7 @@ function onClose() {
|
|||||||
<VIcon icon="mdi-share" />
|
<VIcon icon="mdi-share" />
|
||||||
</VBtn>
|
</VBtn>
|
||||||
<VSpacer />
|
<VSpacer />
|
||||||
<VBtn @click="savegroupInfo" variant="elevated" prepend-icon="mdi-content-save" class="px-5"> 确定 </VBtn>
|
<VBtn @click="saveGroupInfo" variant="elevated" prepend-icon="mdi-content-save" class="px-5"> 确定 </VBtn>
|
||||||
</VCardActions>
|
</VCardActions>
|
||||||
</VCard>
|
</VCard>
|
||||||
</VDialog>
|
</VDialog>
|
||||||
|
|||||||
@@ -9,6 +9,10 @@ import { CustomRule, FilterRuleGroup } from '@/api/types'
|
|||||||
import CustomerRuleCard from '@/components/cards/CustomRuleCard.vue'
|
import CustomerRuleCard from '@/components/cards/CustomRuleCard.vue'
|
||||||
import FilterRuleGroupCard from '@/components/cards/FilterRuleGroupCard.vue'
|
import FilterRuleGroupCard from '@/components/cards/FilterRuleGroupCard.vue'
|
||||||
import ImportCodeDialog from '@/components/dialog/ImportCodeDialog.vue'
|
import ImportCodeDialog from '@/components/dialog/ImportCodeDialog.vue'
|
||||||
|
import debounce from 'lodash/debounce'
|
||||||
|
|
||||||
|
// 防抖时间
|
||||||
|
const debounceTime = 500
|
||||||
|
|
||||||
// 自定义规则列表
|
// 自定义规则列表
|
||||||
const customRules = ref<CustomRule[]>([])
|
const customRules = ref<CustomRule[]>([])
|
||||||
@@ -52,7 +56,29 @@ async function loadMediaCategories() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 保存自定义规则
|
// 保存自定义规则
|
||||||
async function saveCustomRules() {
|
const saveCustomRules = debounce(async () => {
|
||||||
|
// 检查是否存在空id规则
|
||||||
|
if (customRules.value.some(item => !item.id)) {
|
||||||
|
$toast.error('存在空ID的规则!无法保存,请修改!')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 检查是否存在空的规则名称
|
||||||
|
if (customRules.value.some(item => !item.name)) {
|
||||||
|
$toast.error('存在空名字的规则!无法保存,请修改!')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 检查是否存在重名的规则ID
|
||||||
|
const ids = customRules.value.map(item => item.id)
|
||||||
|
if (new Set(ids).size !== ids.length) {
|
||||||
|
$toast.error('存在重复规则ID!无法保存,请修改!')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 检查是否存在重名规
|
||||||
|
const names = customRules.value.map(item => item.name)
|
||||||
|
if (new Set(names).size !== names.length) {
|
||||||
|
$toast.error('存在重复规则名称!无法保存,请修改!')
|
||||||
|
return
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
const result: { [key: string]: any } = await api.post('system/setting/CustomFilterRules', customRules.value)
|
const result: { [key: string]: any } = await api.post('system/setting/CustomFilterRules', customRules.value)
|
||||||
if (result.success) $toast.success('自定义规则保存成功')
|
if (result.success) $toast.success('自定义规则保存成功')
|
||||||
@@ -60,10 +86,10 @@ async function saveCustomRules() {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error)
|
console.log(error)
|
||||||
}
|
}
|
||||||
}
|
}, debounceTime)
|
||||||
|
|
||||||
// 添加自定义规则
|
// 添加自定义规则
|
||||||
function addCustomRule() {
|
const addCustomRule = debounce(async () => {
|
||||||
let id = `RULE${customRules.value.length + 1}`
|
let id = `RULE${customRules.value.length + 1}`
|
||||||
while (customRules.value.some(item => item.id === id)) {
|
while (customRules.value.some(item => item.id === id)) {
|
||||||
id = `RULE${parseInt(id.split('RULE')[1]) + 1}`
|
id = `RULE${parseInt(id.split('RULE')[1]) + 1}`
|
||||||
@@ -78,7 +104,7 @@ function addCustomRule() {
|
|||||||
include: '',
|
include: '',
|
||||||
exclude: '',
|
exclude: '',
|
||||||
})
|
})
|
||||||
}
|
}, debounceTime)
|
||||||
|
|
||||||
// 移除自定义规则
|
// 移除自定义规则
|
||||||
function removeCustomRule(rule: CustomRule) {
|
function removeCustomRule(rule: CustomRule) {
|
||||||
@@ -97,7 +123,18 @@ async function queryFilterRuleGroups() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 保存规则组
|
// 保存规则组
|
||||||
async function saveFilterRuleGroups() {
|
const saveFilterRuleGroups = debounce(async () => {
|
||||||
|
// 检查是否存在空的规则组名称
|
||||||
|
if (filterRuleGroups.value.some(item => !item.name)) {
|
||||||
|
$toast.error('存在空名字的规则组!无法保存,请修改!')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 检查是否存在重名规则组
|
||||||
|
const names = filterRuleGroups.value.map(item => item.name)
|
||||||
|
if (new Set(names).size !== names.length) {
|
||||||
|
$toast.error('存在重复规则组名称!无法保存,请修改!')
|
||||||
|
return
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
const result: { [key: string]: any } = await api.post('system/setting/UserFilterRuleGroups', filterRuleGroups.value)
|
const result: { [key: string]: any } = await api.post('system/setting/UserFilterRuleGroups', filterRuleGroups.value)
|
||||||
if (result.success) $toast.success('优先级规则组保存成功')
|
if (result.success) $toast.success('优先级规则组保存成功')
|
||||||
@@ -105,10 +142,10 @@ async function saveFilterRuleGroups() {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error)
|
console.log(error)
|
||||||
}
|
}
|
||||||
}
|
}, debounceTime)
|
||||||
|
|
||||||
// 添加规则组
|
// 添加规则组
|
||||||
function addFilterRuleGroup() {
|
const addFilterRuleGroup = debounce(() => {
|
||||||
let name = `规则组${filterRuleGroups.value.length + 1}`
|
let name = `规则组${filterRuleGroups.value.length + 1}`
|
||||||
while (filterRuleGroups.value.some(item => item.name === name)) {
|
while (filterRuleGroups.value.some(item => item.name === name)) {
|
||||||
name = `规则组${parseInt(name.split('规则组')[1]) + 1}`
|
name = `规则组${parseInt(name.split('规则组')[1]) + 1}`
|
||||||
@@ -119,10 +156,11 @@ function addFilterRuleGroup() {
|
|||||||
media_type: '',
|
media_type: '',
|
||||||
category: '',
|
category: '',
|
||||||
})
|
})
|
||||||
}
|
}, debounceTime)
|
||||||
|
|
||||||
// 分享规则
|
// 分享规则
|
||||||
function shareRules(rules: CustomRule[] | FilterRuleGroup[]) {
|
// function shareRules(rules: CustomRule[] | FilterRuleGroup[]) {
|
||||||
|
const shareRules = debounce((rules: CustomRule[] | FilterRuleGroup[]) => {
|
||||||
if (!rules || rules.length === 0) return
|
if (!rules || rules.length === 0) return
|
||||||
|
|
||||||
// 将卡片规则接装为字符串
|
// 将卡片规则接装为字符串
|
||||||
@@ -135,7 +173,7 @@ function shareRules(rules: CustomRule[] | FilterRuleGroup[]) {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
$toast.error('优先级规则复制失败!')
|
$toast.error('优先级规则复制失败!')
|
||||||
}
|
}
|
||||||
}
|
}, debounceTime)
|
||||||
|
|
||||||
// 导入规则
|
// 导入规则
|
||||||
async function importRules(ruleType: string) {
|
async function importRules(ruleType: string) {
|
||||||
@@ -179,8 +217,8 @@ watchEffect(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// 规则变化时赋值
|
// 规则变化时赋值
|
||||||
function onRuleChange(rule: CustomRule) {
|
function onRuleChange(rule: CustomRule, id: string) {
|
||||||
const index = customRules.value.findIndex(item => item.id === rule.id)
|
const index = customRules.value.findIndex(item => item.id === id)
|
||||||
if (index !== -1) customRules.value[index] = rule
|
if (index !== -1) customRules.value[index] = rule
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,8 +229,8 @@ function removeFilterRuleGroup(rule: FilterRuleGroup) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 规则组变化时赋值
|
// 规则组变化时赋值
|
||||||
function changeRuleGroup(group: FilterRuleGroup) {
|
function changeRuleGroup(group: FilterRuleGroup, name: string) {
|
||||||
const index = filterRuleGroups.value.findIndex(item => item.name === group.name)
|
const index = filterRuleGroups.value.findIndex(item => item.name === name)
|
||||||
if (index !== -1) filterRuleGroups.value[index] = group
|
if (index !== -1) filterRuleGroups.value[index] = group
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,20 +256,18 @@ async function queryCustomRules() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 保存种子优先规则
|
// 保存种子优先规则
|
||||||
async function saveTorrentPriority() {
|
const saveTorrentPriority = debounce(async () => {
|
||||||
try {
|
try {
|
||||||
// 用户名密码
|
|
||||||
const result: { [key: string]: any } = await api.post(
|
const result: { [key: string]: any } = await api.post(
|
||||||
'system/setting/TorrentsPriority',
|
'system/setting/TorrentsPriority',
|
||||||
selectedTorrentPriority.value,
|
selectedTorrentPriority.value,
|
||||||
)
|
)
|
||||||
|
|
||||||
if (result.success) $toast.success('优先规则保存成功')
|
if (result.success) $toast.success('优先规则保存成功')
|
||||||
else $toast.error('优先规则保存失败!')
|
else $toast.error('优先规则保存失败!')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error)
|
console.log(error)
|
||||||
}
|
}
|
||||||
}
|
}, debounceTime)
|
||||||
|
|
||||||
// 加载数据
|
// 加载数据
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
|||||||
Reference in New Issue
Block a user