mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-09-04 23:18:44 +08:00
add app mode
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "moviepilot",
|
"name": "moviepilot",
|
||||||
"version": "1.9.4-2",
|
"version": "1.9.5",
|
||||||
"private": true,
|
"private": true,
|
||||||
"bin": "dist/service.js",
|
"bin": "dist/service.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -33,11 +33,10 @@ defineProps<{
|
|||||||
.nav-link a {
|
.nav-link a {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
cursor: pointer;
|
|
||||||
padding-left: 1.375rem;
|
|
||||||
padding-right: 1rem;
|
|
||||||
margin-right: 1.125em;
|
|
||||||
border-radius: 0 3.125rem 3.125rem 0 !important;
|
border-radius: 0 3.125rem 3.125rem 0 !important;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-inline-end: 1.125em;
|
||||||
|
padding-inline: 1.375rem 1rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -19,6 +19,9 @@ const superUser = store.state.auth.superUser
|
|||||||
const getMenuList = (header: string) => {
|
const getMenuList = (header: string) => {
|
||||||
return SystemNavMenus.filter((item: NavMenu) => item.header === header && (!item.admin || superUser))
|
return SystemNavMenus.filter((item: NavMenu) => item.header === header && (!item.admin || superUser))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// APP模式
|
||||||
|
const appMode = computed(() => localStorage.getItem('MP_APPMODE') == '1')
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -27,7 +30,7 @@ const getMenuList = (header: string) => {
|
|||||||
<template #navbar="{ toggleVerticalOverlayNavActive }">
|
<template #navbar="{ toggleVerticalOverlayNavActive }">
|
||||||
<div class="d-flex h-100 align-center mx-1">
|
<div class="d-flex h-100 align-center mx-1">
|
||||||
<!-- 👉 Vertical Nav Toggle -->
|
<!-- 👉 Vertical Nav Toggle -->
|
||||||
<IconBtn class="ms-n2 d-lg-none" @click="toggleVerticalOverlayNavActive(true)">
|
<IconBtn v-if="!appMode" class="ms-n2 d-lg-none" @click="toggleVerticalOverlayNavActive(true)">
|
||||||
<VIcon icon="mdi-menu" />
|
<VIcon icon="mdi-menu" />
|
||||||
</IconBtn>
|
</IconBtn>
|
||||||
<!-- 👉 Search Bar -->
|
<!-- 👉 Search Bar -->
|
||||||
|
|||||||
@@ -1,3 +1,35 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { useDisplay } from 'vuetify'
|
||||||
|
|
||||||
|
const display = useDisplay()
|
||||||
|
const appMode = computed(() => {
|
||||||
|
return localStorage.getItem('MP_APPMODE') == '1' && display.mdAndDown.value
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="h-100 d-flex align-center justify-space-between" />
|
<div v-if="appMode" class="w-100" style="block-size: 3.5rem">
|
||||||
|
<VBottomNavigation grow horizontal color="primary">
|
||||||
|
<VBtn to="/dashboard">
|
||||||
|
<VIcon size="28">mdi-home-outline</VIcon>
|
||||||
|
<span>首页</span>
|
||||||
|
</VBtn>
|
||||||
|
<VBtn to="/ranking">
|
||||||
|
<VIcon size="28">mdi-star-check-outline</VIcon>
|
||||||
|
<span>推荐</span>
|
||||||
|
</VBtn>
|
||||||
|
<VBtn to="/subscribe-movie?tab=mysub">
|
||||||
|
<VIcon size="28">mdi-movie-roll</VIcon>
|
||||||
|
<span><span></span>电影</span>
|
||||||
|
</VBtn>
|
||||||
|
<VBtn to="/subscribe-tv?tab=mysub">
|
||||||
|
<VIcon size="28">mdi-television-classic</VIcon>
|
||||||
|
<span>电视剧</span>
|
||||||
|
</VBtn>
|
||||||
|
<VBtn to="/apps">
|
||||||
|
<VIcon size="28">mdi-dots-horizontal</VIcon>
|
||||||
|
<span>更多</span>
|
||||||
|
</VBtn>
|
||||||
|
</VBottomNavigation>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -6,6 +6,9 @@ import router from '@/router'
|
|||||||
import avatar1 from '@images/avatars/avatar-1.png'
|
import avatar1 from '@images/avatars/avatar-1.png'
|
||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
import ProgressDialog from '@/components/dialog/ProgressDialog.vue'
|
import ProgressDialog from '@/components/dialog/ProgressDialog.vue'
|
||||||
|
import { useDisplay } from 'vuetify'
|
||||||
|
|
||||||
|
const display = useDisplay()
|
||||||
|
|
||||||
// Vuex Store
|
// Vuex Store
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
@@ -58,10 +61,20 @@ async function restart() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 是否精简模式
|
||||||
|
const isCompactMode = ref(localStorage.getItem('MP_APPMODE') == '1')
|
||||||
|
|
||||||
// 从Vuex Store中获取信息
|
// 从Vuex Store中获取信息
|
||||||
const superUser = store.state.auth.superUser
|
const superUser = store.state.auth.superUser
|
||||||
const userName = store.state.auth.userName
|
const userName = store.state.auth.userName
|
||||||
const avatar = store.state.auth.avatar
|
const avatar = store.state.auth.avatar
|
||||||
|
|
||||||
|
// 监听精简模式切换
|
||||||
|
watch(isCompactMode, value => {
|
||||||
|
localStorage.setItem('MP_APPMODE', value ? '1' : '0')
|
||||||
|
//刷新页面
|
||||||
|
location.reload()
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -86,6 +99,12 @@ const avatar = store.state.auth.avatar
|
|||||||
</VListItemTitle>
|
</VListItemTitle>
|
||||||
<VListItemSubtitle>{{ userName }}</VListItemSubtitle>
|
<VListItemSubtitle>{{ userName }}</VListItemSubtitle>
|
||||||
</VListItem>
|
</VListItem>
|
||||||
|
<VListItem v-if="display.mdAndDown.value">
|
||||||
|
<template #prepend>
|
||||||
|
<VSwitch class="me-2" v-model="isCompactMode"></VSwitch>
|
||||||
|
</template>
|
||||||
|
<VListItemTitle>App模式</VListItemTitle>
|
||||||
|
</VListItem>
|
||||||
<VDivider class="my-2" />
|
<VDivider class="my-2" />
|
||||||
|
|
||||||
<!-- 👉 Profile -->
|
<!-- 👉 Profile -->
|
||||||
@@ -105,7 +124,7 @@ const avatar = store.state.auth.avatar
|
|||||||
</VListItem>
|
</VListItem>
|
||||||
|
|
||||||
<!-- Divider -->
|
<!-- Divider -->
|
||||||
<VDivider class="my-2" />
|
<VDivider v-if="superUser" class="my-2" />
|
||||||
|
|
||||||
<!-- 👉 restart -->
|
<!-- 👉 restart -->
|
||||||
<VListItem v-if="superUser" @click="restart">
|
<VListItem v-if="superUser" @click="restart">
|
||||||
@@ -115,9 +134,6 @@ const avatar = store.state.auth.avatar
|
|||||||
<VListItemTitle>重启</VListItemTitle>
|
<VListItemTitle>重启</VListItemTitle>
|
||||||
</VListItem>
|
</VListItem>
|
||||||
|
|
||||||
<!-- Divider -->
|
|
||||||
<VDivider class="my-2" />
|
|
||||||
|
|
||||||
<!-- 👉 Logout -->
|
<!-- 👉 Logout -->
|
||||||
<VListItem @click="logout">
|
<VListItem @click="logout">
|
||||||
<VBtn color="error" block>
|
<VBtn color="error" block>
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { NavMenu } from '@/@layouts/types'
|
||||||
|
import { SystemNavMenus } from '@/router/menu'
|
||||||
|
import store from '@/store'
|
||||||
|
|
||||||
|
// 从Vuex Store中获取superuser信息
|
||||||
|
const superUser = store.state.auth.superUser
|
||||||
|
|
||||||
|
// 根据分类获取菜单列表
|
||||||
|
const getMenuList = () => {
|
||||||
|
return SystemNavMenus.filter((item: NavMenu) => !item.admin || superUser)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div class="ps ps--active-y mx-3" tabindex="0">
|
||||||
|
<VRow class="ma-0 mt-n1">
|
||||||
|
<VCol cols="6" md="4" lg="3" class="text-center cursor-pointer shortcut-icon" v-for="item in getMenuList()">
|
||||||
|
<VCard class="pa-4" :to="item.to" variant="flat">
|
||||||
|
<VAvatar size="64" variant="text">
|
||||||
|
<VIcon size="48" :icon="item.icon" color="primary" />
|
||||||
|
</VAvatar>
|
||||||
|
<h6 class="text-base font-weight-medium mt-2 mb-0">{{ item.full_title || item.title }}</h6>
|
||||||
|
</VCard>
|
||||||
|
</VCol>
|
||||||
|
</VRow>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
+17
-1
@@ -5,6 +5,13 @@ import { isNullOrEmptyObject } from '@/@core/utils'
|
|||||||
import { DashboardItem } from '@/api/types'
|
import { DashboardItem } from '@/api/types'
|
||||||
import store from '@/store'
|
import store from '@/store'
|
||||||
import DashboardElement from '@/components/misc/DashboardElement.vue'
|
import DashboardElement from '@/components/misc/DashboardElement.vue'
|
||||||
|
import { useDisplay } from 'vuetify'
|
||||||
|
|
||||||
|
// APP
|
||||||
|
const display = useDisplay()
|
||||||
|
const appMode = computed(() => {
|
||||||
|
return localStorage.getItem('MP_APPMODE') == '1' && display.mdAndDown.value
|
||||||
|
})
|
||||||
|
|
||||||
// 从Vuex Store中获取superuser信息
|
// 从Vuex Store中获取superuser信息
|
||||||
const superUser = store.state.auth.superUser
|
const superUser = store.state.auth.superUser
|
||||||
@@ -314,7 +321,16 @@ onBeforeMount(async () => {
|
|||||||
</draggable>
|
</draggable>
|
||||||
|
|
||||||
<!-- 底部操作按钮 -->
|
<!-- 底部操作按钮 -->
|
||||||
<VFab icon="mdi-view-dashboard-edit" location="bottom" size="x-large" fixed app appear @click="dialog = true" />
|
<VFab
|
||||||
|
icon="mdi-view-dashboard-edit"
|
||||||
|
location="bottom"
|
||||||
|
size="x-large"
|
||||||
|
fixed
|
||||||
|
app
|
||||||
|
appear
|
||||||
|
@click="dialog = true"
|
||||||
|
:class="{ 'mb-12': appMode }"
|
||||||
|
/>
|
||||||
|
|
||||||
<!-- 弹窗,根据配置生成选项 -->
|
<!-- 弹窗,根据配置生成选项 -->
|
||||||
<VDialog v-model="dialog" max-width="35rem" scrollable>
|
<VDialog v-model="dialog" max-width="35rem" scrollable>
|
||||||
|
|||||||
+21
-2
@@ -5,6 +5,13 @@ import type { Context } from '@/api/types'
|
|||||||
import store from '@/store'
|
import store from '@/store'
|
||||||
import TorrentCardListView from '@/views/discover/TorrentCardListView.vue'
|
import TorrentCardListView from '@/views/discover/TorrentCardListView.vue'
|
||||||
import TorrentRowListView from '@/views/discover/TorrentRowListView.vue'
|
import TorrentRowListView from '@/views/discover/TorrentRowListView.vue'
|
||||||
|
import { useDisplay } from 'vuetify'
|
||||||
|
|
||||||
|
// APP
|
||||||
|
const display = useDisplay()
|
||||||
|
const appMode = computed(() => {
|
||||||
|
return localStorage.getItem('MP_APPMODE') == '1' && display.mdAndDown.value
|
||||||
|
})
|
||||||
|
|
||||||
// 路由参数
|
// 路由参数
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
@@ -142,13 +149,25 @@ onUnmounted(() => {
|
|||||||
<!-- 视图切换 -->
|
<!-- 视图切换 -->
|
||||||
<VFab
|
<VFab
|
||||||
v-if="viewType === 'list'"
|
v-if="viewType === 'list'"
|
||||||
|
class="mb-12"
|
||||||
icon="mdi-view-grid"
|
icon="mdi-view-grid"
|
||||||
location="bottom"
|
location="bottom"
|
||||||
size="x-large"
|
size="x-large"
|
||||||
|
absolute
|
||||||
|
app
|
||||||
|
appear
|
||||||
|
@click="setViewType('card')"
|
||||||
|
:class="{ 'mb-12': appMode }"
|
||||||
|
/>
|
||||||
|
<VFab
|
||||||
|
v-else
|
||||||
|
icon="mdi-view-list"
|
||||||
|
location="bottom"
|
||||||
|
size="x-large"
|
||||||
fixed
|
fixed
|
||||||
app
|
app
|
||||||
appear
|
appear
|
||||||
@click="setViewType('card')"
|
@click="setViewType('list')"
|
||||||
|
:class="{ 'mb-12': appMode }"
|
||||||
/>
|
/>
|
||||||
<VFab v-else icon="mdi-view-list" location="bottom" size="x-large" fixed app appear @click="setViewType('list')" />
|
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -137,6 +137,13 @@ const router = createRouter({
|
|||||||
requiresAuth: true,
|
requiresAuth: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/apps',
|
||||||
|
component: () => import('../pages/appcenter.vue'),
|
||||||
|
meta: {
|
||||||
|
requiresAuth: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
+4
-1
@@ -9,7 +9,7 @@ export const SystemNavMenus = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '推荐',
|
title: '推荐',
|
||||||
icon: 'mdi-table-star',
|
icon: 'mdi-star-check-outline',
|
||||||
to: '/ranking',
|
to: '/ranking',
|
||||||
header: '发现',
|
header: '发现',
|
||||||
admin: false,
|
admin: false,
|
||||||
@@ -23,6 +23,7 @@ export const SystemNavMenus = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '电影',
|
title: '电影',
|
||||||
|
full_title: '电影订阅',
|
||||||
icon: 'mdi-movie-roll',
|
icon: 'mdi-movie-roll',
|
||||||
to: '/subscribe-movie?tab=mysub',
|
to: '/subscribe-movie?tab=mysub',
|
||||||
header: '订阅',
|
header: '订阅',
|
||||||
@@ -30,6 +31,7 @@ export const SystemNavMenus = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '电视剧',
|
title: '电视剧',
|
||||||
|
full_title: '电视剧订阅',
|
||||||
icon: 'mdi-television-classic',
|
icon: 'mdi-television-classic',
|
||||||
to: '/subscribe-tv?tab=mysub',
|
to: '/subscribe-tv?tab=mysub',
|
||||||
header: '订阅',
|
header: '订阅',
|
||||||
@@ -37,6 +39,7 @@ export const SystemNavMenus = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '日历',
|
title: '日历',
|
||||||
|
full_title: '订阅日历',
|
||||||
icon: 'mdi-calendar',
|
icon: 'mdi-calendar',
|
||||||
to: '/calendar',
|
to: '/calendar',
|
||||||
header: '订阅',
|
header: '订阅',
|
||||||
|
|||||||
@@ -16,6 +16,11 @@ const route = useRoute()
|
|||||||
// 显示器宽度
|
// 显示器宽度
|
||||||
const display = useDisplay()
|
const display = useDisplay()
|
||||||
|
|
||||||
|
// APP
|
||||||
|
const appMode = computed(() => {
|
||||||
|
return localStorage.getItem('MP_APPMODE') == '1' && display.mdAndDown.value
|
||||||
|
})
|
||||||
|
|
||||||
// 当前标签
|
// 当前标签
|
||||||
const activeTab = ref(route.query.tab)
|
const activeTab = ref(route.query.tab)
|
||||||
|
|
||||||
@@ -438,6 +443,7 @@ onBeforeMount(async () => {
|
|||||||
app
|
app
|
||||||
appear
|
appear
|
||||||
@click="SearchDialog = true"
|
@click="SearchDialog = true"
|
||||||
|
:class="{ 'mb-12': appMode }"
|
||||||
/>
|
/>
|
||||||
<VDialog
|
<VDialog
|
||||||
v-if="SearchDialog"
|
v-if="SearchDialog"
|
||||||
|
|||||||
@@ -7,6 +7,15 @@ import ReorganizeDialog from '@/components/dialog/ReorganizeDialog.vue'
|
|||||||
import ProgressDialog from '@/components/dialog/ProgressDialog.vue'
|
import ProgressDialog from '@/components/dialog/ProgressDialog.vue'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
import router from '@/router'
|
import router from '@/router'
|
||||||
|
import { useDisplay } from 'vuetify'
|
||||||
|
|
||||||
|
// 显示器宽度
|
||||||
|
const display = useDisplay()
|
||||||
|
|
||||||
|
// APP
|
||||||
|
const appMode = computed(() => {
|
||||||
|
return localStorage.getItem('MP_APPMODE') == '1' && display.mdAndDown.value
|
||||||
|
})
|
||||||
|
|
||||||
// 提示框
|
// 提示框
|
||||||
const $toast = useToast()
|
const $toast = useToast()
|
||||||
@@ -473,10 +482,11 @@ onMounted(fetchData)
|
|||||||
app
|
app
|
||||||
appear
|
appear
|
||||||
@click="removeHistoryBatch"
|
@click="removeHistoryBatch"
|
||||||
|
:class="{ 'mb-12': appMode }"
|
||||||
/>
|
/>
|
||||||
<VFab
|
<VFab
|
||||||
v-if="selected.length > 0"
|
v-if="selected.length > 0"
|
||||||
class="mb-16"
|
:class="appMode ? 'mb-28' : 'mb-16'"
|
||||||
icon="mdi-redo-variant"
|
icon="mdi-redo-variant"
|
||||||
location="bottom"
|
location="bottom"
|
||||||
size="x-large"
|
size="x-large"
|
||||||
|
|||||||
@@ -5,6 +5,15 @@ import type { Site } from '@/api/types'
|
|||||||
import SiteCard from '@/components/cards/SiteCard.vue'
|
import SiteCard from '@/components/cards/SiteCard.vue'
|
||||||
import NoDataFound from '@/components/NoDataFound.vue'
|
import NoDataFound from '@/components/NoDataFound.vue'
|
||||||
import SiteAddEditDialog from '@/components/dialog/SiteAddEditDialog.vue'
|
import SiteAddEditDialog from '@/components/dialog/SiteAddEditDialog.vue'
|
||||||
|
import { useDisplay } from 'vuetify'
|
||||||
|
|
||||||
|
// 显示器宽度
|
||||||
|
const display = useDisplay()
|
||||||
|
|
||||||
|
// APP
|
||||||
|
const appMode = computed(() => {
|
||||||
|
return localStorage.getItem('MP_APPMODE') == '1' && display.mdAndDown.value
|
||||||
|
})
|
||||||
|
|
||||||
// 数据列表
|
// 数据列表
|
||||||
const dataList = ref<Site[]>([])
|
const dataList = ref<Site[]>([])
|
||||||
@@ -67,7 +76,16 @@ onBeforeMount(fetchData)
|
|||||||
error-description="已添加并支持的站点将会在这里显示。"
|
error-description="已添加并支持的站点将会在这里显示。"
|
||||||
/>
|
/>
|
||||||
<!-- 新增站点按钮 -->
|
<!-- 新增站点按钮 -->
|
||||||
<VFab icon="mdi-plus" location="bottom" size="x-large" fixed app appear @click="siteAddDialog = true" />
|
<VFab
|
||||||
|
icon="mdi-plus"
|
||||||
|
location="bottom"
|
||||||
|
size="x-large"
|
||||||
|
fixed
|
||||||
|
app
|
||||||
|
appear
|
||||||
|
@click="siteAddDialog = true"
|
||||||
|
:class="{ 'mb-12': appMode }"
|
||||||
|
/>
|
||||||
<!-- 新增站点弹窗 -->
|
<!-- 新增站点弹窗 -->
|
||||||
<SiteAddEditDialog
|
<SiteAddEditDialog
|
||||||
v-if="siteAddDialog"
|
v-if="siteAddDialog"
|
||||||
|
|||||||
@@ -7,6 +7,15 @@ import SubscribeCard from '@/components/cards/SubscribeCard.vue'
|
|||||||
import SubscribeEditDialog from '@/components/dialog/SubscribeEditDialog.vue'
|
import SubscribeEditDialog from '@/components/dialog/SubscribeEditDialog.vue'
|
||||||
import SubscribeHistoryDialog from '@/components/dialog/SubscribeHistoryDialog.vue'
|
import SubscribeHistoryDialog from '@/components/dialog/SubscribeHistoryDialog.vue'
|
||||||
import store from '@/store'
|
import store from '@/store'
|
||||||
|
import { useDisplay } from 'vuetify'
|
||||||
|
|
||||||
|
// 显示器宽度
|
||||||
|
const display = useDisplay()
|
||||||
|
|
||||||
|
// APP
|
||||||
|
const appMode = computed(() => {
|
||||||
|
return localStorage.getItem('MP_APPMODE') == '1' && display.mdAndDown.value
|
||||||
|
})
|
||||||
|
|
||||||
// 输入参数
|
// 输入参数
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -97,13 +106,14 @@ onMounted(async () => {
|
|||||||
app
|
app
|
||||||
appear
|
appear
|
||||||
@click="subscribeEditDialog = true"
|
@click="subscribeEditDialog = true"
|
||||||
|
:class="{ 'mb-12': appMode }"
|
||||||
/>
|
/>
|
||||||
<VFab
|
<VFab
|
||||||
v-if="store.state.auth.superUser"
|
v-if="store.state.auth.superUser"
|
||||||
icon="mdi-history"
|
icon="mdi-history"
|
||||||
color="info"
|
color="info"
|
||||||
location="bottom"
|
location="bottom"
|
||||||
class="mb-16"
|
:class="appMode ? 'mb-28' : 'mb-16'"
|
||||||
size="x-large"
|
size="x-large"
|
||||||
fixed
|
fixed
|
||||||
app
|
app
|
||||||
|
|||||||
Reference in New Issue
Block a user