mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-06-05 07:41:03 +08:00
Merge pull request #303 from Aqr-K/build/reduce-size
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import axios from 'axios'
|
||||
import router from '@/router'
|
||||
import store from '@/store'
|
||||
import { useAuthStore } from '@/stores'
|
||||
|
||||
// 创建axios实例
|
||||
const api = axios.create({
|
||||
@@ -9,10 +9,12 @@ const api = axios.create({
|
||||
|
||||
// 添加请求拦截器
|
||||
api.interceptors.request.use(config => {
|
||||
// 认证 Store
|
||||
const authStore = useAuthStore()
|
||||
// 在请求头中添加token
|
||||
const token = store.state.auth.token
|
||||
if (token) config.headers.Authorization = `Bearer ${token}`
|
||||
|
||||
if (authStore.token) {
|
||||
config.headers.Authorization = `Bearer ${authStore.token}`
|
||||
}
|
||||
return config
|
||||
})
|
||||
|
||||
@@ -26,8 +28,10 @@ api.interceptors.response.use(
|
||||
// 请求超时
|
||||
return Promise.reject(new Error(error))
|
||||
} else if (error.response.status === 403) {
|
||||
// 认证 Store
|
||||
const authStore = useAuthStore()
|
||||
// 清除登录状态信息
|
||||
store.dispatch('auth/logout')
|
||||
authStore.logout()
|
||||
// token验证失败,跳转到登录页面
|
||||
router.push('/login')
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { CustomRule } from '@/api/types'
|
||||
import { useToast } from 'vue-toast-notification'
|
||||
import filter_svg from '@images/svg/filter.svg'
|
||||
import { cloneDeep } from 'lodash'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import { innerFilterRules } from '@/api/constants'
|
||||
|
||||
// 输入参数
|
||||
|
||||
@@ -6,7 +6,7 @@ import { useToast } from 'vue-toast-notification'
|
||||
import type { DownloaderInfo } from '@/api/types'
|
||||
import qbittorrent_image from '@images/logos/qbittorrent.png'
|
||||
import transmission_image from '@images/logos/transmission.png'
|
||||
import { cloneDeep } from 'lodash'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
|
||||
// 定义输入
|
||||
const props = defineProps({
|
||||
@@ -104,7 +104,7 @@ function saveDownloaderInfo() {
|
||||
props.downloaders.forEach(item => {
|
||||
if (item.default && item !== props.downloader) {
|
||||
item.default = false
|
||||
$toast.info(`【${item.name}】存在默认下载器,已替换成【${downloaderInfo.value.name}】`)
|
||||
$toast.info(`存在默认下载器【${item.name}】,已替换成【${downloaderInfo.value.name}】`)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { innerFilterRules } from '@/api/constants'
|
||||
import { CustomRule } from '@/api/types'
|
||||
import { cloneDeep } from 'lodash'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
|
||||
// 输入参数
|
||||
const props = defineProps({
|
||||
|
||||
@@ -6,7 +6,7 @@ import FilterRuleCard from '@/components/cards/FilterRuleCard.vue'
|
||||
import { useToast } from 'vue-toast-notification'
|
||||
import ImportCodeDialog from '@/components/dialog/ImportCodeDialog.vue'
|
||||
import filter_group_svg from '@images/svg/filter-group.svg'
|
||||
import { cloneDeep } from 'lodash'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
|
||||
// 输入参数
|
||||
const props = defineProps({
|
||||
|
||||
@@ -11,6 +11,7 @@ import noImage from '@images/no-image.jpeg'
|
||||
import tmdbImage from '@images/logos/tmdb.png'
|
||||
import doubanImage from '@images/logos/douban-black.png'
|
||||
import bangumiImage from '@images/logos/bangumi.png'
|
||||
import { useUserStore } from '@/stores'
|
||||
|
||||
// 输入参数
|
||||
const props = defineProps({
|
||||
@@ -22,7 +23,8 @@ const props = defineProps({
|
||||
// 从 provide 中获取全局设置
|
||||
const globalSettings: any = inject('globalSettings')
|
||||
|
||||
const store = useStore()
|
||||
// 用户 Store
|
||||
const userStore = useUserStore()
|
||||
|
||||
// 提示框
|
||||
const $toast = useToast()
|
||||
@@ -340,7 +342,7 @@ async function getMediaSeasons() {
|
||||
// 查询订阅弹窗规则
|
||||
async function queryDefaultSubscribeConfig() {
|
||||
// 非管理员不显示
|
||||
if (!store.state.auth.superUser) return false
|
||||
if (!userStore.superUser) return false
|
||||
try {
|
||||
let subscribe_config_url = ''
|
||||
if (props.media?.type === '电影') subscribe_config_url = 'system/setting/DefaultMovieSubscribeConfig'
|
||||
|
||||
@@ -5,7 +5,7 @@ import emby_image from '@images/logos/emby.png'
|
||||
import jellyfin_image from '@images/logos/jellyfin.png'
|
||||
import plex_image from '@images/logos/plex.png'
|
||||
import api from '@/api'
|
||||
import { cloneDeep } from 'lodash'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
|
||||
// 定义输入
|
||||
const props = defineProps({
|
||||
|
||||
@@ -7,7 +7,7 @@ import synologychat_image from '@images/logos/synologychat.png'
|
||||
import slack_image from '@images/logos/slack.webp'
|
||||
import chrome_image from '@images/logos/chrome.png'
|
||||
import { useToast } from 'vue-toast-notification'
|
||||
import { cloneDeep } from 'lodash'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
|
||||
// 定义输入
|
||||
const props = defineProps({
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import api from '@/api'
|
||||
import { Subscribe, User } from '@/api/types'
|
||||
import store from '@/store'
|
||||
import { useUserStore } from '@/stores'
|
||||
import avatar1 from '@images/avatars/avatar-1.png'
|
||||
import { useToast } from 'vue-toast-notification'
|
||||
import { useConfirm } from 'vuetify-use-dialog'
|
||||
@@ -22,10 +22,10 @@ const props = defineProps({
|
||||
})
|
||||
|
||||
// 当前用户的ID
|
||||
const currentLoginUserId = computed(() => store.state.auth.userID)
|
||||
const currentLoginUserId = computed(() => useUserStore().userID)
|
||||
|
||||
// 当前用户是否是管理员
|
||||
const currentUserIsSuperuser = computed(() => store.state.auth.superUser)
|
||||
const currentUserIsSuperuser = computed(() => useUserStore().superUser)
|
||||
|
||||
// 定义触发的自定义事件
|
||||
const emit = defineEmits(['remove', 'save'])
|
||||
@@ -161,14 +161,7 @@ onMounted(() => {
|
||||
</VList>
|
||||
</VCardText>
|
||||
<VCardText class="flex flex-row justify-center">
|
||||
<VBtn
|
||||
v-if="currentUserIsSuperuser"
|
||||
color="primary"
|
||||
class="me-4"
|
||||
@click="editUser"
|
||||
>
|
||||
编辑
|
||||
</VBtn>
|
||||
<VBtn v-if="currentUserIsSuperuser" color="primary" class="me-4" @click="editUser"> 编辑 </VBtn>
|
||||
<VBtn
|
||||
v-if="currentUserIsSuperuser && props.user.id != currentLoginUserId"
|
||||
color="error"
|
||||
|
||||
@@ -5,7 +5,7 @@ import { doneNProgress, startNProgress } from '@/api/nprogress'
|
||||
import api from '@/api'
|
||||
import { useDisplay } from 'vuetify'
|
||||
import avatar1 from '@images/avatars/avatar-1.png'
|
||||
import store from '@/store'
|
||||
import { useUserStore } from '@/stores'
|
||||
|
||||
// 显示器宽度
|
||||
const display = useDisplay()
|
||||
@@ -23,8 +23,11 @@ const props = defineProps({
|
||||
oper: String,
|
||||
})
|
||||
|
||||
// 用户 Store
|
||||
const userStore = useUserStore()
|
||||
|
||||
// 当前登录用户名称
|
||||
const currentLoginUser = store.state.auth.userName
|
||||
const currentLoginUser = userStore.userName
|
||||
|
||||
// 用户名
|
||||
const userName = ref('')
|
||||
@@ -199,13 +202,15 @@ async function updateUser() {
|
||||
if (oldUserName !== currentUserName.value) {
|
||||
$toast.success(`【${oldUserName}】更名【${currentUserName.value}】, 更新成功!`)
|
||||
// 如果是当前登录用户,更新当前用户名称显示
|
||||
if (isCurrentUser.value) store.commit('auth/setUserName', currentUserName.value)
|
||||
if (isCurrentUser.value) {
|
||||
userStore.setUserName(currentUserName.value)
|
||||
}
|
||||
} else {
|
||||
$toast.success(`【${userForm.value?.name}】更新成功!`)
|
||||
}
|
||||
// 更新本地头像显示
|
||||
if (oldAvatar !== currentAvatar.value && isCurrentUser.value) {
|
||||
store.commit('auth/setAvatar', currentAvatar.value)
|
||||
userStore.setAvatar(currentAvatar.value)
|
||||
}
|
||||
emit('save')
|
||||
} else {
|
||||
|
||||
@@ -8,7 +8,7 @@ import UserNofification from '@/layouts/components/UserNotification.vue'
|
||||
import SearchBar from '@/layouts/components/SearchBar.vue'
|
||||
import ShortcutBar from '@/layouts/components/ShortcutBar.vue'
|
||||
import UserProfile from '@/layouts/components/UserProfile.vue'
|
||||
import store from '@/store'
|
||||
import { useUserStore } from '@/stores'
|
||||
import { SystemNavMenus } from '@/router/menu'
|
||||
import { NavMenu } from '@/@layouts/types'
|
||||
import { useDisplay } from 'vuetify'
|
||||
@@ -16,8 +16,11 @@ import { useDisplay } from 'vuetify'
|
||||
const display = useDisplay()
|
||||
const appMode = inject('pwaMode')
|
||||
|
||||
// 用户 Store
|
||||
const userStore = useUserStore()
|
||||
|
||||
// 是否超级用户
|
||||
let superUser = store.state.auth.superUser
|
||||
let superUser = userStore.superUser
|
||||
|
||||
// 开始菜单项
|
||||
const startMenus = ref<NavMenu[]>([])
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
import { useStore } from 'vuex'
|
||||
import { useConfirm } from 'vuetify-use-dialog'
|
||||
import { useToast } from 'vue-toast-notification'
|
||||
import router from '@/router'
|
||||
@@ -7,9 +6,12 @@ import avatar1 from '@images/avatars/avatar-1.png'
|
||||
import api from '@/api'
|
||||
import ProgressDialog from '@/components/dialog/ProgressDialog.vue'
|
||||
import UserAuthDialog from '@/components/dialog/UserAuthDialog.vue'
|
||||
import { useAuthStore, useUserStore } from '@/stores'
|
||||
|
||||
// Vuex Store
|
||||
const store = useStore()
|
||||
// 认证 Store
|
||||
const authStore = useAuthStore()
|
||||
// 用户 Store
|
||||
const userStore = useUserStore()
|
||||
|
||||
// 确认框
|
||||
const createConfirm = useConfirm()
|
||||
@@ -29,7 +31,7 @@ const restartDialog = ref(false)
|
||||
// 执行注销操作
|
||||
function logout() {
|
||||
// 清除登录状态信息
|
||||
store.dispatch('auth/logout')
|
||||
authStore.logout()
|
||||
// 重定向到登录页面或其他适当的页面
|
||||
router.push('/login')
|
||||
}
|
||||
@@ -74,11 +76,11 @@ function siteAuthDone() {
|
||||
logout()
|
||||
}
|
||||
|
||||
// 从Vuex Store中获取信息
|
||||
const superUser = computed(() => store.state.auth.superUser)
|
||||
const userName = computed(() => store.state.auth.userName)
|
||||
const avatar = computed(() => store.state.auth.avatar || avatar1)
|
||||
const userLevel = computed(() => store.state.auth.level)
|
||||
// 从用户 Store中获取信息
|
||||
const superUser = computed(() => userStore.superUser)
|
||||
const userName = computed(() => userStore.userName)
|
||||
const avatar = computed(() => userStore.avatar || avatar1)
|
||||
const userLevel = computed(() => userStore.level)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
13
src/main.ts
13
src/main.ts
@@ -8,7 +8,7 @@ import '@/plugins/webfontloader'
|
||||
import { createApp } from 'vue'
|
||||
import vuetify from '@/plugins/vuetify'
|
||||
import router from '@/router'
|
||||
import store from '@/store'
|
||||
import pinia from '@/stores/index'
|
||||
|
||||
// 3. 全局组件
|
||||
import App from '@/App.vue'
|
||||
@@ -65,10 +65,13 @@ async function initializeApp() {
|
||||
|
||||
// 注册全局组件
|
||||
initializeApp().then(() => {
|
||||
// 优先注册框架
|
||||
// 1. 注册 UI 框架
|
||||
app.use(vuetify)
|
||||
|
||||
// 注册全局组件
|
||||
// 2. 注册状态管理与路由
|
||||
app.use(pinia).use(router)
|
||||
|
||||
// 3. 注册全局组件
|
||||
app
|
||||
.component('VAceEditor', VAceEditor)
|
||||
.component('VApexChart', VueApexCharts)
|
||||
@@ -84,10 +87,8 @@ initializeApp().then(() => {
|
||||
.component('VCronField', CronField)
|
||||
.component('VPathField', PathField)
|
||||
|
||||
// 注册插件
|
||||
// 4. 注册其他插件
|
||||
app
|
||||
.use(router)
|
||||
.use(store)
|
||||
.use(PerfectScrollbarPlugin)
|
||||
.use(ToastPlugin, {
|
||||
position: 'bottom-right',
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import { NavMenu } from '@/@layouts/types'
|
||||
import { SystemNavMenus } from '@/router/menu'
|
||||
import store from '@/store'
|
||||
import { useUserStore } from '@/stores'
|
||||
import draggable from 'vuedraggable'
|
||||
|
||||
// 从Vuex Store中获取superuser信息
|
||||
const superUser = store.state.auth.superUser
|
||||
// 从 Store 中获取superuser信息
|
||||
const superUser = useUserStore().superUser
|
||||
|
||||
// APP图标顺序
|
||||
const appOrder = ref<string[]>([])
|
||||
|
||||
@@ -3,7 +3,7 @@ import draggable from 'vuedraggable'
|
||||
import api from '@/api'
|
||||
import { isNullOrEmptyObject } from '@/@core/utils'
|
||||
import { DashboardItem } from '@/api/types'
|
||||
import store from '@/store'
|
||||
import { useUserStore } from '@/stores'
|
||||
import DashboardElement from '@/components/misc/DashboardElement.vue'
|
||||
import { useDisplay } from 'vuetify'
|
||||
|
||||
@@ -11,8 +11,8 @@ import { useDisplay } from 'vuetify'
|
||||
const display = useDisplay()
|
||||
const appMode = inject('pwaMode') && display.mdAndDown.value
|
||||
|
||||
// 从Vuex Store中获取superuser信息
|
||||
const superUser = store.state.auth.superUser
|
||||
// 从用户 Store 中获取superuser信息
|
||||
const superUser = useUserStore().superUser
|
||||
|
||||
// 是否拉升高度
|
||||
const isElevated = ref(true)
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import { debounce } from 'lodash'
|
||||
import { debounce } from 'lodash-es'
|
||||
import { VForm } from 'vuetify/components/VForm'
|
||||
import { useStore } from 'vuex'
|
||||
import { useAuthStore, useUserStore } from '@/stores'
|
||||
import { authState, userState } from '@/stores/types'
|
||||
import { requiredValidator } from '@/@validators'
|
||||
import api from '@/api'
|
||||
import router from '@/router'
|
||||
@@ -11,10 +12,12 @@ import { checkPrefersColorSchemeIsDark } from '@/@core/utils'
|
||||
import { urlBase64ToUint8Array } from '@/@core/utils/navigator'
|
||||
import { saveLocalTheme } from '@/@core/utils/theme'
|
||||
|
||||
// 主题
|
||||
const { global: globalTheme } = useTheme()
|
||||
|
||||
// Vuex Store
|
||||
const store = useStore()
|
||||
// 认证 Store
|
||||
const authStore = useAuthStore()
|
||||
//用户 Store
|
||||
const userStore = useUserStore()
|
||||
|
||||
// 表单
|
||||
const form = ref({
|
||||
@@ -119,7 +122,7 @@ async function afterLogin(superuser: boolean) {
|
||||
// 生效主题配置
|
||||
await setTheme()
|
||||
// 跳转到首页或回原始页面
|
||||
router.push(store.state.auth.originalPath ?? '/')
|
||||
router.push(authStore.originalPath ?? '/')
|
||||
// 订阅推送通知
|
||||
if (superuser) await subscribeForPushNotifications()
|
||||
}
|
||||
@@ -147,30 +150,25 @@ function login() {
|
||||
},
|
||||
})
|
||||
.then((response: any) => {
|
||||
// 获取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
|
||||
const remember = form.value.remember
|
||||
const permissions = response.permissions
|
||||
const authPayLoad: authState = {
|
||||
token: response.access_token,
|
||||
remember: form.value.remember,
|
||||
}
|
||||
|
||||
// 更新token和remember状态到Vuex Store
|
||||
store.dispatch('auth/login', {
|
||||
token,
|
||||
remember,
|
||||
superUser,
|
||||
userID,
|
||||
userName,
|
||||
avatar,
|
||||
level,
|
||||
permissions,
|
||||
})
|
||||
const userPayload: userState = {
|
||||
superUser: response.super_user,
|
||||
userID: response.user_id,
|
||||
userName: response.user_name,
|
||||
avatar: response.avatar,
|
||||
level: response.level,
|
||||
permissions: response.permissions,
|
||||
}
|
||||
|
||||
authStore.login(authPayLoad)
|
||||
userStore.loginUser(userPayload)
|
||||
|
||||
// 登录后处理
|
||||
afterLogin(superUser)
|
||||
afterLogin(userPayload.superUser)
|
||||
})
|
||||
.catch((error: any) => {
|
||||
// 登录失败,显示错误提示
|
||||
@@ -191,9 +189,9 @@ function startBackgroundRotation() {
|
||||
|
||||
// 自动登录
|
||||
onMounted(async () => {
|
||||
// 从Vuex Store中获取token和remember状态
|
||||
const token = store.state.auth.token
|
||||
const remember = store.state.auth.remember
|
||||
// 获取token和remember状态
|
||||
const token = authStore.token
|
||||
const remember = authStore.remember
|
||||
|
||||
// 如果token存在,且保持登录状态为true,则跳转到首页
|
||||
if (token && remember) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { createRouter, createWebHashHistory } from 'vue-router'
|
||||
import { configureNProgress } from '@/api/nprogress'
|
||||
import store from '@/store'
|
||||
import { useAuthStore } from '@/stores'
|
||||
|
||||
// Nprogress
|
||||
configureNProgress()
|
||||
@@ -223,9 +223,11 @@ function abortAllControllers() {
|
||||
|
||||
// 路由导航守卫
|
||||
router.beforeEach((to: any, from: any, next: any) => {
|
||||
// 认证 Store
|
||||
const authStore = useAuthStore()
|
||||
// 总是记录非login路由
|
||||
if (to.fullPath != '/login') store.state.auth.originalPath = to.fullPath
|
||||
const isAuthenticated = store.state.auth.token !== null
|
||||
if (to.fullPath != '/login') authStore.originalPath = to.fullPath
|
||||
const isAuthenticated = authStore.token !== null
|
||||
if (to.meta.requiresAuth && !isAuthenticated) {
|
||||
next('/login')
|
||||
} else {
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
import type { Module } from 'vuex'
|
||||
|
||||
// 定义状态类型
|
||||
interface AuthState {
|
||||
token: string | null
|
||||
remember: boolean
|
||||
superUser: boolean
|
||||
userID: number
|
||||
userName: string
|
||||
avatar: string
|
||||
originalPath: string | null
|
||||
level: number
|
||||
permissions: { [key: string]: any }
|
||||
}
|
||||
|
||||
// 定义根状态类型
|
||||
interface RootState {
|
||||
auth: AuthState
|
||||
}
|
||||
|
||||
// 用户信息模块
|
||||
const authModule: Module<AuthState, RootState> = {
|
||||
namespaced: true,
|
||||
state: {
|
||||
token: null, // 用户令牌
|
||||
remember: false, // 记住我
|
||||
superUser: false, // 超级管理员
|
||||
userID: 999, // 用户ID
|
||||
userName: '', // 用户名
|
||||
avatar: '', // 头像
|
||||
originalPath: null, // 原始路径
|
||||
level: 1, // 用户认证等级 1-未认证 2-已认证
|
||||
permissions: {},
|
||||
},
|
||||
mutations: {
|
||||
setToken(state, token: string) {
|
||||
state.token = token
|
||||
},
|
||||
clearToken(state) {
|
||||
state.token = null
|
||||
},
|
||||
setRemember(state, remember: boolean) {
|
||||
state.remember = remember
|
||||
},
|
||||
setSuperUser(state, superUser: boolean) {
|
||||
state.superUser = superUser
|
||||
},
|
||||
setUserID(state, userID: number) {
|
||||
state.userID = userID
|
||||
},
|
||||
setUserName(state, userName: string) {
|
||||
state.userName = userName
|
||||
},
|
||||
setAvatar(state, avatar: string) {
|
||||
state.avatar = avatar
|
||||
},
|
||||
setOriginalPath(state, originalPath: string) {
|
||||
state.originalPath = originalPath
|
||||
},
|
||||
setLevel(state, level: number) {
|
||||
state.level = level
|
||||
},
|
||||
setPermissions(state, permissions: object) {
|
||||
state.permissions = permissions
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
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)
|
||||
commit('setPermissions', permissions)
|
||||
},
|
||||
logout({ commit }) {
|
||||
commit('clearToken')
|
||||
commit('setOriginalPath', null)
|
||||
},
|
||||
},
|
||||
getters: {
|
||||
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,
|
||||
getLevel: state => state.level,
|
||||
getPermissions: state => state.permissions,
|
||||
},
|
||||
}
|
||||
|
||||
export default authModule
|
||||
@@ -1,19 +0,0 @@
|
||||
import { createStore } from 'vuex'
|
||||
import createPersistedState from 'vuex-persistedstate'
|
||||
import authModule from './auth'
|
||||
|
||||
const store = createStore({
|
||||
modules: {
|
||||
// 用户认证store
|
||||
auth: authModule,
|
||||
},
|
||||
plugins: [
|
||||
createPersistedState({
|
||||
// 配置持久化存储的选项
|
||||
storage: window.localStorage, // 使用 localStorage 存储状态
|
||||
key: 'moviepilot', // 存储的键名
|
||||
}),
|
||||
],
|
||||
})
|
||||
|
||||
export default store
|
||||
42
src/stores/auth.ts
Normal file
42
src/stores/auth.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import type { authState } from '@/stores/types'
|
||||
|
||||
export const useAuthStore = defineStore('auth', {
|
||||
state: (): authState => ({
|
||||
token: null,
|
||||
remember: false,
|
||||
originalPath: null,
|
||||
}),
|
||||
|
||||
// 全局持久化
|
||||
persist: true,
|
||||
|
||||
actions: {
|
||||
setToken(token: string | null) {
|
||||
this.token = token
|
||||
},
|
||||
clearToken() {
|
||||
this.token = null
|
||||
},
|
||||
setRemember(remember: boolean) {
|
||||
this.remember = remember
|
||||
},
|
||||
setOriginalPath(originalPath: string | null) {
|
||||
this.originalPath = originalPath
|
||||
},
|
||||
login(payload: authState) {
|
||||
this.setToken(payload.token)
|
||||
this.setRemember(payload.remember)
|
||||
},
|
||||
logout() {
|
||||
this.clearToken()
|
||||
this.setOriginalPath(null)
|
||||
},
|
||||
},
|
||||
|
||||
getters: {
|
||||
getToken: state => state.token,
|
||||
getRemember: state => state.remember,
|
||||
getOriginalPath: state => state.originalPath,
|
||||
},
|
||||
})
|
||||
16
src/stores/index.ts
Normal file
16
src/stores/index.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { createPinia } from 'pinia'
|
||||
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
|
||||
|
||||
// 创建 Pinia 实例
|
||||
const pinia = createPinia()
|
||||
|
||||
// 使用持久化插件
|
||||
pinia.use(piniaPluginPersistedstate)
|
||||
|
||||
export default pinia
|
||||
|
||||
// 所有的 store
|
||||
import { useAuthStore } from './auth'
|
||||
import { useUserStore } from './user'
|
||||
|
||||
export { useAuthStore, useUserStore }
|
||||
23
src/stores/types.ts
Normal file
23
src/stores/types.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
export interface authState {
|
||||
// 用户令牌
|
||||
token: string | null
|
||||
// 记住我
|
||||
remember: boolean
|
||||
// 原始路径
|
||||
originalPath?: string | null
|
||||
}
|
||||
|
||||
export interface userState {
|
||||
// 是否属于超级管理员
|
||||
superUser: boolean
|
||||
// 用户ID
|
||||
userID: number
|
||||
// 用户名
|
||||
userName: string
|
||||
// 头像
|
||||
avatar: string
|
||||
// 用户认证等级 1-未认证 2-已认证
|
||||
level: number
|
||||
// 权限
|
||||
permissions: { [key: string]: any }
|
||||
}
|
||||
62
src/stores/user.ts
Normal file
62
src/stores/user.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import type { userState } from '@/stores/types'
|
||||
|
||||
export const useUserStore = defineStore('user', {
|
||||
state: (): userState => ({
|
||||
superUser: false,
|
||||
userID: -1,
|
||||
userName: '',
|
||||
avatar: '',
|
||||
level: 1,
|
||||
permissions: {},
|
||||
}),
|
||||
|
||||
// 全局持久化
|
||||
persist: true,
|
||||
|
||||
actions: {
|
||||
setSuperUser(superUser: boolean) {
|
||||
this.superUser = superUser
|
||||
},
|
||||
setUserID(userID: number) {
|
||||
this.userID = userID
|
||||
},
|
||||
setUserName(userName: string) {
|
||||
this.userName = userName
|
||||
},
|
||||
setAvatar(avatar: string) {
|
||||
this.avatar = avatar
|
||||
},
|
||||
setLevel(level: number) {
|
||||
this.level = level
|
||||
},
|
||||
setPermissions(permissions: object) {
|
||||
this.permissions = permissions
|
||||
},
|
||||
loginUser(payload: userState) {
|
||||
this.setSuperUser(payload.superUser)
|
||||
this.setUserID(payload.userID)
|
||||
this.setUserName(payload.userName)
|
||||
this.setAvatar(payload.avatar)
|
||||
this.setLevel(payload.level)
|
||||
this.setPermissions(payload.permissions)
|
||||
},
|
||||
reset() {
|
||||
this.setSuperUser(false)
|
||||
this.setUserID(-1)
|
||||
this.setUserName('')
|
||||
this.setAvatar('')
|
||||
this.setLevel(1)
|
||||
this.setPermissions({})
|
||||
},
|
||||
},
|
||||
|
||||
getters: {
|
||||
getSuperUser: state => state.superUser,
|
||||
getUserID: state => state.userID,
|
||||
getUserName: state => state.userName,
|
||||
getAvatar: state => state.avatar,
|
||||
getLevel: state => state.level,
|
||||
getPermissions: state => state.permissions,
|
||||
},
|
||||
})
|
||||
@@ -2,12 +2,13 @@
|
||||
import { useTheme } from 'vuetify'
|
||||
import api from '@/api'
|
||||
import { hexToRgb } from '@layouts/utils'
|
||||
import { useUserStore } from '@/stores'
|
||||
|
||||
const vuetifyTheme = useTheme()
|
||||
|
||||
// 从Vuex Store中获取信息
|
||||
const store = useStore()
|
||||
const superUser = store.state.auth.superUser
|
||||
// 用户 Store
|
||||
const userStore = useUserStore()
|
||||
const superUser = userStore.superUser
|
||||
|
||||
const options = controlledComputed(
|
||||
() => vuetifyTheme.name.value,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { DiscoverSource } from '@/api/types'
|
||||
import MediaCardListView from '@/views/discover/MediaCardListView.vue'
|
||||
import FormRender from '@/components/render/FormRender.vue'
|
||||
import { cloneDeep, isNull } from 'lodash'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
|
||||
// 输入参数
|
||||
const props = defineProps<{
|
||||
|
||||
@@ -10,6 +10,7 @@ import { formatSeason } from '@/@core/utils/formatters'
|
||||
import router from '@/router'
|
||||
import SubscribeEditDialog from '@/components/dialog/SubscribeEditDialog.vue'
|
||||
import { isNullOrEmptyObject } from '@/@core/utils'
|
||||
import { useUserStore } from '@/stores'
|
||||
|
||||
// 输入参数
|
||||
const mediaProps = defineProps({
|
||||
@@ -22,7 +23,8 @@ const mediaProps = defineProps({
|
||||
// 从 provide 中获取全局设置
|
||||
const globalSettings: any = inject('globalSettings')
|
||||
|
||||
const store = useStore()
|
||||
// 用户 Store
|
||||
const userStore = useUserStore()
|
||||
|
||||
// 提示框
|
||||
const $toast = useToast()
|
||||
@@ -466,7 +468,7 @@ async function handlePlay() {
|
||||
|
||||
async function queryDefaultSubscribeConfig() {
|
||||
// 非管理员不显示
|
||||
if (!store.state.auth.superUser) return false
|
||||
if (!userStore.superUser) return false
|
||||
try {
|
||||
let subscribe_config_url = ''
|
||||
if (mediaProps.type === '电影') subscribe_config_url = 'system/setting/DefaultMovieSubscribeConfig'
|
||||
|
||||
@@ -4,13 +4,16 @@ import api from '@/api'
|
||||
import type { DownloadingInfo } from '@/api/types'
|
||||
import NoDataFound from '@/components/NoDataFound.vue'
|
||||
import DownloadingCard from '@/components/cards/DownloadingCard.vue'
|
||||
import store from '@/store'
|
||||
import { useUserStore } from '@/stores'
|
||||
|
||||
// 定义输入参数
|
||||
const props = defineProps<{
|
||||
name: string
|
||||
}>()
|
||||
|
||||
// 用户 Store
|
||||
const userStore = useUserStore()
|
||||
|
||||
// 定时器
|
||||
let refreshTimer: NodeJS.Timeout | null = null
|
||||
|
||||
@@ -42,9 +45,9 @@ function onRefresh() {
|
||||
|
||||
// 过滤数据,管理员用户显示全部,非管理员只显示自己的订阅
|
||||
const filteredDataList = computed(() => {
|
||||
// 从Vuex Store中获取用户信息
|
||||
const superUser = store.state.auth.superUser
|
||||
const userName = store.state.auth.userName
|
||||
// 从 Store 中获取用户信息
|
||||
const superUser = userStore.superUser
|
||||
const userName = userStore.userName
|
||||
if (superUser) return dataList.value
|
||||
else return dataList.value.filter(data => data.userid === userName || data.username === userName)
|
||||
})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { debounce } from 'lodash'
|
||||
import { debounce } from 'lodash-es'
|
||||
import { useToast } from 'vue-toast-notification'
|
||||
import api from '@/api'
|
||||
import type { TransferHistory } from '@/api/types'
|
||||
|
||||
@@ -6,13 +6,16 @@ import NoDataFound from '@/components/NoDataFound.vue'
|
||||
import SubscribeCard from '@/components/cards/SubscribeCard.vue'
|
||||
import SubscribeEditDialog from '@/components/dialog/SubscribeEditDialog.vue'
|
||||
import SubscribeHistoryDialog from '@/components/dialog/SubscribeHistoryDialog.vue'
|
||||
import store from '@/store'
|
||||
import { useUserStore } from '@/stores'
|
||||
import { useDisplay } from 'vuetify'
|
||||
|
||||
// APP
|
||||
const display = useDisplay()
|
||||
const appMode = inject('pwaMode') && display.mdAndDown.value
|
||||
|
||||
// 用户 Store
|
||||
const userStore = useUserStore()
|
||||
|
||||
// 输入参数
|
||||
const props = defineProps({
|
||||
type: String,
|
||||
@@ -46,9 +49,9 @@ const displayList = ref<Subscribe[]>([])
|
||||
|
||||
// 监听dataList变化,同步更新displayList
|
||||
watch(dataList, () => {
|
||||
// 从Vuex Store中获取用户信息
|
||||
const superUser = store.state.auth.superUser
|
||||
const userName = store.state.auth.userName
|
||||
// 从 Store 中获取用户信息
|
||||
const superUser = userStore.superUser
|
||||
const userName = userStore.userName
|
||||
if (superUser) displayList.value = dataList.value.filter(data => data.type === props.type)
|
||||
else displayList.value = dataList.value.filter(data => data.type === props.type && data.username === userName)
|
||||
// 排序
|
||||
@@ -163,7 +166,7 @@ onActivated(async () => {
|
||||
<!-- 底部操作按钮 -->
|
||||
<div v-if="isRefreshed">
|
||||
<VFab
|
||||
v-if="store.state.auth.superUser"
|
||||
v-if="userStore.superUser"
|
||||
icon="mdi-clipboard-edit"
|
||||
location="bottom"
|
||||
size="x-large"
|
||||
@@ -174,7 +177,7 @@ onActivated(async () => {
|
||||
:class="{ 'mb-12': appMode }"
|
||||
/>
|
||||
<VFab
|
||||
v-if="store.state.auth.superUser"
|
||||
v-if="userStore.superUser"
|
||||
icon="mdi-history"
|
||||
color="info"
|
||||
location="bottom"
|
||||
|
||||
@@ -3,16 +3,19 @@ import api from '@/api'
|
||||
import type { Plugin, Site, Subscribe } from '@/api/types'
|
||||
import { SystemNavMenus, SettingTabs } from '@/router/menu'
|
||||
import { NavMenu } from '@/@layouts/types'
|
||||
import store from '@/store'
|
||||
import { useUserStore } from '@/stores'
|
||||
|
||||
// 路由
|
||||
const router = useRouter()
|
||||
|
||||
// 用户 Store
|
||||
const userStore = useUserStore()
|
||||
|
||||
// 超级用户
|
||||
const superUser = store.state.auth.superUser
|
||||
const superUser = userStore.superUser
|
||||
|
||||
// 当前用户名
|
||||
const userName = store.state.auth.userName
|
||||
const userName = userStore.userName
|
||||
|
||||
// 定义事件
|
||||
const emit = defineEmits(['close'])
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts" setup>
|
||||
import _ from 'lodash'
|
||||
import { cloneDeepWith } from 'lodash-es'
|
||||
import type { Context } from '@/api/types'
|
||||
import TorrentCard from '@/components/cards/TorrentCard.vue'
|
||||
|
||||
@@ -259,7 +259,7 @@ function filterData() {
|
||||
)
|
||||
})
|
||||
if (matchData.length > 0) {
|
||||
const firstData = _.cloneDeepWith(matchData[0]) as SearchTorrent
|
||||
const firstData = cloneDeepWith(matchData[0]) as SearchTorrent
|
||||
if (matchData.length > 1) firstData.more = matchData.slice(1)
|
||||
|
||||
// 显示前20个,4行左右。
|
||||
|
||||
@@ -6,7 +6,7 @@ import api from '@/api'
|
||||
import type { User } from '@/api/types'
|
||||
import avatar1 from '@images/avatars/avatar-1.png'
|
||||
import { useDisplay } from 'vuetify'
|
||||
import store from '@/store'
|
||||
import { useUserStore } from '@/stores'
|
||||
|
||||
// 显示器宽度
|
||||
const display = useDisplay()
|
||||
@@ -16,6 +16,9 @@ const isConfirmPasswordVisible = ref(false)
|
||||
const newPassword = ref('')
|
||||
const confirmPassword = ref('')
|
||||
|
||||
// 用户 Store
|
||||
const userStore = useUserStore()
|
||||
|
||||
// 提示框
|
||||
const $toast = useToast()
|
||||
|
||||
@@ -53,13 +56,7 @@ const accountInfo = ref<User>({
|
||||
avatar: '',
|
||||
is_otp: false,
|
||||
permissions: {},
|
||||
settings: {
|
||||
wechat_userid: null,
|
||||
telegram_userid: null,
|
||||
slack_userid: null,
|
||||
vocechat_userid: null,
|
||||
synologychat_userid: null,
|
||||
},
|
||||
settings: {},
|
||||
})
|
||||
|
||||
// 二维码信息
|
||||
@@ -149,13 +146,13 @@ async function saveAccountInfo() {
|
||||
if (oldUserName !== currentUserName.value) {
|
||||
$toast.success(`【${oldUserName}】更名【${currentUserName.value}】,用户信息保存成功!`)
|
||||
// 更新本地用户名显示
|
||||
store.commit('auth/setUserName', currentUserName.value)
|
||||
userStore.setUserName(currentUserName.value)
|
||||
} else {
|
||||
$toast.success('用户信息保存成功!')
|
||||
}
|
||||
// 更新本地头像显示
|
||||
if (oldAvatar !== currentAvatar.value) {
|
||||
store.commit('auth/setAvatar', currentAvatar.value)
|
||||
userStore.setAvatar(currentAvatar.value)
|
||||
}
|
||||
} else {
|
||||
if (oldAvatar !== currentAvatar.value) {
|
||||
@@ -238,9 +235,9 @@ onMounted(() => {
|
||||
|
||||
// 监听 localStorage 中的用户头像变化
|
||||
watch(
|
||||
() => store.state.auth.avatar,
|
||||
() => userStore.avatar,
|
||||
() => {
|
||||
currentAvatar.value = store.state.auth.avatar
|
||||
currentAvatar.value = userStore.avatar
|
||||
},
|
||||
)
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user