mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-09-05 15:36:49 +08:00
feat 过滤规则设置
This commit is contained in:
@@ -0,0 +1,71 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
// 定义触发的自定义事件
|
||||||
|
const emit = defineEmits(["close", "changed"]);
|
||||||
|
|
||||||
|
// 输入参数
|
||||||
|
const props = defineProps({
|
||||||
|
pri: String,
|
||||||
|
rules: Array as PropType<string[]>,
|
||||||
|
width: String,
|
||||||
|
height: String,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 按钮点击
|
||||||
|
const onClose = () => {
|
||||||
|
emit("close");
|
||||||
|
};
|
||||||
|
|
||||||
|
// 选项变化
|
||||||
|
const filtersChanged = (value: string[]) => {
|
||||||
|
emit("changed", props.pri, value);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 过滤规则下拉框
|
||||||
|
const selectFilterOptions = ref<{ [key: string]: string }[]>([
|
||||||
|
{ title: "特效字幕", value: " SPECSUB ", color: "success" },
|
||||||
|
{ title: "中文字幕", value: " CNSUB ", color: "success" },
|
||||||
|
{ title: "分辨率: 4K", value: " 4K ", color: "success" },
|
||||||
|
{ title: "分辨率: 1080P", value: " 1080P ", color: "success" },
|
||||||
|
{ title: "蓝光原盘", value: " BLU ", color: "success" },
|
||||||
|
{ title: "排除蓝光原盘", value: " !BLU ", color: "error" },
|
||||||
|
{ title: "Remux", value: " REMUX ", color: "success" },
|
||||||
|
{ title: "排除Remux", value: " !REMUX ", color: "error" },
|
||||||
|
{ title: "WEB-DL", value: " WEBDL ", color: "success" },
|
||||||
|
{ title: "排除WEB-DL", value: " !WEBDL ", color: "error" },
|
||||||
|
{ title: "H265", value: " H265 ", color: "success" },
|
||||||
|
{ title: "排除H265", value: " !H265 ", color: "error" },
|
||||||
|
{ title: "H264", value: " H264 ", color: "success" },
|
||||||
|
{ title: "排除H264", value: " !H264 ", color: "error" },
|
||||||
|
{ title: "杜比", value: " DOLBY ", color: "success" },
|
||||||
|
{ title: "排除杜比", value: " !DOLBY ", color: "error" },
|
||||||
|
{ title: "HDR", value: " HDR ", color: "success" },
|
||||||
|
{ title: "排除HDR", value: " !HDR ", color: "error" },
|
||||||
|
{ title: "免费", value: " FREE ", color: "success" },
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 已选择的过滤规则
|
||||||
|
const selectedFilters = ref<string[]>(props.rules ?? []);
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<VCard variant="tonal" :width="props.width" :height="props.height">
|
||||||
|
<DialogCloseBtn @click="onClose" />
|
||||||
|
<VCardItem>
|
||||||
|
<VCardTitle>优先级 {{ props.pri }}</VCardTitle>
|
||||||
|
<VRow>
|
||||||
|
<VCol>
|
||||||
|
<VSelect
|
||||||
|
variant="underlined"
|
||||||
|
:key="props.pri"
|
||||||
|
v-model="selectedFilters"
|
||||||
|
:items="selectFilterOptions"
|
||||||
|
@update:modelValue="filtersChanged"
|
||||||
|
chips
|
||||||
|
label=""
|
||||||
|
multiple
|
||||||
|
>
|
||||||
|
</VSelect>
|
||||||
|
</VCol>
|
||||||
|
</VRow>
|
||||||
|
</VCardItem>
|
||||||
|
</VCard>
|
||||||
|
</template>
|
||||||
@@ -158,7 +158,7 @@ onMounted(() => {
|
|||||||
/>
|
/>
|
||||||
<VerticalNavLink
|
<VerticalNavLink
|
||||||
:item="{
|
:item="{
|
||||||
title: '站点',
|
title: '站点管理',
|
||||||
icon: 'mdi-web',
|
icon: 'mdi-web',
|
||||||
to: '/site',
|
to: '/site',
|
||||||
}"
|
}"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import AccountSettingAccount from "@/views/account-setting/AccountSettingAccount.vue";
|
import AccountSettingAccount from "@/views/account-setting/AccountSettingAccount.vue";
|
||||||
|
import AccountSettingFilter from "@/views/account-setting/AccountSettingFilter.vue";
|
||||||
import AccountSettingNotification from "@/views/account-setting/AccountSettingNotification.vue";
|
import AccountSettingNotification from "@/views/account-setting/AccountSettingNotification.vue";
|
||||||
import AccountSettingSystem from "@/views/account-setting/AccountSettingSystem.vue";
|
import AccountSettingSystem from "@/views/account-setting/AccountSettingSystem.vue";
|
||||||
import AccountSettingWords from "@/views/account-setting/AccountSettingWords.vue";
|
import AccountSettingWords from "@/views/account-setting/AccountSettingWords.vue";
|
||||||
@@ -11,9 +12,10 @@ const activeTab = ref(route.params.tab);
|
|||||||
|
|
||||||
// tabs
|
// tabs
|
||||||
const tabs = [
|
const tabs = [
|
||||||
{ title: "用户", icon: "mdi-account-outline", tab: "account" },
|
{ title: "用户", icon: "mdi-account", tab: "account" },
|
||||||
{ title: "资源", icon: "mdi-file-multiple", tab: "system" },
|
{ title: "站点", icon: "mdi-sitemap", tab: "system" },
|
||||||
{ title: "通知", icon: "mdi-bell-outline", tab: "notification" },
|
{ title: "规则", icon: "mdi-filter-cog", tab: "filter" },
|
||||||
|
{ title: "通知", icon: "mdi-bell", tab: "notification" },
|
||||||
{ title: "自定义词表", icon: "mdi-file-word-box", tab: "words" },
|
{ title: "自定义词表", icon: "mdi-file-word-box", tab: "words" },
|
||||||
];
|
];
|
||||||
</script>
|
</script>
|
||||||
@@ -39,6 +41,11 @@ const tabs = [
|
|||||||
<AccountSettingSystem />
|
<AccountSettingSystem />
|
||||||
</VWindowItem>
|
</VWindowItem>
|
||||||
|
|
||||||
|
<!-- Notification -->
|
||||||
|
<VWindowItem value="filter">
|
||||||
|
<AccountSettingFilter />
|
||||||
|
</VWindowItem>
|
||||||
|
|
||||||
<!-- Notification -->
|
<!-- Notification -->
|
||||||
<VWindowItem value="notification">
|
<VWindowItem value="notification">
|
||||||
<AccountSettingNotification />
|
<AccountSettingNotification />
|
||||||
|
|||||||
@@ -0,0 +1,136 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import api from "@/api";
|
||||||
|
import FilterRuleCard from "@/components/cards/FilterRuleCard.vue";
|
||||||
|
import { useToast } from "vue-toast-notification";
|
||||||
|
|
||||||
|
// 规则卡片类型
|
||||||
|
interface FilterCard {
|
||||||
|
// 优先级
|
||||||
|
pri: string;
|
||||||
|
// 已选规则
|
||||||
|
rules: string[];
|
||||||
|
// 是否可见
|
||||||
|
visible: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提示框
|
||||||
|
const $toast = useToast();
|
||||||
|
|
||||||
|
// 查询已设置过滤规则
|
||||||
|
const queryCustomFilters = async () => {
|
||||||
|
try {
|
||||||
|
const result: { [key: string]: any } = await api.get("system/setting/FilterRules");
|
||||||
|
if (result.success) {
|
||||||
|
// 保存的是个字符串,需要分割成数组
|
||||||
|
const groups = result.data?.value.split(">");
|
||||||
|
// 生成规则卡片
|
||||||
|
filterCards.value = groups?.map((group: string, index: number) => {
|
||||||
|
return {
|
||||||
|
pri: (index + 1).toString(),
|
||||||
|
rules: group.split("&"),
|
||||||
|
visible: true,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 保存用户设置的识别词
|
||||||
|
const saveCustomFilters = async () => {
|
||||||
|
try {
|
||||||
|
// 有值才处理
|
||||||
|
if (filterCards.value.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 将卡片规则接装为字符串
|
||||||
|
const value = filterCards.value
|
||||||
|
.filter((card) => card.rules.length > 0)
|
||||||
|
.map((card) => card.rules.join("&"))
|
||||||
|
.join(">");
|
||||||
|
// 保存
|
||||||
|
const result: { [key: string]: any } = await api.post(
|
||||||
|
"system/setting/FilterRules",
|
||||||
|
value
|
||||||
|
);
|
||||||
|
if (result.success) {
|
||||||
|
$toast.success("过滤规则保存成功");
|
||||||
|
} else {
|
||||||
|
$toast.error("过滤规则保存失败!");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 规则卡片列表
|
||||||
|
const filterCards = ref<FilterCard[]>([]);
|
||||||
|
|
||||||
|
// 更新规则卡片的值
|
||||||
|
const updateFilterCardValue = (pri: string, rules: string[]) => {
|
||||||
|
const card = filterCards.value.find((card) => card.pri === pri);
|
||||||
|
if (card) {
|
||||||
|
card.rules = rules;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 移除卡片
|
||||||
|
const filterCardClose = (pri: string) => {
|
||||||
|
// 将卡片从列表中删除,并更新剩余卡片的序号
|
||||||
|
filterCards.value = filterCards.value.filter((card) => card.pri !== pri);
|
||||||
|
filterCards.value.forEach((card, index) => {
|
||||||
|
card.pri = (index + 1).toString();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 增加卡片
|
||||||
|
const addFilterCard = () => {
|
||||||
|
// 优先级
|
||||||
|
const pri = (filterCards.value.length + 1).toString();
|
||||||
|
// 新卡片
|
||||||
|
const newCard: FilterCard = { pri, rules: [], visible: true };
|
||||||
|
// 添加到列表
|
||||||
|
filterCards.value.push(newCard);
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
queryCustomFilters();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<VRow>
|
||||||
|
<VCol cols="12">
|
||||||
|
<VCard title="过滤规则">
|
||||||
|
<VCardSubtitle> 设置在搜索和订阅时默认使用的过滤规则 </VCardSubtitle>
|
||||||
|
<VCardItem>
|
||||||
|
<div class="grid gap-3 grid-filterrule-card">
|
||||||
|
<FilterRuleCard
|
||||||
|
v-for="(card, index) in filterCards"
|
||||||
|
:key="index"
|
||||||
|
:pri="card.pri"
|
||||||
|
:rules="card.rules"
|
||||||
|
:visible="card.visible"
|
||||||
|
@changed="updateFilterCardValue"
|
||||||
|
@close="filterCardClose(card.pri)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</VCardItem>
|
||||||
|
<VCardItem>
|
||||||
|
<VBtn type="submit" @click="saveCustomFilters" class="me-2"> 保存 </VBtn>
|
||||||
|
<VBtn @click="addFilterCard" color="success" variant="tonal">
|
||||||
|
<VIcon icon="mdi-plus" />
|
||||||
|
<span class="d-none d-sm-block">增加规则</span>
|
||||||
|
</VBtn>
|
||||||
|
</VCardItem>
|
||||||
|
</VCard>
|
||||||
|
</VCol>
|
||||||
|
</VRow>
|
||||||
|
</template>
|
||||||
|
<style type="scss">
|
||||||
|
.grid-filterrule-card {
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
|
||||||
|
padding-block-end: 1rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user