mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-06-30 20:12:02 +08:00
10
.github/workflows/build.yml
vendored
10
.github/workflows/build.yml
vendored
@@ -1,10 +1,12 @@
|
||||
name: Build Moviepilot-Frontend
|
||||
name: Build Moviepilot-Frontend v2
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
- v2
|
||||
paths:
|
||||
- 'package.json'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -43,14 +45,14 @@ jobs:
|
||||
- name: Delete Release
|
||||
uses: dev-drprasad/delete-tag-and-release@v1.1
|
||||
with:
|
||||
tag_name: dev_${{ env.frontend_version }}
|
||||
tag_name: ${{ env.frontend_version }}
|
||||
delete_release: true
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Generate Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: dev_${{ env.frontend_version }}
|
||||
tag_name: ${{ env.frontend_version }}
|
||||
name: ${{ env.frontend_version }}
|
||||
draft: false
|
||||
prerelease: false
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "moviepilot",
|
||||
"version": "2.0.0-alpha",
|
||||
"version": "2.0.0-beta",
|
||||
"private": true,
|
||||
"bin": "dist/service.js",
|
||||
"scripts": {
|
||||
|
||||
3
src/@layouts/types.d.ts
vendored
3
src/@layouts/types.d.ts
vendored
@@ -123,7 +123,8 @@ export interface NavLink extends NavLinkProps, Partial<AclProperties> {
|
||||
export interface NavMenu extends NavLink {
|
||||
header: string
|
||||
description?: string
|
||||
permission?: string
|
||||
admin?: boolean
|
||||
footer?: boolean
|
||||
}
|
||||
|
||||
// 👉 Vertical nav group
|
||||
|
||||
@@ -1042,6 +1042,8 @@ export interface TransferDirectoryConf {
|
||||
download_category_folder?: boolean
|
||||
// 监控方式 downloader/monitor,None为不监控
|
||||
monitor_type?: string
|
||||
// 监控模式 fast/compatibility
|
||||
monitor_mode?: string
|
||||
// 整理方式 move/copy/link/softlink
|
||||
transfer_type?: string
|
||||
// 文件覆盖模式 always/size/never/latest
|
||||
@@ -1058,6 +1060,8 @@ export interface TransferDirectoryConf {
|
||||
library_type_folder?: boolean
|
||||
// 媒体库类别子目录
|
||||
library_category_folder?: boolean
|
||||
// 是否发送通知
|
||||
notify?: boolean
|
||||
}
|
||||
|
||||
// 自定义规则项
|
||||
|
||||
@@ -93,6 +93,11 @@ function onClose() {
|
||||
<template>
|
||||
<div>
|
||||
<VCard variant="tonal" @click="openRuleInfoDialog">
|
||||
<span class="absolute top-3 right-12">
|
||||
<IconBtn>
|
||||
<VIcon class="cursor-move" icon="mdi-drag" />
|
||||
</IconBtn>
|
||||
</span>
|
||||
<DialogCloseBtn @click="onClose" />
|
||||
<VCardText class="flex justify-space-between align-center gap-3">
|
||||
<div class="align-self-start">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts" setup>
|
||||
import type { TransferDirectoryConf } from '@/api/types'
|
||||
import { VTextField } from 'vuetify/lib/components/index.mjs'
|
||||
import { VDivider, VSpacer, VTextField } from 'vuetify/lib/components/index.mjs'
|
||||
import { useToast } from 'vue-toast-notification'
|
||||
import api from '@/api'
|
||||
import { nextTick } from 'vue'
|
||||
@@ -26,6 +26,9 @@ const downloadPath = ref<string>('')
|
||||
// 媒体库路径
|
||||
const libraryPath = ref<string>('')
|
||||
|
||||
// 卡版是否折叠状态
|
||||
const isCollapsed = ref(true)
|
||||
|
||||
// 类型下拉字典
|
||||
const typeItems = [
|
||||
{ title: '全部', value: '' },
|
||||
@@ -48,6 +51,12 @@ const transferSourceItems = [
|
||||
{ title: '目录监控', value: 'monitor' },
|
||||
]
|
||||
|
||||
// 监控模式下拉字典
|
||||
const MonitorModeItems = [
|
||||
{ title: '性能模式', value: 'fast' },
|
||||
{ title: '兼容模式', value: 'compatibility' },
|
||||
]
|
||||
|
||||
// 整理方式下拉字典
|
||||
const transferTypeItems = ref<{ title: string; value: string }[]>([])
|
||||
|
||||
@@ -182,7 +191,7 @@ watch(
|
||||
</IconBtn>
|
||||
</span>
|
||||
</VCardItem>
|
||||
<VCardText>
|
||||
<VCardText v-if="!isCollapsed">
|
||||
<VForm>
|
||||
<VRow>
|
||||
<VCol cols="6">
|
||||
@@ -236,6 +245,14 @@ watch(
|
||||
</VCol>
|
||||
</VRow>
|
||||
<VRow v-if="$props.directory.monitor_type">
|
||||
<VCol cols="12" v-if="$props.directory.monitor_type == 'monitor'">
|
||||
<VSelect
|
||||
v-model="props.directory.monitor_mode"
|
||||
variant="underlined"
|
||||
:items="MonitorModeItems"
|
||||
label="监控模式"
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="4">
|
||||
<VSelect
|
||||
v-model="props.directory.library_storage"
|
||||
@@ -285,8 +302,16 @@ watch(
|
||||
<VCol cols="6">
|
||||
<VSwitch v-model="props.directory.scraping" label="刮削元数据"></VSwitch>
|
||||
</VCol>
|
||||
<VCol cols="6">
|
||||
<VSwitch v-model="props.directory.notify" label="发送通知"></VSwitch>
|
||||
</VCol>
|
||||
</VRow>
|
||||
</VForm>
|
||||
</VCardText>
|
||||
<VCardActions class="text-center py-0">
|
||||
<VSpacer />
|
||||
<VBtn :icon="isCollapsed ? 'mdi-chevron-down' : 'mdi-chevron-up'" @click.stop="isCollapsed = !isCollapsed" />
|
||||
<VSpacer />
|
||||
</VCardActions>
|
||||
</VCard>
|
||||
</template>
|
||||
|
||||
@@ -209,6 +209,11 @@ function onClose() {
|
||||
<template>
|
||||
<div>
|
||||
<VCard variant="tonal" @click="opengroupInfoDialog">
|
||||
<span class="absolute top-3 right-12">
|
||||
<IconBtn>
|
||||
<VIcon class="cursor-move" icon="mdi-drag" />
|
||||
</IconBtn>
|
||||
</span>
|
||||
<DialogCloseBtn @click="onClose" />
|
||||
<VCardText class="flex justify-space-between align-center gap-3">
|
||||
<div class="align-self-start">
|
||||
|
||||
@@ -117,6 +117,11 @@ function onClose() {
|
||||
<template>
|
||||
<div>
|
||||
<VCard variant="tonal" @click="openNotificationInfoDialog">
|
||||
<span class="absolute top-3 right-12">
|
||||
<IconBtn>
|
||||
<VIcon class="cursor-move" icon="mdi-drag" />
|
||||
</IconBtn>
|
||||
</span>
|
||||
<DialogCloseBtn @click="onClose" />
|
||||
<VCardText class="flex justify-space-between align-center gap-3">
|
||||
<div class="align-self-start">
|
||||
|
||||
@@ -134,8 +134,8 @@ async function forkSubscribe() {
|
||||
</template>
|
||||
</VImg>
|
||||
</div>
|
||||
<div class="flex flex-col justify-center pl-2 xl:pl-4 line-clamp-2 overflow-hidden text-ellipsis ...">
|
||||
<div class="mr-2 min-w-0 text-lg font-bold text-white">
|
||||
<div class="flex flex-col justify-center pl-2 xl:pl-4">
|
||||
<div class="mr-2 min-w-0 text-lg font-bold text-white line-clamp-2 overflow-hidden text-ellipsis ...">
|
||||
{{ props.media?.share_title }}
|
||||
</div>
|
||||
<div class="text-sm font-medium text-gray-200 sm:pt-1 line-clamp-3 overflow-hidden text-ellipsis ...">
|
||||
|
||||
@@ -21,8 +21,11 @@ const props = defineProps({
|
||||
},
|
||||
})
|
||||
|
||||
// 当前用户名称
|
||||
const currentLoginUser = store.state.auth.userName
|
||||
// 当前用户的ID
|
||||
const currentLoginUserId = computed(() => store.state.auth.userID)
|
||||
|
||||
// 当前用户是否是管理员
|
||||
const currentUserIsSuperuser = computed(() => store.state.auth.superUser)
|
||||
|
||||
// 定义触发的自定义事件
|
||||
const emit = defineEmits(['remove', 'save'])
|
||||
@@ -57,7 +60,7 @@ async function fetchSubscriptions() {
|
||||
|
||||
// 删除用户
|
||||
async function removeUser() {
|
||||
if (props.user.name == currentLoginUser) {
|
||||
if (props.user.id === currentLoginUserId.value) {
|
||||
$toast.error('不能删除当前登录用户!')
|
||||
return
|
||||
}
|
||||
@@ -84,19 +87,6 @@ function editUser() {
|
||||
userEditDialog.value = true
|
||||
}
|
||||
|
||||
// 计算是否有用户编辑权限
|
||||
const canEditUser = computed(() => {
|
||||
if (store.state.auth.superUser && props.user.name !== currentLoginUser) return true
|
||||
return false
|
||||
})
|
||||
|
||||
// 计算是否有用户管理权限
|
||||
const canManageUser = computed(() => {
|
||||
if (props.user.name == currentLoginUser) return false
|
||||
if (store.state.auth.superUser) return true
|
||||
return false
|
||||
})
|
||||
|
||||
// 用户重新完成时
|
||||
function onUserUpdate() {
|
||||
userEditDialog.value = false
|
||||
@@ -139,8 +129,9 @@ onMounted(() => {
|
||||
</div>
|
||||
</VCardText>
|
||||
<VCardText class="pb-6">
|
||||
<h5 class="text-h6">详情</h5>
|
||||
<VDivider class="my-2" />
|
||||
<VDivider class="my-2">
|
||||
<h5 class="text-h6">详情</h5>
|
||||
</VDivider>
|
||||
<VList lines="one">
|
||||
<VListItem>
|
||||
<VListItemTitle class="text-sm">
|
||||
@@ -170,8 +161,22 @@ onMounted(() => {
|
||||
</VList>
|
||||
</VCardText>
|
||||
<VCardText class="flex flex-row justify-center">
|
||||
<VBtn v-if="canEditUser" color="primary" class="me-4" @click="editUser">编辑</VBtn>
|
||||
<VBtn v-if="canManageUser" color="error" variant="outlined" @click="removeUser"> 删除 </VBtn>
|
||||
<VBtn
|
||||
v-if="currentUserIsSuperuser"
|
||||
color="primary"
|
||||
class="me-4"
|
||||
@click="editUser"
|
||||
>
|
||||
编辑
|
||||
</VBtn>
|
||||
<VBtn
|
||||
v-if="currentUserIsSuperuser && props.user.id != currentLoginUserId"
|
||||
color="error"
|
||||
variant="outlined"
|
||||
@click="removeUser"
|
||||
>
|
||||
删除
|
||||
</VBtn>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
<!-- 用户编辑弹窗 -->
|
||||
|
||||
@@ -36,7 +36,7 @@ const systemMenus = ref<NavMenu[]>([])
|
||||
|
||||
// 根据分类获取菜单列表
|
||||
const getMenuList = (header: string) => {
|
||||
return SystemNavMenus.filter((item: NavMenu) => item.header === header && superUser)
|
||||
return SystemNavMenus.filter((item: NavMenu) => item.header === header && (superUser || !item.admin))
|
||||
}
|
||||
|
||||
// 返回上一页
|
||||
|
||||
@@ -143,8 +143,8 @@ onMounted(() => {
|
||||
<VAvatar size="48" variant="tonal">
|
||||
<VIcon icon="mdi-filter-cog-outline" />
|
||||
</VAvatar>
|
||||
<h6 class="text-base font-weight-medium mt-2 mb-0">优先级</h6>
|
||||
<span class="text-sm">优先级规则测试</span>
|
||||
<h6 class="text-base font-weight-medium mt-2 mb-0">规则</h6>
|
||||
<span class="text-sm">规则测试</span>
|
||||
</VListItem>
|
||||
</VCol>
|
||||
</VRow>
|
||||
@@ -241,7 +241,7 @@ onMounted(() => {
|
||||
</VDialog>
|
||||
<!-- 规则测试弹窗 -->
|
||||
<VDialog v-if="ruleTestDialog" v-model="ruleTestDialog" max-width="50rem" scrollable>
|
||||
<VCard title="优先级测试">
|
||||
<VCard title="规则测试">
|
||||
<DialogCloseBtn @click="ruleTestDialog = false" />
|
||||
<VCardText>
|
||||
<RuleTestView />
|
||||
|
||||
@@ -6,9 +6,6 @@ import router from '@/router'
|
||||
import avatar1 from '@images/avatars/avatar-1.png'
|
||||
import api from '@/api'
|
||||
import ProgressDialog from '@/components/dialog/ProgressDialog.vue'
|
||||
import { useDisplay } from 'vuetify'
|
||||
|
||||
const display = useDisplay()
|
||||
|
||||
// Vuex Store
|
||||
const store = useStore()
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
import '@/@core/utils/compatibility'
|
||||
import './ace-config'
|
||||
import '@/@iconify/icons-bundle'
|
||||
import '@/plugins/webfontloader'
|
||||
import App from '@/App.vue'
|
||||
import vuetify from '@/plugins/vuetify'
|
||||
import router from '@/router'
|
||||
import store from '@/store'
|
||||
import { VAceEditor } from 'vue3-ace-editor'
|
||||
import { createApp } from 'vue'
|
||||
import { removeEl } from './@core/utils/dom'
|
||||
import { fetchGlobalSettings } from './api'
|
||||
import { isPWA } from './@core/utils/navigator'
|
||||
import './ace-config'
|
||||
import { VAceEditor } from 'vue3-ace-editor'
|
||||
import { PerfectScrollbarPlugin } from 'vue3-perfect-scrollbar'
|
||||
import { VTreeview } from 'vuetify/labs/VTreeview'
|
||||
import ToastPlugin from 'vue-toast-notification'
|
||||
@@ -23,8 +25,6 @@ import MediaInfoCard from './components/cards/MediaInfoCard.vue'
|
||||
import TorrentCard from './components/cards/TorrentCard.vue'
|
||||
import MediaIdSelector from './components/misc/MediaIdSelector.vue'
|
||||
import PathField from './components/input/PathField.vue'
|
||||
import { fetchGlobalSettings } from './api'
|
||||
import { isPWA } from './@core/utils/navigator'
|
||||
import '@core/scss/template/index.scss'
|
||||
import '@layouts/styles/index.scss'
|
||||
import '@styles/styles.scss'
|
||||
|
||||
@@ -12,7 +12,7 @@ const appOrder = ref<string[]>([])
|
||||
|
||||
// 根据分类获取菜单列表
|
||||
const getMenuList = () => {
|
||||
return SystemNavMenus.filter((item: NavMenu) => !item.admin || superUser)
|
||||
return SystemNavMenus.filter((item: NavMenu) => (!item.admin || superUser) && !item.footer)
|
||||
}
|
||||
|
||||
// APP列表
|
||||
@@ -48,7 +48,7 @@ onMounted(() => {
|
||||
:component-data="{ 'class': 'ma-0 mt-n1' }"
|
||||
>
|
||||
<template #item="{ element }">
|
||||
<VCol cols="6" md="4" lg="3" class="text-center cursor-pointer shortcut-icon select-none">
|
||||
<VCol cols="6" md="3" lg="2" class="text-center cursor-pointer shortcut-icon select-none">
|
||||
<VCard class="pa-4" :to="element.to" variant="flat">
|
||||
<VAvatar size="64" variant="text">
|
||||
<VIcon size="48" :icon="element.icon" color="primary" />
|
||||
|
||||
@@ -15,9 +15,6 @@ const { global: globalTheme } = useTheme()
|
||||
// Vuex Store
|
||||
const store = useStore()
|
||||
|
||||
// 从 provide 中获取全局设置
|
||||
const globalSettings: any = inject('globalSettings')
|
||||
|
||||
// 表单
|
||||
const form = ref({
|
||||
username: '',
|
||||
@@ -55,15 +52,8 @@ let intervalTimer: NodeJS.Timeout | null = null
|
||||
// 获取背景图片
|
||||
async function fetchBackgroundImage() {
|
||||
try {
|
||||
const results: string[] = await api.get('/login/wallpapers')
|
||||
if (results && results.length > 0) {
|
||||
results.map((url: string) => {
|
||||
if (globalSettings.GLOBAL_IMAGE_CACHE)
|
||||
backgroundImages.value.push(
|
||||
`${import.meta.env.VITE_API_BASE_URL}system/cache/image?url=${encodeURIComponent(url)}`,
|
||||
)
|
||||
else backgroundImages.value.push(url)
|
||||
})
|
||||
backgroundImages.value = await api.get('/login/wallpapers')
|
||||
if (backgroundImages.value && backgroundImages.value.length > 0) {
|
||||
// 随机打乱排序
|
||||
backgroundImages.value.sort(() => Math.random() - 0.5)
|
||||
backgroundImageUrl.value = backgroundImages.value[0]
|
||||
@@ -171,6 +161,7 @@ function login() {
|
||||
// 获取token
|
||||
const token = response.access_token
|
||||
const superUser = response.super_user
|
||||
const userID = response.user_id
|
||||
const userName = response.user_name
|
||||
const avatar = response.avatar
|
||||
const level = response.level
|
||||
@@ -178,7 +169,16 @@ function login() {
|
||||
const permissions = response.permissions
|
||||
|
||||
// 更新token和remember状态到Vuex Store
|
||||
store.dispatch('auth/login', { token, remember, superUser, userName, avatar, level, permissions })
|
||||
store.dispatch('auth/login', {
|
||||
token,
|
||||
remember,
|
||||
superUser,
|
||||
userID,
|
||||
userName,
|
||||
avatar,
|
||||
level,
|
||||
permissions,
|
||||
})
|
||||
|
||||
// 登录后处理
|
||||
afterLogin(superUser)
|
||||
|
||||
@@ -5,21 +5,23 @@ export const SystemNavMenus = [
|
||||
icon: 'mdi-home-outline',
|
||||
to: '/dashboard',
|
||||
header: '开始',
|
||||
permission: 'dashboard',
|
||||
admin: false,
|
||||
footer: true,
|
||||
},
|
||||
{
|
||||
title: '推荐',
|
||||
icon: 'mdi-star-outline',
|
||||
to: '/ranking',
|
||||
header: '发现',
|
||||
permission: 'ranking',
|
||||
admin: false,
|
||||
footer: true,
|
||||
},
|
||||
{
|
||||
title: '资源搜索',
|
||||
icon: 'mdi-magnify',
|
||||
to: '/resource',
|
||||
header: '发现',
|
||||
permission: 'resource.search',
|
||||
admin: false,
|
||||
},
|
||||
{
|
||||
title: '电影',
|
||||
@@ -27,7 +29,8 @@ export const SystemNavMenus = [
|
||||
icon: 'mdi-movie-open-outline',
|
||||
to: '/subscribe/movie',
|
||||
header: '订阅',
|
||||
permission: 'subscribe.movie',
|
||||
admin: false,
|
||||
footer: true,
|
||||
},
|
||||
{
|
||||
title: '电视剧',
|
||||
@@ -35,7 +38,8 @@ export const SystemNavMenus = [
|
||||
icon: 'mdi-television',
|
||||
to: '/subscribe/tv',
|
||||
header: '订阅',
|
||||
permission: 'subscribe.tv',
|
||||
admin: false,
|
||||
footer: true,
|
||||
},
|
||||
{
|
||||
title: '日历',
|
||||
@@ -43,56 +47,56 @@ export const SystemNavMenus = [
|
||||
icon: 'mdi-calendar',
|
||||
to: '/calendar',
|
||||
header: '订阅',
|
||||
permission: 'subscribe.calendar',
|
||||
admin: false,
|
||||
},
|
||||
{
|
||||
title: '正在下载',
|
||||
icon: 'mdi-download-outline',
|
||||
to: '/downloading',
|
||||
header: '整理',
|
||||
permission: 'downloading.view',
|
||||
admin: false,
|
||||
},
|
||||
{
|
||||
title: '历史记录',
|
||||
icon: 'mdi-history',
|
||||
to: '/history',
|
||||
header: '整理',
|
||||
permission: 'admin',
|
||||
admin: true,
|
||||
},
|
||||
{
|
||||
title: '文件管理',
|
||||
icon: 'mdi-folder-multiple-outline',
|
||||
to: '/filemanager',
|
||||
header: '整理',
|
||||
permission: 'admin',
|
||||
admin: true,
|
||||
},
|
||||
{
|
||||
title: '插件',
|
||||
icon: 'mdi-apps',
|
||||
to: '/plugins',
|
||||
header: '系统',
|
||||
permission: 'admin',
|
||||
admin: true,
|
||||
},
|
||||
{
|
||||
title: '站点管理',
|
||||
icon: 'mdi-web',
|
||||
to: '/site',
|
||||
header: '系统',
|
||||
permission: 'admin',
|
||||
admin: true,
|
||||
},
|
||||
{
|
||||
title: '用户管理',
|
||||
icon: 'mdi-account-group',
|
||||
to: '/user',
|
||||
header: '系统',
|
||||
permission: 'usermanage',
|
||||
admin: true,
|
||||
},
|
||||
{
|
||||
title: '设定',
|
||||
icon: 'mdi-cog',
|
||||
to: '/setting',
|
||||
header: '系统',
|
||||
permission: 'admin',
|
||||
admin: true,
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ interface AuthState {
|
||||
token: string | null
|
||||
remember: boolean
|
||||
superUser: boolean
|
||||
userID: number
|
||||
userName: string
|
||||
avatar: string
|
||||
originalPath: string | null
|
||||
@@ -24,6 +25,7 @@ const authModule: Module<AuthState, RootState> = {
|
||||
token: null, // 用户令牌
|
||||
remember: false, // 记住我
|
||||
superUser: false, // 超级管理员
|
||||
userID: 999, // 用户ID
|
||||
userName: '', // 用户名
|
||||
avatar: '', // 头像
|
||||
originalPath: null, // 原始路径
|
||||
@@ -43,6 +45,9 @@ const authModule: Module<AuthState, RootState> = {
|
||||
setSuperUser(state, superUser: boolean) {
|
||||
state.superUser = superUser
|
||||
},
|
||||
setUserID(state, userID: number) {
|
||||
state.userID = userID
|
||||
},
|
||||
setUserName(state, userName: string) {
|
||||
state.userName = userName
|
||||
},
|
||||
@@ -60,10 +65,11 @@ const authModule: Module<AuthState, RootState> = {
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
login({ commit }, { token, remember, superUser, userName, avatar, level, permissions }) {
|
||||
login({ commit }, { token, remember, superUser, userID, userName, avatar, level, permissions }) {
|
||||
commit('setToken', token)
|
||||
commit('setRemember', remember)
|
||||
commit('setSuperUser', superUser)
|
||||
commit('setUserID', userID)
|
||||
commit('setUserName', userName)
|
||||
commit('setAvatar', avatar)
|
||||
commit('setLevel', level)
|
||||
@@ -78,6 +84,7 @@ const authModule: Module<AuthState, RootState> = {
|
||||
getToken: state => state.token,
|
||||
getRemember: state => state.remember,
|
||||
getSuperUser: state => state.superUser,
|
||||
getUserID: state => state.userID,
|
||||
getUserName: state => state.userName,
|
||||
getAvatar: state => state.avatar,
|
||||
getOriginalPath: state => state.originalPath,
|
||||
|
||||
@@ -166,7 +166,7 @@
|
||||
}
|
||||
|
||||
.grid-directory-card {
|
||||
grid-template-columns: repeat(auto-fill, minmax(24rem, 1fr));
|
||||
grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
|
||||
padding-block-end: 1rem;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,8 @@ async function loadLatest(server: string) {
|
||||
|
||||
onMounted(async () => {
|
||||
await loadMediaServerSetting()
|
||||
for (const server of mediaServers.value) {
|
||||
const enabledServers = mediaServers.value.filter(server => server.enabled)
|
||||
for (const server of enabledServers) {
|
||||
loadLatest(server.name)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -35,7 +35,8 @@ async function loadLibrary(server: string) {
|
||||
|
||||
onMounted(async () => {
|
||||
await loadMediaServerSetting()
|
||||
for (const server of mediaServers.value) {
|
||||
const enabledServers = mediaServers.value.filter(server => server.enabled)
|
||||
for (const server of enabledServers) {
|
||||
loadLibrary(server.name)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -33,7 +33,8 @@ async function loadPlayingList(server: string) {
|
||||
|
||||
onMounted(async () => {
|
||||
await loadMediaServerSetting()
|
||||
for (const server of mediaServers.value) {
|
||||
const enabledServers = mediaServers.value.filter(server => server.enabled)
|
||||
for (const server of enabledServers) {
|
||||
loadPlayingList(server.name)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -2,15 +2,16 @@
|
||||
import { reactive, ref } from 'vue'
|
||||
import { requiredValidator } from '@/@validators'
|
||||
import api from '@/api'
|
||||
import { FilterRuleGroup } from '@/api/types'
|
||||
|
||||
// 识别结果
|
||||
const ruleTestResult = ref('')
|
||||
|
||||
// 名称识别表单
|
||||
const ruleTestForm = reactive({
|
||||
title: '',
|
||||
subtitle: '',
|
||||
ruletype: '1',
|
||||
title: null,
|
||||
subtitle: null,
|
||||
rulegroup: null,
|
||||
})
|
||||
|
||||
// 识别按钮状态
|
||||
@@ -22,10 +23,27 @@ const ruleTestText = ref('测试')
|
||||
// 是否显示结果
|
||||
const showResult = ref(false)
|
||||
|
||||
// 所有规则组列表
|
||||
const filterRuleGroups = ref<FilterRuleGroup[]>([])
|
||||
|
||||
// 规则组选项
|
||||
const filterRuleGroupItems = computed(() => {
|
||||
return filterRuleGroups.value.map(item => ({ title: item.name, value: item.name }))
|
||||
})
|
||||
|
||||
// 加载规则组
|
||||
async function queryFilterRuleGroups() {
|
||||
try {
|
||||
const result: { [key: string]: any } = await api.get('system/setting/UserFilterRuleGroups')
|
||||
filterRuleGroups.value = result.data?.value ?? []
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
|
||||
// 调用API识别
|
||||
async function ruleTest() {
|
||||
if (!ruleTestForm.title)
|
||||
return
|
||||
if (!ruleTestForm.title) return
|
||||
|
||||
try {
|
||||
ruleTestLoading.value = true
|
||||
@@ -35,69 +53,41 @@ async function ruleTest() {
|
||||
params: {
|
||||
title: ruleTestForm.title,
|
||||
subtitle: ruleTestForm.subtitle,
|
||||
ruletype: ruleTestForm.ruletype,
|
||||
rulegroup_name: ruleTestForm.rulegroup,
|
||||
},
|
||||
})
|
||||
if (result.success)
|
||||
ruleTestResult.value = `优先级:${result.data.priority}`
|
||||
|
||||
else
|
||||
ruleTestResult.value = '未命中任何优先级规则!'
|
||||
if (result.success) ruleTestResult.value = `优先级:${result.data.priority}`
|
||||
else ruleTestResult.value = '未命中任何优先级规则!'
|
||||
|
||||
ruleTestLoading.value = false
|
||||
ruleTestText.value = '重新测试'
|
||||
showResult.value = true
|
||||
}
|
||||
catch (error) {
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
queryFilterRuleGroups()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VForm @submit.prevent="() => {}">
|
||||
<VRow class="pt-2">
|
||||
<VCol cols="12" md="8">
|
||||
<VTextField
|
||||
v-model="ruleTestForm.title"
|
||||
label="标题"
|
||||
:rules="[requiredValidator]"
|
||||
/>
|
||||
<VTextField v-model="ruleTestForm.title" label="标题" :rules="[requiredValidator]" />
|
||||
</VCol>
|
||||
<VCol cols="12" md="4">
|
||||
<VSelect
|
||||
v-model="ruleTestForm.ruletype"
|
||||
label="规则类型"
|
||||
:items="[{
|
||||
title: '订阅优先级',
|
||||
value: '1',
|
||||
}, {
|
||||
title: '洗版优先级',
|
||||
value: '2',
|
||||
}, {
|
||||
title: '搜索优先级',
|
||||
value: '3',
|
||||
}]"
|
||||
/>
|
||||
<VSelect v-model="ruleTestForm.rulegroup" label="规则组" :items="filterRuleGroupItems" />
|
||||
</VCol>
|
||||
<VCol cols="12">
|
||||
<VTextarea
|
||||
v-model="ruleTestForm.subtitle"
|
||||
label="副标题"
|
||||
rows="2"
|
||||
auto-grow
|
||||
/>
|
||||
<VTextarea v-model="ruleTestForm.subtitle" label="副标题" rows="2" auto-grow />
|
||||
</VCol>
|
||||
</VRow>
|
||||
<VRow>
|
||||
<VCol
|
||||
cols="12"
|
||||
class="text-center"
|
||||
>
|
||||
<VBtn
|
||||
:disabled="ruleTestLoading"
|
||||
@click="ruleTest"
|
||||
>
|
||||
<VCol cols="12" class="text-center">
|
||||
<VBtn :disabled="ruleTestLoading" @click="ruleTest">
|
||||
<template #prepend>
|
||||
<VIcon icon="mdi-filter-check-outline" />
|
||||
</template>
|
||||
@@ -109,9 +99,7 @@ async function ruleTest() {
|
||||
<VExpandTransition>
|
||||
<div v-show="showResult">
|
||||
<VCol>
|
||||
<VAlert
|
||||
icon="mdi-alert-circle-outline"
|
||||
>
|
||||
<VAlert icon="mdi-alert-circle-outline">
|
||||
{{ ruleTestResult }}
|
||||
</VAlert>
|
||||
</VCol>
|
||||
|
||||
Reference in New Issue
Block a user