Refactor navigator utility functions and add isPWA check

This commit is contained in:
jxxghp
2024-10-19 10:39:31 +08:00
parent b3f616ddc6
commit 76a487854b
16 changed files with 38 additions and 82 deletions
+11 -4
View File
@@ -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
}
+3 -1
View File
@@ -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
}) })
// 用户重新完成时 // 用户重新完成时
+1 -1
View File
@@ -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,
+2 -4
View File
@@ -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)'
}) })
+1 -3
View File
@@ -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 -6
View File
@@ -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()
+2 -22
View File
@@ -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
View File
@@ -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)
+1 -4
View File
@@ -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
+1 -4
View File
@@ -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()
+2 -4
View File
@@ -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)'
}) })
+1 -3
View File
@@ -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)
+2 -7
View File
@@ -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)'
}) })
+1 -6
View File
@@ -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[]>([])
+1 -6
View File
@@ -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({
+2 -5
View File
@@ -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>