mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-09-07 00:36:41 +08:00
refactor: replace Vuex with Pinia
This commit is contained in:
+9
-5
@@ -1,6 +1,6 @@
|
|||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import router from '@/router'
|
import router from '@/router'
|
||||||
import store from '@/store'
|
import { useAuthStore } from '@/stores'
|
||||||
|
|
||||||
// 创建axios实例
|
// 创建axios实例
|
||||||
const api = axios.create({
|
const api = axios.create({
|
||||||
@@ -9,10 +9,12 @@ const api = axios.create({
|
|||||||
|
|
||||||
// 添加请求拦截器
|
// 添加请求拦截器
|
||||||
api.interceptors.request.use(config => {
|
api.interceptors.request.use(config => {
|
||||||
|
// 认证 Store
|
||||||
|
const authStore = useAuthStore()
|
||||||
// 在请求头中添加token
|
// 在请求头中添加token
|
||||||
const token = store.state.auth.token
|
if (authStore.token) {
|
||||||
if (token) config.headers.Authorization = `Bearer ${token}`
|
config.headers.Authorization = `Bearer ${authStore.token}`
|
||||||
|
}
|
||||||
return config
|
return config
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -26,8 +28,10 @@ api.interceptors.response.use(
|
|||||||
// 请求超时
|
// 请求超时
|
||||||
return Promise.reject(new Error(error))
|
return Promise.reject(new Error(error))
|
||||||
} else if (error.response.status === 403) {
|
} else if (error.response.status === 403) {
|
||||||
|
// 认证 Store
|
||||||
|
const authStore = useAuthStore()
|
||||||
// 清除登录状态信息
|
// 清除登录状态信息
|
||||||
store.dispatch('auth/logout')
|
authStore.logout()
|
||||||
// token验证失败,跳转到登录页面
|
// token验证失败,跳转到登录页面
|
||||||
router.push('/login')
|
router.push('/login')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import noImage from '@images/no-image.jpeg'
|
|||||||
import tmdbImage from '@images/logos/tmdb.png'
|
import tmdbImage from '@images/logos/tmdb.png'
|
||||||
import doubanImage from '@images/logos/douban-black.png'
|
import doubanImage from '@images/logos/douban-black.png'
|
||||||
import bangumiImage from '@images/logos/bangumi.png'
|
import bangumiImage from '@images/logos/bangumi.png'
|
||||||
|
import { useUserStore } from '@/stores'
|
||||||
|
|
||||||
// 输入参数
|
// 输入参数
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -22,7 +23,8 @@ const props = defineProps({
|
|||||||
// 从 provide 中获取全局设置
|
// 从 provide 中获取全局设置
|
||||||
const globalSettings: any = inject('globalSettings')
|
const globalSettings: any = inject('globalSettings')
|
||||||
|
|
||||||
const store = useStore()
|
// 用户 Store
|
||||||
|
const userStore = useUserStore()
|
||||||
|
|
||||||
// 提示框
|
// 提示框
|
||||||
const $toast = useToast()
|
const $toast = useToast()
|
||||||
@@ -340,7 +342,7 @@ async function getMediaSeasons() {
|
|||||||
// 查询订阅弹窗规则
|
// 查询订阅弹窗规则
|
||||||
async function queryDefaultSubscribeConfig() {
|
async function queryDefaultSubscribeConfig() {
|
||||||
// 非管理员不显示
|
// 非管理员不显示
|
||||||
if (!store.state.auth.superUser) return false
|
if (!userStore.superUser) return false
|
||||||
try {
|
try {
|
||||||
let subscribe_config_url = ''
|
let subscribe_config_url = ''
|
||||||
if (props.media?.type === '电影') subscribe_config_url = 'system/setting/DefaultMovieSubscribeConfig'
|
if (props.media?.type === '电影') subscribe_config_url = 'system/setting/DefaultMovieSubscribeConfig'
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
import { Subscribe, User } from '@/api/types'
|
import { Subscribe, User } from '@/api/types'
|
||||||
import store from '@/store'
|
import { useUserStore } from '@/stores'
|
||||||
import avatar1 from '@images/avatars/avatar-1.png'
|
import avatar1 from '@images/avatars/avatar-1.png'
|
||||||
import { useToast } from 'vue-toast-notification'
|
import { useToast } from 'vue-toast-notification'
|
||||||
import { useConfirm } from 'vuetify-use-dialog'
|
import { useConfirm } from 'vuetify-use-dialog'
|
||||||
@@ -22,10 +22,10 @@ const props = defineProps({
|
|||||||
})
|
})
|
||||||
|
|
||||||
// 当前用户的ID
|
// 当前用户的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'])
|
const emit = defineEmits(['remove', 'save'])
|
||||||
@@ -161,14 +161,7 @@ onMounted(() => {
|
|||||||
</VList>
|
</VList>
|
||||||
</VCardText>
|
</VCardText>
|
||||||
<VCardText class="flex flex-row justify-center">
|
<VCardText class="flex flex-row justify-center">
|
||||||
<VBtn
|
<VBtn v-if="currentUserIsSuperuser" color="primary" class="me-4" @click="editUser"> 编辑 </VBtn>
|
||||||
v-if="currentUserIsSuperuser"
|
|
||||||
color="primary"
|
|
||||||
class="me-4"
|
|
||||||
@click="editUser"
|
|
||||||
>
|
|
||||||
编辑
|
|
||||||
</VBtn>
|
|
||||||
<VBtn
|
<VBtn
|
||||||
v-if="currentUserIsSuperuser && props.user.id != currentLoginUserId"
|
v-if="currentUserIsSuperuser && props.user.id != currentLoginUserId"
|
||||||
color="error"
|
color="error"
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { doneNProgress, startNProgress } from '@/api/nprogress'
|
|||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
import { useDisplay } from 'vuetify'
|
import { useDisplay } from 'vuetify'
|
||||||
import avatar1 from '@images/avatars/avatar-1.png'
|
import avatar1 from '@images/avatars/avatar-1.png'
|
||||||
import store from '@/store'
|
import { useUserStore } from '@/stores'
|
||||||
|
|
||||||
// 显示器宽度
|
// 显示器宽度
|
||||||
const display = useDisplay()
|
const display = useDisplay()
|
||||||
@@ -23,8 +23,11 @@ const props = defineProps({
|
|||||||
oper: String,
|
oper: String,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 用户 Store
|
||||||
|
const userStore = useUserStore()
|
||||||
|
|
||||||
// 当前登录用户名称
|
// 当前登录用户名称
|
||||||
const currentLoginUser = store.state.auth.userName
|
const currentLoginUser = userStore.userName
|
||||||
|
|
||||||
// 用户名
|
// 用户名
|
||||||
const userName = ref('')
|
const userName = ref('')
|
||||||
@@ -199,13 +202,15 @@ async function updateUser() {
|
|||||||
if (oldUserName !== currentUserName.value) {
|
if (oldUserName !== currentUserName.value) {
|
||||||
$toast.success(`【${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 {
|
} else {
|
||||||
$toast.success(`【${userForm.value?.name}】更新成功!`)
|
$toast.success(`【${userForm.value?.name}】更新成功!`)
|
||||||
}
|
}
|
||||||
// 更新本地头像显示
|
// 更新本地头像显示
|
||||||
if (oldAvatar !== currentAvatar.value && isCurrentUser.value) {
|
if (oldAvatar !== currentAvatar.value && isCurrentUser.value) {
|
||||||
store.commit('auth/setAvatar', currentAvatar.value)
|
userStore.setAvatar(currentAvatar.value)
|
||||||
}
|
}
|
||||||
emit('save')
|
emit('save')
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import UserNofification from '@/layouts/components/UserNotification.vue'
|
|||||||
import SearchBar from '@/layouts/components/SearchBar.vue'
|
import SearchBar from '@/layouts/components/SearchBar.vue'
|
||||||
import ShortcutBar from '@/layouts/components/ShortcutBar.vue'
|
import ShortcutBar from '@/layouts/components/ShortcutBar.vue'
|
||||||
import UserProfile from '@/layouts/components/UserProfile.vue'
|
import UserProfile from '@/layouts/components/UserProfile.vue'
|
||||||
import store from '@/store'
|
import { useUserStore } from '@/stores'
|
||||||
import { SystemNavMenus } from '@/router/menu'
|
import { SystemNavMenus } from '@/router/menu'
|
||||||
import { NavMenu } from '@/@layouts/types'
|
import { NavMenu } from '@/@layouts/types'
|
||||||
import { useDisplay } from 'vuetify'
|
import { useDisplay } from 'vuetify'
|
||||||
@@ -16,8 +16,11 @@ import { useDisplay } from 'vuetify'
|
|||||||
const display = useDisplay()
|
const display = useDisplay()
|
||||||
const appMode = inject('pwaMode')
|
const appMode = inject('pwaMode')
|
||||||
|
|
||||||
|
// 用户 Store
|
||||||
|
const userStore = useUserStore()
|
||||||
|
|
||||||
// 是否超级用户
|
// 是否超级用户
|
||||||
let superUser = store.state.auth.superUser
|
let superUser = userStore.superUser
|
||||||
|
|
||||||
// 开始菜单项
|
// 开始菜单项
|
||||||
const startMenus = ref<NavMenu[]>([])
|
const startMenus = ref<NavMenu[]>([])
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useStore } from 'vuex'
|
|
||||||
import { useConfirm } from 'vuetify-use-dialog'
|
import { useConfirm } from 'vuetify-use-dialog'
|
||||||
import { useToast } from 'vue-toast-notification'
|
import { useToast } from 'vue-toast-notification'
|
||||||
import router from '@/router'
|
import router from '@/router'
|
||||||
@@ -7,9 +6,12 @@ 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 UserAuthDialog from '@/components/dialog/UserAuthDialog.vue'
|
import UserAuthDialog from '@/components/dialog/UserAuthDialog.vue'
|
||||||
|
import { useAuthStore, useUserStore } from '@/stores'
|
||||||
|
|
||||||
// Vuex Store
|
// 认证 Store
|
||||||
const store = useStore()
|
const authStore = useAuthStore()
|
||||||
|
// 用户 Store
|
||||||
|
const userStore = useUserStore()
|
||||||
|
|
||||||
// 确认框
|
// 确认框
|
||||||
const createConfirm = useConfirm()
|
const createConfirm = useConfirm()
|
||||||
@@ -29,7 +31,7 @@ const restartDialog = ref(false)
|
|||||||
// 执行注销操作
|
// 执行注销操作
|
||||||
function logout() {
|
function logout() {
|
||||||
// 清除登录状态信息
|
// 清除登录状态信息
|
||||||
store.dispatch('auth/logout')
|
authStore.logout()
|
||||||
// 重定向到登录页面或其他适当的页面
|
// 重定向到登录页面或其他适当的页面
|
||||||
router.push('/login')
|
router.push('/login')
|
||||||
}
|
}
|
||||||
@@ -74,11 +76,11 @@ function siteAuthDone() {
|
|||||||
logout()
|
logout()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 从Vuex Store中获取信息
|
// 从用户 Store中获取信息
|
||||||
const superUser = computed(() => store.state.auth.superUser)
|
const superUser = computed(() => userStore.superUser)
|
||||||
const userName = computed(() => store.state.auth.userName)
|
const userName = computed(() => userStore.userName)
|
||||||
const avatar = computed(() => store.state.auth.avatar || avatar1)
|
const avatar = computed(() => userStore.avatar || avatar1)
|
||||||
const userLevel = computed(() => store.state.auth.level)
|
const userLevel = computed(() => userStore.level)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
+7
-6
@@ -8,7 +8,7 @@ import '@/plugins/webfontloader'
|
|||||||
import { createApp } from 'vue'
|
import { createApp } from 'vue'
|
||||||
import vuetify from '@/plugins/vuetify'
|
import vuetify from '@/plugins/vuetify'
|
||||||
import router from '@/router'
|
import router from '@/router'
|
||||||
import store from '@/store'
|
import pinia from '@/stores/index'
|
||||||
|
|
||||||
// 3. 全局组件
|
// 3. 全局组件
|
||||||
import App from '@/App.vue'
|
import App from '@/App.vue'
|
||||||
@@ -65,10 +65,13 @@ async function initializeApp() {
|
|||||||
|
|
||||||
// 注册全局组件
|
// 注册全局组件
|
||||||
initializeApp().then(() => {
|
initializeApp().then(() => {
|
||||||
// 优先注册框架
|
// 1. 注册 UI 框架
|
||||||
app.use(vuetify)
|
app.use(vuetify)
|
||||||
|
|
||||||
// 注册全局组件
|
// 2. 注册状态管理与路由
|
||||||
|
app.use(pinia).use(router)
|
||||||
|
|
||||||
|
// 3. 注册全局组件
|
||||||
app
|
app
|
||||||
.component('VAceEditor', VAceEditor)
|
.component('VAceEditor', VAceEditor)
|
||||||
.component('VApexChart', VueApexCharts)
|
.component('VApexChart', VueApexCharts)
|
||||||
@@ -84,10 +87,8 @@ initializeApp().then(() => {
|
|||||||
.component('VCronField', CronField)
|
.component('VCronField', CronField)
|
||||||
.component('VPathField', PathField)
|
.component('VPathField', PathField)
|
||||||
|
|
||||||
// 注册插件
|
// 4. 注册其他插件
|
||||||
app
|
app
|
||||||
.use(router)
|
|
||||||
.use(store)
|
|
||||||
.use(PerfectScrollbarPlugin)
|
.use(PerfectScrollbarPlugin)
|
||||||
.use(ToastPlugin, {
|
.use(ToastPlugin, {
|
||||||
position: 'bottom-right',
|
position: 'bottom-right',
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { NavMenu } from '@/@layouts/types'
|
import { NavMenu } from '@/@layouts/types'
|
||||||
import { SystemNavMenus } from '@/router/menu'
|
import { SystemNavMenus } from '@/router/menu'
|
||||||
import store from '@/store'
|
import { useUserStore } from '@/stores'
|
||||||
import draggable from 'vuedraggable'
|
import draggable from 'vuedraggable'
|
||||||
|
|
||||||
// 从Vuex Store中获取superuser信息
|
// 从 Store 中获取superuser信息
|
||||||
const superUser = store.state.auth.superUser
|
const superUser = useUserStore().superUser
|
||||||
|
|
||||||
// APP图标顺序
|
// APP图标顺序
|
||||||
const appOrder = ref<string[]>([])
|
const appOrder = ref<string[]>([])
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import draggable from 'vuedraggable'
|
|||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
import { isNullOrEmptyObject } from '@/@core/utils'
|
import { isNullOrEmptyObject } from '@/@core/utils'
|
||||||
import { DashboardItem } from '@/api/types'
|
import { DashboardItem } from '@/api/types'
|
||||||
import store from '@/store'
|
import { useUserStore } from '@/stores'
|
||||||
import DashboardElement from '@/components/misc/DashboardElement.vue'
|
import DashboardElement from '@/components/misc/DashboardElement.vue'
|
||||||
import { useDisplay } from 'vuetify'
|
import { useDisplay } from 'vuetify'
|
||||||
|
|
||||||
@@ -11,8 +11,8 @@ import { useDisplay } from 'vuetify'
|
|||||||
const display = useDisplay()
|
const display = useDisplay()
|
||||||
const appMode = inject('pwaMode') && display.mdAndDown.value
|
const appMode = inject('pwaMode') && display.mdAndDown.value
|
||||||
|
|
||||||
// 从Vuex Store中获取superuser信息
|
// 从用户 Store 中获取superuser信息
|
||||||
const superUser = store.state.auth.superUser
|
const superUser = useUserStore().superUser
|
||||||
|
|
||||||
// 是否拉升高度
|
// 是否拉升高度
|
||||||
const isElevated = ref(true)
|
const isElevated = ref(true)
|
||||||
|
|||||||
+27
-29
@@ -1,7 +1,8 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { debounce } from 'lodash'
|
import { debounce } from 'lodash'
|
||||||
import { VForm } from 'vuetify/components/VForm'
|
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 { requiredValidator } from '@/@validators'
|
||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
import router from '@/router'
|
import router from '@/router'
|
||||||
@@ -11,10 +12,12 @@ import { checkPrefersColorSchemeIsDark } from '@/@core/utils'
|
|||||||
import { urlBase64ToUint8Array } from '@/@core/utils/navigator'
|
import { urlBase64ToUint8Array } from '@/@core/utils/navigator'
|
||||||
import { saveLocalTheme } from '@/@core/utils/theme'
|
import { saveLocalTheme } from '@/@core/utils/theme'
|
||||||
|
|
||||||
|
// 主题
|
||||||
const { global: globalTheme } = useTheme()
|
const { global: globalTheme } = useTheme()
|
||||||
|
// 认证 Store
|
||||||
// Vuex Store
|
const authStore = useAuthStore()
|
||||||
const store = useStore()
|
//用户 Store
|
||||||
|
const userStore = useUserStore()
|
||||||
|
|
||||||
// 表单
|
// 表单
|
||||||
const form = ref({
|
const form = ref({
|
||||||
@@ -119,7 +122,7 @@ async function afterLogin(superuser: boolean) {
|
|||||||
// 生效主题配置
|
// 生效主题配置
|
||||||
await setTheme()
|
await setTheme()
|
||||||
// 跳转到首页或回原始页面
|
// 跳转到首页或回原始页面
|
||||||
router.push(store.state.auth.originalPath ?? '/')
|
router.push(authStore.originalPath ?? '/')
|
||||||
// 订阅推送通知
|
// 订阅推送通知
|
||||||
if (superuser) await subscribeForPushNotifications()
|
if (superuser) await subscribeForPushNotifications()
|
||||||
}
|
}
|
||||||
@@ -147,30 +150,25 @@ function login() {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then((response: any) => {
|
.then((response: any) => {
|
||||||
// 获取token
|
const authPayLoad: authState = {
|
||||||
const token = response.access_token
|
token: response.access_token,
|
||||||
const superUser = response.super_user
|
remember: form.value.remember,
|
||||||
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
|
|
||||||
|
|
||||||
// 更新token和remember状态到Vuex Store
|
const userPayload: userState = {
|
||||||
store.dispatch('auth/login', {
|
superUser: response.super_user,
|
||||||
token,
|
userID: response.user_id,
|
||||||
remember,
|
userName: response.user_name,
|
||||||
superUser,
|
avatar: response.avatar,
|
||||||
userID,
|
level: response.level,
|
||||||
userName,
|
permissions: response.permissions,
|
||||||
avatar,
|
}
|
||||||
level,
|
|
||||||
permissions,
|
authStore.login(authPayLoad)
|
||||||
})
|
userStore.loginUser(userPayload)
|
||||||
|
|
||||||
// 登录后处理
|
// 登录后处理
|
||||||
afterLogin(superUser)
|
afterLogin(userPayload.superUser)
|
||||||
})
|
})
|
||||||
.catch((error: any) => {
|
.catch((error: any) => {
|
||||||
// 登录失败,显示错误提示
|
// 登录失败,显示错误提示
|
||||||
@@ -191,9 +189,9 @@ function startBackgroundRotation() {
|
|||||||
|
|
||||||
// 自动登录
|
// 自动登录
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
// 从Vuex Store中获取token和remember状态
|
// 获取token和remember状态
|
||||||
const token = store.state.auth.token
|
const token = authStore.token
|
||||||
const remember = store.state.auth.remember
|
const remember = authStore.remember
|
||||||
|
|
||||||
// 如果token存在,且保持登录状态为true,则跳转到首页
|
// 如果token存在,且保持登录状态为true,则跳转到首页
|
||||||
if (token && remember) {
|
if (token && remember) {
|
||||||
|
|||||||
+5
-3
@@ -1,6 +1,6 @@
|
|||||||
import { createRouter, createWebHashHistory } from 'vue-router'
|
import { createRouter, createWebHashHistory } from 'vue-router'
|
||||||
import { configureNProgress } from '@/api/nprogress'
|
import { configureNProgress } from '@/api/nprogress'
|
||||||
import store from '@/store'
|
import { useAuthStore } from '@/stores'
|
||||||
|
|
||||||
// Nprogress
|
// Nprogress
|
||||||
configureNProgress()
|
configureNProgress()
|
||||||
@@ -215,9 +215,11 @@ function abortAllControllers() {
|
|||||||
|
|
||||||
// 路由导航守卫
|
// 路由导航守卫
|
||||||
router.beforeEach((to: any, from: any, next: any) => {
|
router.beforeEach((to: any, from: any, next: any) => {
|
||||||
|
// 认证 Store
|
||||||
|
const authStore = useAuthStore()
|
||||||
// 总是记录非login路由
|
// 总是记录非login路由
|
||||||
if (to.fullPath != '/login') store.state.auth.originalPath = to.fullPath
|
if (to.fullPath != '/login') authStore.originalPath = to.fullPath
|
||||||
const isAuthenticated = store.state.auth.token !== null
|
const isAuthenticated = authStore.token !== null
|
||||||
if (to.meta.requiresAuth && !isAuthenticated) {
|
if (to.meta.requiresAuth && !isAuthenticated) {
|
||||||
next('/login')
|
next('/login')
|
||||||
} else {
|
} 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
|
|
||||||
@@ -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,
|
||||||
|
},
|
||||||
|
})
|
||||||
@@ -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 }
|
||||||
@@ -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 }
|
||||||
|
}
|
||||||
@@ -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 { useTheme } from 'vuetify'
|
||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
import { hexToRgb } from '@layouts/utils'
|
import { hexToRgb } from '@layouts/utils'
|
||||||
|
import { useUserStore } from '@/stores'
|
||||||
|
|
||||||
const vuetifyTheme = useTheme()
|
const vuetifyTheme = useTheme()
|
||||||
|
|
||||||
// 从Vuex Store中获取信息
|
// 用户 Store
|
||||||
const store = useStore()
|
const userStore = useUserStore()
|
||||||
const superUser = store.state.auth.superUser
|
const superUser = userStore.superUser
|
||||||
|
|
||||||
const options = controlledComputed(
|
const options = controlledComputed(
|
||||||
() => vuetifyTheme.name.value,
|
() => vuetifyTheme.name.value,
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { formatSeason } from '@/@core/utils/formatters'
|
|||||||
import router from '@/router'
|
import router from '@/router'
|
||||||
import SubscribeEditDialog from '@/components/dialog/SubscribeEditDialog.vue'
|
import SubscribeEditDialog from '@/components/dialog/SubscribeEditDialog.vue'
|
||||||
import { isNullOrEmptyObject } from '@/@core/utils'
|
import { isNullOrEmptyObject } from '@/@core/utils'
|
||||||
|
import { useUserStore } from '@/stores'
|
||||||
|
|
||||||
// 输入参数
|
// 输入参数
|
||||||
const mediaProps = defineProps({
|
const mediaProps = defineProps({
|
||||||
@@ -22,7 +23,8 @@ const mediaProps = defineProps({
|
|||||||
// 从 provide 中获取全局设置
|
// 从 provide 中获取全局设置
|
||||||
const globalSettings: any = inject('globalSettings')
|
const globalSettings: any = inject('globalSettings')
|
||||||
|
|
||||||
const store = useStore()
|
// 用户 Store
|
||||||
|
const userStore = useUserStore()
|
||||||
|
|
||||||
// 提示框
|
// 提示框
|
||||||
const $toast = useToast()
|
const $toast = useToast()
|
||||||
@@ -466,7 +468,7 @@ async function handlePlay() {
|
|||||||
|
|
||||||
async function queryDefaultSubscribeConfig() {
|
async function queryDefaultSubscribeConfig() {
|
||||||
// 非管理员不显示
|
// 非管理员不显示
|
||||||
if (!store.state.auth.superUser) return false
|
if (!userStore.superUser) return false
|
||||||
try {
|
try {
|
||||||
let subscribe_config_url = ''
|
let subscribe_config_url = ''
|
||||||
if (mediaProps.type === '电影') subscribe_config_url = 'system/setting/DefaultMovieSubscribeConfig'
|
if (mediaProps.type === '电影') subscribe_config_url = 'system/setting/DefaultMovieSubscribeConfig'
|
||||||
|
|||||||
@@ -4,13 +4,16 @@ import api from '@/api'
|
|||||||
import type { DownloadingInfo } from '@/api/types'
|
import type { DownloadingInfo } from '@/api/types'
|
||||||
import NoDataFound from '@/components/NoDataFound.vue'
|
import NoDataFound from '@/components/NoDataFound.vue'
|
||||||
import DownloadingCard from '@/components/cards/DownloadingCard.vue'
|
import DownloadingCard from '@/components/cards/DownloadingCard.vue'
|
||||||
import store from '@/store'
|
import { useUserStore } from '@/stores'
|
||||||
|
|
||||||
// 定义输入参数
|
// 定义输入参数
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
name: string
|
name: string
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
// 用户 Store
|
||||||
|
const userStore = useUserStore()
|
||||||
|
|
||||||
// 定时器
|
// 定时器
|
||||||
let refreshTimer: NodeJS.Timeout | null = null
|
let refreshTimer: NodeJS.Timeout | null = null
|
||||||
|
|
||||||
@@ -42,9 +45,9 @@ function onRefresh() {
|
|||||||
|
|
||||||
// 过滤数据,管理员用户显示全部,非管理员只显示自己的订阅
|
// 过滤数据,管理员用户显示全部,非管理员只显示自己的订阅
|
||||||
const filteredDataList = computed(() => {
|
const filteredDataList = computed(() => {
|
||||||
// 从Vuex Store中获取用户信息
|
// 从 Store 中获取用户信息
|
||||||
const superUser = store.state.auth.superUser
|
const superUser = userStore.superUser
|
||||||
const userName = store.state.auth.userName
|
const userName = userStore.userName
|
||||||
if (superUser) return dataList.value
|
if (superUser) return dataList.value
|
||||||
else return dataList.value.filter(data => data.userid === userName || data.username === userName)
|
else return dataList.value.filter(data => data.userid === userName || data.username === userName)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -6,13 +6,16 @@ import NoDataFound from '@/components/NoDataFound.vue'
|
|||||||
import SubscribeCard from '@/components/cards/SubscribeCard.vue'
|
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 { useUserStore } from '@/stores'
|
||||||
import { useDisplay } from 'vuetify'
|
import { useDisplay } from 'vuetify'
|
||||||
|
|
||||||
// APP
|
// APP
|
||||||
const display = useDisplay()
|
const display = useDisplay()
|
||||||
const appMode = inject('pwaMode') && display.mdAndDown.value
|
const appMode = inject('pwaMode') && display.mdAndDown.value
|
||||||
|
|
||||||
|
// 用户 Store
|
||||||
|
const userStore = useUserStore()
|
||||||
|
|
||||||
// 输入参数
|
// 输入参数
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
type: String,
|
type: String,
|
||||||
@@ -46,9 +49,9 @@ const displayList = ref<Subscribe[]>([])
|
|||||||
|
|
||||||
// 监听dataList变化,同步更新displayList
|
// 监听dataList变化,同步更新displayList
|
||||||
watch(dataList, () => {
|
watch(dataList, () => {
|
||||||
// 从Vuex Store中获取用户信息
|
// 从 Store 中获取用户信息
|
||||||
const superUser = store.state.auth.superUser
|
const superUser = userStore.superUser
|
||||||
const userName = store.state.auth.userName
|
const userName = userStore.userName
|
||||||
if (superUser) displayList.value = dataList.value.filter(data => data.type === props.type)
|
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)
|
else displayList.value = dataList.value.filter(data => data.type === props.type && data.username === userName)
|
||||||
// 排序
|
// 排序
|
||||||
@@ -163,7 +166,7 @@ onActivated(async () => {
|
|||||||
<!-- 底部操作按钮 -->
|
<!-- 底部操作按钮 -->
|
||||||
<div v-if="isRefreshed">
|
<div v-if="isRefreshed">
|
||||||
<VFab
|
<VFab
|
||||||
v-if="store.state.auth.superUser"
|
v-if="userStore.superUser"
|
||||||
icon="mdi-clipboard-edit"
|
icon="mdi-clipboard-edit"
|
||||||
location="bottom"
|
location="bottom"
|
||||||
size="x-large"
|
size="x-large"
|
||||||
@@ -174,7 +177,7 @@ onActivated(async () => {
|
|||||||
:class="{ 'mb-12': appMode }"
|
:class="{ 'mb-12': appMode }"
|
||||||
/>
|
/>
|
||||||
<VFab
|
<VFab
|
||||||
v-if="store.state.auth.superUser"
|
v-if="userStore.superUser"
|
||||||
icon="mdi-history"
|
icon="mdi-history"
|
||||||
color="info"
|
color="info"
|
||||||
location="bottom"
|
location="bottom"
|
||||||
|
|||||||
@@ -3,16 +3,19 @@ import api from '@/api'
|
|||||||
import type { Plugin, Site, Subscribe } from '@/api/types'
|
import type { Plugin, Site, Subscribe } from '@/api/types'
|
||||||
import { SystemNavMenus, SettingTabs } from '@/router/menu'
|
import { SystemNavMenus, SettingTabs } from '@/router/menu'
|
||||||
import { NavMenu } from '@/@layouts/types'
|
import { NavMenu } from '@/@layouts/types'
|
||||||
import store from '@/store'
|
import { useUserStore } from '@/stores'
|
||||||
|
|
||||||
// 路由
|
// 路由
|
||||||
const router = useRouter()
|
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'])
|
const emit = defineEmits(['close'])
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import api from '@/api'
|
|||||||
import type { User } from '@/api/types'
|
import type { User } from '@/api/types'
|
||||||
import avatar1 from '@images/avatars/avatar-1.png'
|
import avatar1 from '@images/avatars/avatar-1.png'
|
||||||
import { useDisplay } from 'vuetify'
|
import { useDisplay } from 'vuetify'
|
||||||
import store from '@/store'
|
import { useUserStore } from '@/stores'
|
||||||
|
|
||||||
// 显示器宽度
|
// 显示器宽度
|
||||||
const display = useDisplay()
|
const display = useDisplay()
|
||||||
@@ -16,6 +16,9 @@ const isConfirmPasswordVisible = ref(false)
|
|||||||
const newPassword = ref('')
|
const newPassword = ref('')
|
||||||
const confirmPassword = ref('')
|
const confirmPassword = ref('')
|
||||||
|
|
||||||
|
// 用户 Store
|
||||||
|
const userStore = useUserStore()
|
||||||
|
|
||||||
// 提示框
|
// 提示框
|
||||||
const $toast = useToast()
|
const $toast = useToast()
|
||||||
|
|
||||||
@@ -53,13 +56,7 @@ const accountInfo = ref<User>({
|
|||||||
avatar: '',
|
avatar: '',
|
||||||
is_otp: false,
|
is_otp: false,
|
||||||
permissions: {},
|
permissions: {},
|
||||||
settings: {
|
settings: {},
|
||||||
wechat_userid: null,
|
|
||||||
telegram_userid: null,
|
|
||||||
slack_userid: null,
|
|
||||||
vocechat_userid: null,
|
|
||||||
synologychat_userid: null,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// 二维码信息
|
// 二维码信息
|
||||||
@@ -149,13 +146,13 @@ async function saveAccountInfo() {
|
|||||||
if (oldUserName !== currentUserName.value) {
|
if (oldUserName !== currentUserName.value) {
|
||||||
$toast.success(`【${oldUserName}】更名【${currentUserName.value}】,用户信息保存成功!`)
|
$toast.success(`【${oldUserName}】更名【${currentUserName.value}】,用户信息保存成功!`)
|
||||||
// 更新本地用户名显示
|
// 更新本地用户名显示
|
||||||
store.commit('auth/setUserName', currentUserName.value)
|
userStore.setUserName(currentUserName.value)
|
||||||
} else {
|
} else {
|
||||||
$toast.success('用户信息保存成功!')
|
$toast.success('用户信息保存成功!')
|
||||||
}
|
}
|
||||||
// 更新本地头像显示
|
// 更新本地头像显示
|
||||||
if (oldAvatar !== currentAvatar.value) {
|
if (oldAvatar !== currentAvatar.value) {
|
||||||
store.commit('auth/setAvatar', currentAvatar.value)
|
userStore.setAvatar(currentAvatar.value)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (oldAvatar !== currentAvatar.value) {
|
if (oldAvatar !== currentAvatar.value) {
|
||||||
@@ -238,9 +235,9 @@ onMounted(() => {
|
|||||||
|
|
||||||
// 监听 localStorage 中的用户头像变化
|
// 监听 localStorage 中的用户头像变化
|
||||||
watch(
|
watch(
|
||||||
() => store.state.auth.avatar,
|
() => userStore.avatar,
|
||||||
() => {
|
() => {
|
||||||
currentAvatar.value = store.state.auth.avatar
|
currentAvatar.value = userStore.avatar
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user