mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-09-05 07:28:37 +08:00
Refactor navigator utility functions and add isPWA check
This commit is contained in:
@@ -2,8 +2,7 @@
|
|||||||
export async function getClipboardContent() {
|
export async function getClipboardContent() {
|
||||||
if (navigator.clipboard && window.isSecureContext) {
|
if (navigator.clipboard && window.isSecureContext) {
|
||||||
return await navigator.clipboard.readText()
|
return await navigator.clipboard.readText()
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
const input = document.createElement('textarea')
|
const input = document.createElement('textarea')
|
||||||
document.body.appendChild(input)
|
document.body.appendChild(input)
|
||||||
input.select()
|
input.select()
|
||||||
@@ -18,8 +17,7 @@ export async function getClipboardContent() {
|
|||||||
export async function copyToClipboard(content: string) {
|
export async function copyToClipboard(content: string) {
|
||||||
if (navigator.clipboard && window.isSecureContext) {
|
if (navigator.clipboard && window.isSecureContext) {
|
||||||
await navigator.clipboard.writeText(content)
|
await navigator.clipboard.writeText(content)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
const input = document.createElement('textarea')
|
const input = document.createElement('textarea')
|
||||||
input.value = content
|
input.value = content
|
||||||
document.body.appendChild(input)
|
document.body.appendChild(input)
|
||||||
@@ -42,3 +40,12 @@ export function urlBase64ToUint8Array(base64String: string) {
|
|||||||
}
|
}
|
||||||
return outputArray
|
return outputArray
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 判断是否为PWA
|
||||||
|
export const isPWA = async (): Promise<boolean> => {
|
||||||
|
if ('serviceWorker' in navigator) {
|
||||||
|
const registrations = await navigator.serviceWorker.getRegistrations()
|
||||||
|
return registrations.length > 0
|
||||||
|
}
|
||||||
|
return (window.navigator as any).standalone === true
|
||||||
|
}
|
||||||
|
|||||||
@@ -92,7 +92,9 @@ const canEditUser = computed(() => {
|
|||||||
|
|
||||||
// 计算是否有用户管理权限
|
// 计算是否有用户管理权限
|
||||||
const canManageUser = computed(() => {
|
const canManageUser = computed(() => {
|
||||||
return canEditUser
|
if (props.user.name == currentLoginUser) return false
|
||||||
|
if (store.state.auth.superUser) return true
|
||||||
|
return false
|
||||||
})
|
})
|
||||||
|
|
||||||
// 用户重新完成时
|
// 用户重新完成时
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ const userForm = ref<User>({
|
|||||||
name: props.username ?? '',
|
name: props.username ?? '',
|
||||||
password: '',
|
password: '',
|
||||||
email: '',
|
email: '',
|
||||||
is_active: false,
|
is_active: true,
|
||||||
is_superuser: false,
|
is_superuser: false,
|
||||||
avatar: avatar1,
|
avatar: avatar1,
|
||||||
is_otp: false,
|
is_otp: false,
|
||||||
|
|||||||
@@ -15,9 +15,7 @@ import { useDisplay } from 'vuetify'
|
|||||||
const display = useDisplay()
|
const display = useDisplay()
|
||||||
|
|
||||||
// APP
|
// APP
|
||||||
const appMode = computed(() => {
|
const appMode = inject('appMode')
|
||||||
return localStorage.getItem('MP_APPMODE') != '0' && display.mdAndDown.value
|
|
||||||
})
|
|
||||||
|
|
||||||
// 输入参数
|
// 输入参数
|
||||||
const inProps = defineProps({
|
const inProps = defineProps({
|
||||||
@@ -119,7 +117,7 @@ const currentImgLink = ref('')
|
|||||||
|
|
||||||
// 大小控制
|
// 大小控制
|
||||||
const scrollStyle = computed(() => {
|
const scrollStyle = computed(() => {
|
||||||
return appMode.value
|
return appMode
|
||||||
? 'height: calc(100vh - 15.5rem - env(safe-area-inset-bottom) - 3.5rem)'
|
? 'height: calc(100vh - 15.5rem - env(safe-area-inset-bottom) - 3.5rem)'
|
||||||
: 'height: calc(100vh - 14.5rem - env(safe-area-inset-bottom)'
|
: 'height: calc(100vh - 14.5rem - env(safe-area-inset-bottom)'
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -14,9 +14,7 @@ import { NavMenu } from '@/@layouts/types'
|
|||||||
import { useDisplay } from 'vuetify'
|
import { useDisplay } from 'vuetify'
|
||||||
|
|
||||||
const display = useDisplay()
|
const display = useDisplay()
|
||||||
const appMode = computed(() => {
|
const appMode = inject('appMode')
|
||||||
return localStorage.getItem('MP_APPMODE') != '0' && display.mdAndDown.value
|
|
||||||
})
|
|
||||||
|
|
||||||
// 是否超级用户
|
// 是否超级用户
|
||||||
let superUser = store.state.auth.superUser
|
let superUser = store.state.auth.superUser
|
||||||
|
|||||||
@@ -1,10 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useDisplay } from 'vuetify'
|
const appMode = inject('appMode')
|
||||||
|
|
||||||
const display = useDisplay()
|
|
||||||
const appMode = computed(() => {
|
|
||||||
return localStorage.getItem('MP_APPMODE') != '0' && display.mdAndDown.value
|
|
||||||
})
|
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
|
||||||
|
|||||||
@@ -59,20 +59,10 @@ async function restart() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 是否精简模式
|
|
||||||
const isCompactMode = ref(localStorage.getItem('MP_APPMODE') != '0')
|
|
||||||
|
|
||||||
// 从Vuex Store中获取信息
|
// 从Vuex Store中获取信息
|
||||||
const superUser = computed(() =>store.state.auth.superUser)
|
const superUser = computed(() => store.state.auth.superUser)
|
||||||
const userName = computed(() =>store.state.auth.userName)
|
const userName = computed(() => store.state.auth.userName)
|
||||||
const avatar = computed(() => store.state.auth.avatar || avatar1)
|
const avatar = computed(() => store.state.auth.avatar || avatar1)
|
||||||
|
|
||||||
// 监听精简模式切换
|
|
||||||
watch(isCompactMode, value => {
|
|
||||||
localStorage.setItem('MP_APPMODE', value ? '1' : '0')
|
|
||||||
//刷新页面
|
|
||||||
location.reload()
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -97,16 +87,6 @@ watch(isCompactMode, value => {
|
|||||||
<VListItemSubtitle>{{ userName }}</VListItemSubtitle>
|
<VListItemSubtitle>{{ userName }}</VListItemSubtitle>
|
||||||
</VListItem>
|
</VListItem>
|
||||||
|
|
||||||
<!-- Divider -->
|
|
||||||
<VDivider v-if="display.mdAndDown.value" class="my-2" />
|
|
||||||
|
|
||||||
<!-- 👉 AppMode -->
|
|
||||||
<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 -->
|
||||||
|
|||||||
+6
-2
@@ -23,20 +23,24 @@ import MediaInfoCard from './components/cards/MediaInfoCard.vue'
|
|||||||
import TorrentCard from './components/cards/TorrentCard.vue'
|
import TorrentCard from './components/cards/TorrentCard.vue'
|
||||||
import MediaIdSelector from './components/misc/MediaIdSelector.vue'
|
import MediaIdSelector from './components/misc/MediaIdSelector.vue'
|
||||||
import PathField from './components/input/PathField.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 '@core/scss/template/index.scss'
|
||||||
import '@layouts/styles/index.scss'
|
import '@layouts/styles/index.scss'
|
||||||
import '@styles/styles.scss'
|
import '@styles/styles.scss'
|
||||||
import 'vue-toast-notification/dist/theme-bootstrap.css'
|
import 'vue-toast-notification/dist/theme-bootstrap.css'
|
||||||
import 'vue3-perfect-scrollbar/style.css'
|
import 'vue3-perfect-scrollbar/style.css'
|
||||||
import { fetchGlobalSettings } from './api'
|
|
||||||
|
|
||||||
// 创建Vue实例
|
// 创建Vue实例
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
|
|
||||||
async function initializeApp() {
|
async function initializeApp() {
|
||||||
try {
|
try {
|
||||||
|
// 是否为PWA
|
||||||
|
const appMode = await isPWA()
|
||||||
|
app.provide('appMode', appMode)
|
||||||
|
// 全局设置
|
||||||
const globalSettings = await fetchGlobalSettings()
|
const globalSettings = await fetchGlobalSettings()
|
||||||
// 使用 provide 传递全局设置
|
|
||||||
app.provide('globalSettings', globalSettings)
|
app.provide('globalSettings', globalSettings)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to initialize app', error)
|
console.error('Failed to initialize app', error)
|
||||||
|
|||||||
@@ -8,10 +8,7 @@ import DashboardElement from '@/components/misc/DashboardElement.vue'
|
|||||||
import { useDisplay } from 'vuetify'
|
import { useDisplay } from 'vuetify'
|
||||||
|
|
||||||
// APP
|
// APP
|
||||||
const display = useDisplay()
|
const appMode = inject('appMode')
|
||||||
const appMode = computed(() => {
|
|
||||||
return localStorage.getItem('MP_APPMODE') != '0' && display.mdAndDown.value
|
|
||||||
})
|
|
||||||
|
|
||||||
// 从Vuex Store中获取superuser信息
|
// 从Vuex Store中获取superuser信息
|
||||||
const superUser = store.state.auth.superUser
|
const superUser = store.state.auth.superUser
|
||||||
|
|||||||
@@ -7,10 +7,7 @@ import TorrentRowListView from '@/views/discover/TorrentRowListView.vue'
|
|||||||
import { useDisplay } from 'vuetify'
|
import { useDisplay } from 'vuetify'
|
||||||
|
|
||||||
// APP
|
// APP
|
||||||
const display = useDisplay()
|
const appMode = inject('appMode')
|
||||||
const appMode = computed(() => {
|
|
||||||
return localStorage.getItem('MP_APPMODE') != '0' && display.mdAndDown.value
|
|
||||||
})
|
|
||||||
|
|
||||||
// 路由参数
|
// 路由参数
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
|||||||
@@ -8,9 +8,7 @@ import { useDisplay } from 'vuetify'
|
|||||||
const display = useDisplay()
|
const display = useDisplay()
|
||||||
|
|
||||||
// APP
|
// APP
|
||||||
const appMode = computed(() => {
|
const appMode = inject('appMode')
|
||||||
return localStorage.getItem('MP_APPMODE') != '0' && display.mdAndDown.value
|
|
||||||
})
|
|
||||||
|
|
||||||
// 定义输入参数
|
// 定义输入参数
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -38,7 +36,7 @@ const filterForm = reactive({
|
|||||||
|
|
||||||
// 列表样式
|
// 列表样式
|
||||||
const listStyle = computed(() => {
|
const listStyle = computed(() => {
|
||||||
return appMode.value
|
return appMode
|
||||||
? 'height: calc(100vh - 7.5rem - env(safe-area-inset-bottom) - 3.5rem)'
|
? 'height: calc(100vh - 7.5rem - env(safe-area-inset-bottom) - 3.5rem)'
|
||||||
: 'height: calc(100vh - 6.5rem - env(safe-area-inset-bottom)'
|
: 'height: calc(100vh - 6.5rem - env(safe-area-inset-bottom)'
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -16,9 +16,7 @@ const route = useRoute()
|
|||||||
const display = useDisplay()
|
const display = useDisplay()
|
||||||
|
|
||||||
// APP
|
// APP
|
||||||
const appMode = computed(() => {
|
const appMode = inject('appMode')
|
||||||
return localStorage.getItem('MP_APPMODE') != '0' && display.mdAndDown.value
|
|
||||||
})
|
|
||||||
|
|
||||||
// 当前标签
|
// 当前标签
|
||||||
const activeTab = ref(route.query.tab)
|
const activeTab = ref(route.query.tab)
|
||||||
|
|||||||
@@ -10,13 +10,8 @@ import router from '@/router'
|
|||||||
import { useDisplay } from 'vuetify'
|
import { useDisplay } from 'vuetify'
|
||||||
import { storageDict } from '@/api/constants'
|
import { storageDict } from '@/api/constants'
|
||||||
|
|
||||||
// 显示器宽度
|
|
||||||
const display = useDisplay()
|
|
||||||
|
|
||||||
// APP
|
// APP
|
||||||
const appMode = computed(() => {
|
const appMode = inject('appMode')
|
||||||
return localStorage.getItem('MP_APPMODE') != '0' && display.mdAndDown.value
|
|
||||||
})
|
|
||||||
|
|
||||||
// 提示框
|
// 提示框
|
||||||
const $toast = useToast()
|
const $toast = useToast()
|
||||||
@@ -126,7 +121,7 @@ const TransferDict: { [key: string]: string } = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const tableStyle = computed(() => {
|
const tableStyle = computed(() => {
|
||||||
return appMode.value
|
return appMode
|
||||||
? 'height: calc(100vh - 15.5rem - env(safe-area-inset-bottom) - 3.5rem)'
|
? 'height: calc(100vh - 15.5rem - env(safe-area-inset-bottom) - 3.5rem)'
|
||||||
: 'height: calc(100vh - 14.5rem - env(safe-area-inset-bottom)'
|
: 'height: calc(100vh - 14.5rem - env(safe-area-inset-bottom)'
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -7,13 +7,8 @@ import NoDataFound from '@/components/NoDataFound.vue'
|
|||||||
import SiteAddEditDialog from '@/components/dialog/SiteAddEditDialog.vue'
|
import SiteAddEditDialog from '@/components/dialog/SiteAddEditDialog.vue'
|
||||||
import { useDisplay } from 'vuetify'
|
import { useDisplay } from 'vuetify'
|
||||||
|
|
||||||
// 显示器宽度
|
|
||||||
const display = useDisplay()
|
|
||||||
|
|
||||||
// APP
|
// APP
|
||||||
const appMode = computed(() => {
|
const appMode = inject('appMode')
|
||||||
return localStorage.getItem('MP_APPMODE') != '0' && display.mdAndDown.value
|
|
||||||
})
|
|
||||||
|
|
||||||
// 站点列表
|
// 站点列表
|
||||||
const siteList = ref<Site[]>([])
|
const siteList = ref<Site[]>([])
|
||||||
|
|||||||
@@ -9,13 +9,8 @@ import SubscribeHistoryDialog from '@/components/dialog/SubscribeHistoryDialog.v
|
|||||||
import store from '@/store'
|
import store from '@/store'
|
||||||
import { useDisplay } from 'vuetify'
|
import { useDisplay } from 'vuetify'
|
||||||
|
|
||||||
// 显示器宽度
|
|
||||||
const display = useDisplay()
|
|
||||||
|
|
||||||
// APP
|
// APP
|
||||||
const appMode = computed(() => {
|
const appMode = inject('appMode')
|
||||||
return localStorage.getItem('MP_APPMODE') != '0' && display.mdAndDown.value
|
|
||||||
})
|
|
||||||
|
|
||||||
// 输入参数
|
// 输入参数
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
|
|||||||
@@ -7,10 +7,7 @@ import UserCard from '@/components/cards/UserCard.vue'
|
|||||||
import UserAddEditDialog from '@/components/dialog/UserAddEditDialog.vue'
|
import UserAddEditDialog from '@/components/dialog/UserAddEditDialog.vue'
|
||||||
|
|
||||||
// APP
|
// APP
|
||||||
const display = useDisplay()
|
const appMode = inject('appMode')
|
||||||
const appMode = computed(() => {
|
|
||||||
return localStorage.getItem('MP_APPMODE') != '0' && display.mdAndDown.value
|
|
||||||
})
|
|
||||||
|
|
||||||
// 是否刷新过
|
// 是否刷新过
|
||||||
const isRefreshed = ref(false)
|
const isRefreshed = ref(false)
|
||||||
@@ -58,7 +55,7 @@ onActivated(() => {
|
|||||||
<template>
|
<template>
|
||||||
<LoadingBanner v-if="!isRefreshed" class="mt-12" />
|
<LoadingBanner v-if="!isRefreshed" class="mt-12" />
|
||||||
|
|
||||||
<div v-if="allUsers.length > 0" class="grid gap-3 grid-user-card items-start">
|
<div v-if="allUsers.length > 0" class="grid gap-3 grid-user-card">
|
||||||
<UserCard v-for="user in allUsers" :user="user" :users="allUsers" @remove="loadAllUsers" @save="loadAllUsers" />
|
<UserCard v-for="user in allUsers" :user="user" :users="allUsers" @remove="loadAllUsers" @save="loadAllUsers" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user