使用Pinia代替Vuex进行数据存储

This commit is contained in:
不做码农 2022-06-10 22:25:19 +08:00
parent ef604d008d
commit 859f8acfe2
41 changed files with 700 additions and 797 deletions

View File

@ -30,6 +30,7 @@
"jsencrypt": "3.2.1", "jsencrypt": "3.2.1",
"md-editor-v3": "^1.11.11", "md-editor-v3": "^1.11.11",
"nprogress": "0.2.0", "nprogress": "0.2.0",
"pinia": "^2.0.14",
"sortablejs": "^1.15.0", "sortablejs": "^1.15.0",
"vue": "^3.2.36", "vue": "^3.2.36",
"vue-clipboard3": "^2.0.0", "vue-clipboard3": "^2.0.0",
@ -37,7 +38,6 @@
"vue-i18n": "^9.1.10", "vue-i18n": "^9.1.10",
"vue-router": "^4.0.15", "vue-router": "^4.0.15",
"vue3-seamless-scroll": "^1.2.0", "vue3-seamless-scroll": "^1.2.0",
"vuex": "4.0.2",
"wangeditor": "^4.7.15" "wangeditor": "^4.7.15"
}, },
"devDependencies": { "devDependencies": {

View File

@ -4,7 +4,8 @@
</el-config-provider> </el-config-provider>
</template> </template>
<script setup> <script setup>
import store from '@/store/index' import useUserStore from './store/modules/user'
import useAppStore from './store/modules/app'
import { ElConfigProvider } from 'element-plus' import { ElConfigProvider } from 'element-plus'
import zh from 'element-plus/lib/locale/lang/zh-cn' // import zh from 'element-plus/lib/locale/lang/zh-cn' //
import en from 'element-plus/lib/locale/lang/en' // import en from 'element-plus/lib/locale/lang/en' //
@ -13,15 +14,15 @@ import tw from 'element-plus/lib/locale/lang/zh-tw' //繁体
const { proxy } = getCurrentInstance() const { proxy } = getCurrentInstance()
const token = computed(() => { const token = computed(() => {
return store.getters.token return useUserStore().token
}) })
const lang = computed(() => { const lang = computed(() => {
return store.getters.language return useAppStore().lang
}) })
const locale = ref(zh) const locale = ref(zh)
const size = ref('small') const size = ref('small')
size.value = store.getters.size size.value = useAppStore().size
watch( watch(
token, token,
(val) => { (val) => {

13
src/auto-import.d.ts vendored
View File

@ -1,19 +1,28 @@
// Generated by 'unplugin-auto-import' // Generated by 'unplugin-auto-import'
// We suggest you to commit this file into source control // We suggest you to commit this file into source control
declare global { declare global {
const acceptHMRUpdate: typeof import('pinia')['acceptHMRUpdate']
const computed: typeof import('vue')['computed'] const computed: typeof import('vue')['computed']
const createApp: typeof import('vue')['createApp'] const createApp: typeof import('vue')['createApp']
const createPinia: typeof import('pinia')['createPinia']
const customRef: typeof import('vue')['customRef'] const customRef: typeof import('vue')['customRef']
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent'] const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
const defineComponent: typeof import('vue')['defineComponent'] const defineComponent: typeof import('vue')['defineComponent']
const defineStore: typeof import('pinia')['defineStore']
const effectScope: typeof import('vue')['effectScope'] const effectScope: typeof import('vue')['effectScope']
const EffectScope: typeof import('vue')['EffectScope'] const EffectScope: typeof import('vue')['EffectScope']
const getActivePinia: typeof import('pinia')['getActivePinia']
const getCurrentInstance: typeof import('vue')['getCurrentInstance'] const getCurrentInstance: typeof import('vue')['getCurrentInstance']
const getCurrentScope: typeof import('vue')['getCurrentScope'] const getCurrentScope: typeof import('vue')['getCurrentScope']
const h: typeof import('vue')['h'] const h: typeof import('vue')['h']
const inject: typeof import('vue')['inject'] const inject: typeof import('vue')['inject']
const isReadonly: typeof import('vue')['isReadonly'] const isReadonly: typeof import('vue')['isReadonly']
const isRef: typeof import('vue')['isRef'] const isRef: typeof import('vue')['isRef']
const mapActions: typeof import('pinia')['mapActions']
const mapGetters: typeof import('pinia')['mapGetters']
const mapState: typeof import('pinia')['mapState']
const mapStores: typeof import('pinia')['mapStores']
const mapWritableState: typeof import('pinia')['mapWritableState']
const markRaw: typeof import('vue')['markRaw'] const markRaw: typeof import('vue')['markRaw']
const nextTick: typeof import('vue')['nextTick'] const nextTick: typeof import('vue')['nextTick']
const onActivated: typeof import('vue')['onActivated'] const onActivated: typeof import('vue')['onActivated']
@ -33,9 +42,12 @@ declare global {
const reactive: typeof import('vue')['reactive'] const reactive: typeof import('vue')['reactive']
const readonly: typeof import('vue')['readonly'] const readonly: typeof import('vue')['readonly']
const ref: typeof import('vue')['ref'] const ref: typeof import('vue')['ref']
const setActivePinia: typeof import('pinia')['setActivePinia']
const setMapStoreSuffix: typeof import('pinia')['setMapStoreSuffix']
const shallowReactive: typeof import('vue')['shallowReactive'] const shallowReactive: typeof import('vue')['shallowReactive']
const shallowReadonly: typeof import('vue')['shallowReadonly'] const shallowReadonly: typeof import('vue')['shallowReadonly']
const shallowRef: typeof import('vue')['shallowRef'] const shallowRef: typeof import('vue')['shallowRef']
const storeToRefs: typeof import('pinia')['storeToRefs']
const toRaw: typeof import('vue')['toRaw'] const toRaw: typeof import('vue')['toRaw']
const toRef: typeof import('vue')['toRef'] const toRef: typeof import('vue')['toRef']
const toRefs: typeof import('vue')['toRefs'] const toRefs: typeof import('vue')['toRefs']
@ -46,7 +58,6 @@ declare global {
const useRoute: typeof import('vue-router')['useRoute'] const useRoute: typeof import('vue-router')['useRoute']
const useRouter: typeof import('vue-router')['useRouter'] const useRouter: typeof import('vue-router')['useRouter']
const useSlots: typeof import('vue')['useSlots'] const useSlots: typeof import('vue')['useSlots']
const useStore: typeof import('vuex')['useStore']
const watch: typeof import('vue')['watch'] const watch: typeof import('vue')['watch']
const watchEffect: typeof import('vue')['watchEffect'] const watchEffect: typeof import('vue')['watchEffect']
} }

View File

@ -21,6 +21,7 @@
import Fuse from 'fuse.js' import Fuse from 'fuse.js'
import { getNormalPath } from '@/utils/ruoyi' import { getNormalPath } from '@/utils/ruoyi'
import { isHttp } from '@/utils/validate' import { isHttp } from '@/utils/validate'
import usePermissionStore from '@/store/modules/permission'
const search = ref(''); const search = ref('');
const options = ref([]); const options = ref([]);
@ -28,9 +29,8 @@ const searchPool = ref([]);
const show = ref(false); const show = ref(false);
const fuse = ref(undefined); const fuse = ref(undefined);
const headerSearchSelectRef = ref(null); const headerSearchSelectRef = ref(null);
const store = useStore();
const router = useRouter(); const router = useRouter();
const routes = computed(() => store.getters.permission_routes); const routes = computed(() => usePermissionStore().routes);
function click() { function click() {
show.value = !show.value show.value = !show.value

View File

@ -14,8 +14,9 @@
</template> </template>
<script setup> <script setup>
const store = useStore() import useAppStore from '@/store/modules/app'
const lang = computed(() => store.getters.language) const appStore = useAppStore()
const lang = computed(() => useAppStore().lang)
const { proxy } = getCurrentInstance() const { proxy } = getCurrentInstance()
const langOptions = ref([ const langOptions = ref([
@ -26,7 +27,7 @@ const langOptions = ref([
function handleLanguageChange(lang) { function handleLanguageChange(lang) {
proxy.$modal.loading('正在设置语言,请稍候...') proxy.$modal.loading('正在设置语言,请稍候...')
store.dispatch('app/setLang', lang) appStore.setLang(lang)
setTimeout('window.location.reload()', 1000) setTimeout('window.location.reload()', 1000)
} }
</script> </script>

View File

@ -33,15 +33,18 @@
</template> </template>
<script setup name="noticeIndex"> <script setup name="noticeIndex">
import useSocketStore from '@/store/modules/socket'
const { proxy } = getCurrentInstance() const { proxy } = getCurrentInstance()
// //
const newsDot = ref(false) const newsDot = ref(false)
const noticeList = computed(() => { const noticeList = computed(() => {
return proxy.$store.getters.noticeList return useSocketStore().noticeList
}) })
const noticeDot = computed(() => { const noticeDot = computed(() => {
return proxy.$store.getters.noticeDot return useSocketStore().noticeDot
}) })
// //
function onAllReadClick() { function onAllReadClick() {

View File

@ -14,8 +14,9 @@
</template> </template>
<script setup> <script setup>
const store = useStore() import useAppStore from '@/store/modules/app'
const size = computed(() => store.getters.size) const appStore = useAppStore()
const size = computed(() => appStore.size)
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
const { proxy } = getCurrentInstance() const { proxy } = getCurrentInstance()
@ -25,21 +26,21 @@ const sizeOptions = ref([
{ label: proxy.$t('layout.small'), value: 'small' }, { label: proxy.$t('layout.small'), value: 'small' },
]) ])
function refreshView() { // function refreshView() {
// In order to make the cached page re-rendered // // In order to make the cached page re-rendered
store.dispatch('tagsView/delAllCachedViews', route) // store.dispatch('tagsView/delAllCachedViews', route)
const { fullPath } = route // const { fullPath } = route
nextTick(() => { // nextTick(() => {
router.replace({ // router.replace({
path: '/redirect' + fullPath, // path: '/redirect' + fullPath,
}) // })
}) // })
} // }
function handleSetSize(size) { function handleSetSize(size) {
proxy.$modal.loading('正在设置布局大小,请稍候...') proxy.$modal.loading('正在设置布局大小,请稍候...')
store.dispatch('app/setSize', size) appStore.setSize(size)
setTimeout('window.location.reload()', 1000) setTimeout('window.location.reload()', 1000)
} }
</script> </script>

View File

@ -37,6 +37,9 @@ import { constantRoutes } from '@/router'
import { isHttp } from '@/utils/validate' import { isHttp } from '@/utils/validate'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { getNormalPath } from '@/utils/ruoyi' import { getNormalPath } from '@/utils/ruoyi'
import useAppStore from '@/store/modules/app'
import useSettingsStore from '@/store/modules/settings'
import usePermissionStore from '@/store/modules/permission'
// //
const visibleNumber = ref(5) const visibleNumber = ref(5)
@ -45,14 +48,16 @@ const isFrist = ref(false)
// index // index
const currentIndex = ref(undefined) const currentIndex = ref(undefined)
const store = useStore() const appStore = useAppStore()
const settingsStore = useSettingsStore()
const permissionStore = usePermissionStore()
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
// //
const theme = computed(() => store.state.settings.theme) const theme = computed(() => settingsStore.theme)
// //
const routers = computed(() => store.state.permission.topbarRouters) const routers = computed(() => permissionStore.topbarRouters)
// //
const topMenus = computed(() => { const topMenus = computed(() => {
@ -153,7 +158,7 @@ function activeRoutes(key) {
}) })
} }
if (routes.length > 0) { if (routes.length > 0) {
store.commit('SET_SIDEBAR_ROUTERS', routes) permissionStore.setSidebarRouters(routes)
} }
return routes return routes
} }

View File

@ -1,28 +1,28 @@
/** /**
* v-hasPermi 操作权限处理 * v-hasPermi 操作权限处理
* Copyright (c) 2019 ruoyi * Copyright (c) 2019 ruoyi
*/ */
import store from '@/store' import useUserStore from '@/store/modules/user'
export default { export default {
mounted(el, binding, vnode) { mounted(el, binding, vnode) {
const { value } = binding const { value } = binding
const all_permission = "*:*:*"; const all_permission = "*:*:*";
const permissions = store.getters && store.getters.permissions const permissions = useUserStore().permissions
if (value && value instanceof Array && value.length > 0) { if (value && value instanceof Array && value.length > 0) {
const permissionFlag = value const permissionFlag = value
const hasPermissions = permissions.some(permission => { const hasPermissions = permissions.some(permission => {
return all_permission === permission || permissionFlag.includes(permission) return all_permission === permission || permissionFlag.includes(permission)
}) })
if (!hasPermissions) { if (!hasPermissions) {
el.parentNode && el.parentNode.removeChild(el) el.parentNode && el.parentNode.removeChild(el)
} }
} else { } else {
throw new Error(`请设置操作权限标签值`) throw new Error(`请设置操作权限标签值`)
} }
} }
} }

View File

@ -3,13 +3,13 @@
* Copyright (c) 2019 ruoyi * Copyright (c) 2019 ruoyi
*/ */
import store from '@/store' import useUserStore from '@/store/modules/user'
export default { export default {
mounted(el, binding, vnode) { mounted(el, binding, vnode) {
const { value } = binding const { value } = binding
const super_admin = "admin"; const super_admin = "admin";
const roles = store.getters && store.getters.roles const roles = useUserStore().roles
if (value && value instanceof Array && value.length > 0) { if (value && value instanceof Array && value.length > 0) {
const roleFlag = value const roleFlag = value

View File

@ -1,9 +1,10 @@
import { createI18n } from 'vue-i18n' import { createI18n } from 'vue-i18n'
import store from '@/store/index' // import useAppStore from '@/store/modules/app'
import { listLangByLocale } from '@/api/system/commonLang' import { listLangByLocale } from '@/api/system/commonLang'
import jsCookie from 'js-cookie'
const language = computed(() => { const language = computed(() => {
return store.getters.language // return useAppStore().lang
return jsCookie.get('lang') || 'zh-cn'
}) })
import zhCn from './lang/zh-cn.json' import zhCn from './lang/zh-cn.json'
@ -23,7 +24,7 @@ const i18n = createI18n({
// 全局注入 $t 函数 // 全局注入 $t 函数
globalInjection: true, globalInjection: true,
fallbackLocale: 'zh-cn', fallbackLocale: 'zh-cn',
locale: store.getters.language, //默认选择的语言 locale: language.value, //默认选择的语言
legacy: false, // 使用 Composition API 模式则需要将其设置为false legacy: false, // 使用 Composition API 模式则需要将其设置为false
messages: { messages: {
'zh-cn': { 'zh-cn': {

View File

@ -10,9 +10,11 @@
</el-main> </el-main>
</template> </template>
<script setup> <script setup>
const route = useRoute() import useTagsViewStore from '@/store/modules/tagsView'
const store = useStore() // const route = useRoute()
const tagsViewStore = useTagsViewStore()
// tagsViewStore.addCachedView(route)
const cachedViews = computed(() => { const cachedViews = computed(() => {
return store.state.tagsView.cachedViews return tagsViewStore.cachedViews
}) })
</script> </script>

View File

@ -1,13 +1,13 @@
<template> <template>
<div class="navbar" :data-theme="sideTheme" :class="getters.device"> <div class="navbar" :data-theme="sideTheme" :class="appStore.device">
<hamburger id="hamburger-container" :is-active="getters.sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" /> <hamburger id="hamburger-container" :is-active="appStore.sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
<template v-if="getters.device != 'mobile'"> <template v-if="appStore.device != 'mobile'">
<breadcrumb id="breadcrumb-container" class="breadcrumb-container" v-if="!$store.state.settings.topNav" /> <breadcrumb id="breadcrumb-container" class="breadcrumb-container" v-if="!settingsStore.topNav" />
<top-nav id="topmenu-container" class="topmenu-container" v-if="$store.state.settings.topNav" /> <top-nav id="topmenu-container" class="topmenu-container" v-if="settingsStore.topNav" />
</template> </template>
<div class="right-menu"> <div class="right-menu">
<header-search id="header-search" class="right-menu-item" v-if="getters.device != 'mobile'" /> <header-search id="header-search" class="right-menu-item" v-if="appStore.device != 'mobile'" />
<zr-git title="源码地址" class="right-menu-item" /> <zr-git title="源码地址" class="right-menu-item" />
<zr-doc title="文档地址" class="right-menu-item" /> <zr-doc title="文档地址" class="right-menu-item" />
<screenfull title="全屏" class="right-menu-item" /> <screenfull title="全屏" class="right-menu-item" />
@ -17,8 +17,8 @@
<el-dropdown @command="handleCommand" class="right-menu-item avatar-container" trigger="hover"> <el-dropdown @command="handleCommand" class="right-menu-item avatar-container" trigger="hover">
<span class="avatar-wrapper"> <span class="avatar-wrapper">
<img :src="getters.avatar" class="user-avatar" /> <img :src="userStore.avatar" class="user-avatar" />
<span class="name">{{ getters.name }}</span> <span class="name">{{ userStore.name }}</span>
<el-icon><ArrowDown /></el-icon> <el-icon><ArrowDown /></el-icon>
</span> </span>
<template #dropdown> <template #dropdown>
@ -50,13 +50,18 @@ import ZrGit from '@/components/Zr/Git'
import ZrDoc from '@/components/Zr/Doc' import ZrDoc from '@/components/Zr/Doc'
import Notice from '@/components/Notice/Index' import Notice from '@/components/Notice/Index'
import LangSelect from '@/components/LangSelect/index' import LangSelect from '@/components/LangSelect/index'
import useAppStore from '@/store/modules/app'
import useUserStore from '@/store/modules/user'
import useSettingsStore from '@/store/modules/settings'
const { proxy } = getCurrentInstance() const { proxy } = getCurrentInstance()
const store = useStore() const appStore = useAppStore()
const getters = computed(() => store.getters) const userStore = useUserStore()
const sideTheme = computed(() => store.state.settings.sideTheme) const settingsStore = useSettingsStore()
const sideTheme = computed(() => settingsStore.sideTheme)
function toggleSideBar() { function toggleSideBar() {
store.dispatch('app/toggleSideBar') appStore.toggleSideBar()
} }
function handleCommand(command) { function handleCommand(command) {
@ -80,7 +85,7 @@ function logout() {
type: 'warning', type: 'warning',
}) })
.then(() => { .then(() => {
store.dispatch('LogOut').then(() => { userStore.logOut().then(() => {
location.href = '/index' location.href = '/index'
}) })
}) })

View File

@ -93,13 +93,18 @@ import 'element-plus/theme-chalk/dark/css-vars.css'
import { useDark, useCycleList, useColorMode } from '@vueuse/core' import { useDark, useCycleList, useColorMode } from '@vueuse/core'
import { useDynamicTitle } from '@/utils/dynamicTitle' import { useDynamicTitle } from '@/utils/dynamicTitle'
import { getLightColor } from '@/utils/index' import { getLightColor } from '@/utils/index'
import useAppStore from '@/store/modules/app'
import useSettingsStore from '@/store/modules/settings'
import usePermissionStore from '@/store/modules/permission'
const { proxy } = getCurrentInstance() const { proxy } = getCurrentInstance()
const store = useStore() const appStore = useAppStore()
const settingsStore = useSettingsStore()
const permissionStore = usePermissionStore()
const showSettings = ref(false) const showSettings = ref(false)
const theme = ref(store.state.settings.theme) const theme = ref(settingsStore.theme)
const sideTheme = ref(store.state.settings.sideTheme) const sideTheme = ref(settingsStore.sideTheme)
const storeSettings = computed(() => store.state.settings) const storeSettings = computed(() => settingsStore)
const predefineColors = ref(['#409EFF', '#ff4500', '#ff8c00', '#ffd700', '#90ee90', '#00ced1', '#1e90ff', '#c71585']) const predefineColors = ref(['#409EFF', '#ff4500', '#ff8c00', '#ffd700', '#90ee90', '#00ced1', '#1e90ff', '#c71585'])
// model.value = 'cafe' // model.value = 'cafe'
@ -117,13 +122,10 @@ const isDark = useDark()
const topNav = computed({ const topNav = computed({
get: () => storeSettings.value.topNav, get: () => storeSettings.value.topNav,
set: (val) => { set: (val) => {
store.dispatch('settings/changeSetting', { settingsStore.changeSetting({ key: 'topNav', value: val })
key: 'topNav',
value: val,
})
if (!val) { if (!val) {
store.dispatch('app/toggleSideBarHide', false) appStore.toggleSideBarHide(false)
store.commit('SET_SIDEBAR_ROUTERS', store.state.permission.defaultRoutes) permissionStore.setSidebarRouters(permissionStore.defaultRoutes)
} }
}, },
}) })
@ -131,50 +133,35 @@ const topNav = computed({
const tagsView = computed({ const tagsView = computed({
get: () => storeSettings.value.tagsView, get: () => storeSettings.value.tagsView,
set: (val) => { set: (val) => {
store.dispatch('settings/changeSetting', { settingsStore.changeSetting({ key: 'tagsView', value: val })
key: 'tagsView',
value: val,
})
}, },
}) })
/**是否需要固定头部 */ /**是否需要固定头部 */
const fixedHeader = computed({ const fixedHeader = computed({
get: () => storeSettings.value.fixedHeader, get: () => storeSettings.value.fixedHeader,
set: (val) => { set: (val) => {
store.dispatch('settings/changeSetting', { settingsStore.changeSetting({ key: 'fixedHeader', value: val })
key: 'fixedHeader',
value: val,
})
}, },
}) })
// //
const showFooter = computed({ const showFooter = computed({
get: () => storeSettings.value.showFooter, get: () => storeSettings.value.showFooter,
set: (val) => { set: (val) => {
store.dispatch('settings/changeSetting', { settingsStore.changeSetting({ key: 'showFooter', value: val })
key: 'showFooter',
value: val,
})
}, },
}) })
/**是否需要侧边栏的logo */ /**是否需要侧边栏的logo */
const sidebarLogo = computed({ const sidebarLogo = computed({
get: () => storeSettings.value.sidebarLogo, get: () => storeSettings.value.sidebarLogo,
set: (val) => { set: (val) => {
store.dispatch('settings/changeSetting', { settingsStore.changeSetting({ key: 'sidebarLogo', value: val })
key: 'sidebarLogo',
value: val,
})
}, },
}) })
/**是否需要侧边栏的动态网页的title */ /**是否需要侧边栏的动态网页的title */
const dynamicTitle = computed({ const dynamicTitle = computed({
get: () => storeSettings.value.dynamicTitle, get: () => storeSettings.value.dynamicTitle,
set: (val) => { set: (val) => {
store.dispatch('settings/changeSetting', { settingsStore.changeSetting({ key: 'dynamicTitle', value: val })
key: 'dynamicTitle',
value: val,
})
// //
useDynamicTitle() useDynamicTitle()
}, },
@ -216,10 +203,7 @@ watch(
* 改变主题颜色 * 改变主题颜色
*/ */
function themeChange(val) { function themeChange(val) {
store.dispatch('settings/changeSetting', { settingsStore.changeSetting({ key: 'theme', value: val })
key: 'theme',
value: val,
})
theme.value = val theme.value = val
// element-plus ui // element-plus ui
document.documentElement.style.setProperty('--el-color-primary', val) document.documentElement.style.setProperty('--el-color-primary', val)
@ -230,10 +214,7 @@ function themeChange(val) {
} }
} }
function handleTheme(val) { function handleTheme(val) {
store.dispatch('settings/changeSetting', { settingsStore.changeSetting({ key: 'sideTheme', value: val })
key: 'sideTheme',
value: val,
})
sideTheme.value = val sideTheme.value = val
const body = document.documentElement const body = document.documentElement
if (val == 'theme-black') body.setAttribute('data-theme', 'theme-black') if (val == 'theme-black') body.setAttribute('data-theme', 'theme-black')

View File

@ -15,6 +15,7 @@
<script setup> <script setup>
import logo from '@/assets/logo/logo.png' import logo from '@/assets/logo/logo.png'
import useSettingsStore from '@/store/modules/settings'
defineProps({ defineProps({
collapse: { collapse: {
@ -24,8 +25,8 @@ defineProps({
}) })
const title = ref(import.meta.env.VITE_APP_TITLE) const title = ref(import.meta.env.VITE_APP_TITLE)
const store = useStore() const settingsStore = useSettingsStore();
const sideTheme = computed(() => store.state.settings.sideTheme) const sideTheme = computed(() => settingsStore.sideTheme);
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -20,15 +20,20 @@
<script setup> <script setup>
import Logo from './Logo' import Logo from './Logo'
import SidebarItem from './SidebarItem' import SidebarItem from './SidebarItem'
import useAppStore from '@/store/modules/app'
import useSettingsStore from '@/store/modules/settings'
import usePermissionStore from '@/store/modules/permission'
const route = useRoute() const route = useRoute()
const store = useStore() const appStore = useAppStore()
const settingsStore = useSettingsStore()
const permissionStore = usePermissionStore()
const sidebarRouters = computed(() => store.getters.sidebarRouters) const sidebarRouters = computed(() => permissionStore.sidebarRouters)
const showLogo = computed(() => store.state.settings.sidebarLogo) const showLogo = computed(() => settingsStore.sidebarLogo)
const sideTheme = computed(() => store.state.settings.sideTheme) const sideTheme = computed(() => settingsStore.sideTheme)
const theme = computed(() => store.state.settings.theme) const theme = computed(() => settingsStore.theme)
const isCollapse = computed(() => !store.state.app.sidebar.opened) const isCollapse = computed(() => !appStore.sidebar.opened)
const activeMenu = computed(() => { const activeMenu = computed(() => {
const { meta, path } = route const { meta, path } = route

View File

@ -1,19 +1,16 @@
<template> <template>
<el-scrollbar <el-scrollbar ref="scrollContainer" :vertical="false" class="scroll-container" @wheel.prevent="handleScroll">
ref="scrollContainer"
:vertical="false"
class="scroll-container"
@wheel.prevent="handleScroll"
>
<slot /> <slot />
</el-scrollbar> </el-scrollbar>
</template> </template>
<script setup> <script setup>
const tagAndTagSpacing = ref(4); import useTagsViewStore from '@/store/modules/tagsView'
const { proxy } = getCurrentInstance();
const scrollWrapper = computed(() => proxy.$refs.scrollContainer.$refs.wrap$); const tagAndTagSpacing = ref(4)
const { proxy } = getCurrentInstance()
const scrollWrapper = computed(() => proxy.$refs.scrollContainer.$refs.wrap$)
onMounted(() => { onMounted(() => {
scrollWrapper.value.addEventListener('scroll', emitScroll, true) scrollWrapper.value.addEventListener('scroll', emitScroll, true)
@ -24,7 +21,7 @@ onBeforeUnmount(() => {
function handleScroll(e) { function handleScroll(e) {
const eventDelta = e.wheelDelta || -e.deltaY * 40 const eventDelta = e.wheelDelta || -e.deltaY * 40
const $scrollWrapper = scrollWrapper.value; const $scrollWrapper = scrollWrapper.value
$scrollWrapper.scrollLeft = $scrollWrapper.scrollLeft + eventDelta / 4 $scrollWrapper.scrollLeft = $scrollWrapper.scrollLeft + eventDelta / 4
} }
const emits = defineEmits() const emits = defineEmits()
@ -32,13 +29,13 @@ const emitScroll = () => {
emits('scroll') emits('scroll')
} }
const store = useStore(); const tagsViewStore = useTagsViewStore()
const visitedViews = computed(() => store.state.tagsView.visitedViews); const visitedViews = computed(() => tagsViewStore.visitedViews)
function moveToTarget(currentTag) { function moveToTarget(currentTag) {
const $container = proxy.$refs.scrollContainer.$el const $container = proxy.$refs.scrollContainer.$el
const $containerWidth = $container.offsetWidth const $containerWidth = $container.offsetWidth
const $scrollWrapper = scrollWrapper.value; const $scrollWrapper = scrollWrapper.value
let firstTag = null let firstTag = null
let lastTag = null let lastTag = null
@ -54,17 +51,17 @@ function moveToTarget(currentTag) {
} else if (lastTag === currentTag) { } else if (lastTag === currentTag) {
$scrollWrapper.scrollLeft = $scrollWrapper.scrollWidth - $containerWidth $scrollWrapper.scrollLeft = $scrollWrapper.scrollWidth - $containerWidth
} else { } else {
const tagListDom = document.getElementsByClassName('tags-view-item'); const tagListDom = document.getElementsByClassName('tags-view-item')
const currentIndex = visitedViews.value.findIndex(item => item === currentTag) const currentIndex = visitedViews.value.findIndex((item) => item === currentTag)
let prevTag = null let prevTag = null
let nextTag = null let nextTag = null
for (const k in tagListDom) { for (const k in tagListDom) {
if (k !== 'length' && Object.hasOwnProperty.call(tagListDom, k)) { if (k !== 'length' && Object.hasOwnProperty.call(tagListDom, k)) {
if (tagListDom[k].dataset.path === visitedViews.value[currentIndex - 1].path) { if (tagListDom[k].dataset.path === visitedViews.value[currentIndex - 1].path) {
prevTag = tagListDom[k]; prevTag = tagListDom[k]
} }
if (tagListDom[k].dataset.path === visitedViews.value[currentIndex + 1].path) { if (tagListDom[k].dataset.path === visitedViews.value[currentIndex + 1].path) {
nextTag = tagListDom[k]; nextTag = tagListDom[k]
} }
} }
} }
@ -87,7 +84,7 @@ defineExpose({
}) })
</script> </script>
<style lang='scss' scoped> <style lang="scss" scoped>
.scroll-container { .scroll-container {
white-space: nowrap; white-space: nowrap;
position: relative; position: relative;

View File

@ -37,6 +37,9 @@
<script setup> <script setup>
import ScrollPane from './ScrollPane' import ScrollPane from './ScrollPane'
import { getNormalPath } from '@/utils/ruoyi' import { getNormalPath } from '@/utils/ruoyi'
import useTagsViewStore from '@/store/modules/tagsView'
// import useSettingsStore from '@/store/modules/settings'
import usePermissionStore from '@/store/modules/permission'
const visible = ref(false) const visible = ref(false)
const top = ref(0) const top = ref(0)
@ -46,13 +49,12 @@ const affixTags = ref([])
const scrollPaneRef = ref(null) const scrollPaneRef = ref(null)
const { proxy } = getCurrentInstance() const { proxy } = getCurrentInstance()
const store = useStore()
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
const visitedViews = computed(() => store.state.tagsView.visitedViews) const visitedViews = computed(() => useTagsViewStore().visitedViews)
const routes = computed(() => store.state.permission.routes) const routes = computed(() => usePermissionStore().routes)
// const theme = computed(() => store.state.settings.theme) // const theme = computed(() => useSettingsStore().theme);
watch(route, () => { watch(route, () => {
addTags() addTags()
@ -124,14 +126,14 @@ function initTags() {
for (const tag of res) { for (const tag of res) {
// Must have tag name // Must have tag name
if (tag.name) { if (tag.name) {
store.dispatch('tagsView/addVisitedView', tag) useTagsViewStore().addVisitedView(tag)
} }
} }
} }
function addTags() { function addTags() {
const { name } = route const { name } = route
if (name) { if (name) {
store.dispatch('tagsView/addView', route) useTagsViewStore().addView(route)
} }
return false return false
} }
@ -142,7 +144,7 @@ function moveToCurrentTag() {
scrollPaneRef.value.moveToTarget(r) scrollPaneRef.value.moveToTarget(r)
// when query is different then update // when query is different then update
if (r.fullPath !== route.fullPath) { if (r.fullPath !== route.fullPath) {
store.dispatch('tagsView/updateVisitedView', route) useTagsViewStore().updateVisitedView(route)
} }
} }
} }

View File

@ -33,25 +33,29 @@ import { useWindowSize } from '@vueuse/core'
import Sidebar from './components/Sidebar/index.vue' import Sidebar from './components/Sidebar/index.vue'
import { Navbar, Settings, TagsView } from './components' import { Navbar, Settings, TagsView } from './components'
import defaultSettings from '@/settings' import defaultSettings from '@/settings'
import useAppStore from '@/store/modules/app'
import useSettingsStore from '@/store/modules/settings'
import useTagsViewStore from '@/store/modules/tagsView'
const menuDrawer = computed({ const menuDrawer = computed({
get: () => store.state.app.sidebar.opened, get: () => useAppStore().sidebar.opened,
set: (val) => { set: (val) => {
store.dispatch('app/toggleSideBar') useAppStore().toggleSideBar(val)
}, },
}) })
let store = useStore() const settingsStore = useSettingsStore()
const theme = computed(() => store.state.settings.theme) const theme = computed(() => settingsStore.theme)
const sidebar = computed(() => store.state.app.sidebar) const sidebar = computed(() => useAppStore().sidebar)
const device = computed(() => store.state.app.device) const device = computed(() => useAppStore().device)
const needTagsView = computed(() => store.state.settings.tagsView) const needTagsView = computed(() => settingsStore.tagsView)
const fixedHeader = computed(() => store.state.settings.fixedHeader) const fixedHeader = computed(() => settingsStore.fixedHeader)
const showFooter = computed(() => store.state.settings.showFooter) const showFooter = computed(() => settingsStore.showFooter)
// appMain start // appMain start
const route = useRoute() const route = useRoute()
store.dispatch('tagsView/addCachedView', route) useTagsViewStore().addCachedView(route)
const cachedViews = computed(() => { const cachedViews = computed(() => {
return store.state.tagsView.cachedViews return useTagsViewStore().cachedViews
}) })
//appMain //appMain
@ -66,18 +70,18 @@ const WIDTH = 992 // refer to Bootstrap's responsive design
watchEffect(() => { watchEffect(() => {
if (device.value === 'mobile' && sidebar.value.opened) { if (device.value === 'mobile' && sidebar.value.opened) {
// store.dispatch('app/closeSideBar') // useAppStore().closeSideBar()
} }
if (width.value - 1 < WIDTH) { if (width.value - 1 < WIDTH) {
store.dispatch('app/toggleDevice', 'mobile') useAppStore().toggleDevice('mobile')
// store.dispatch('app/closeSideBar') // useAppStore().closeSideBar()
} else { } else {
store.dispatch('app/toggleDevice', 'desktop') useAppStore().toggleDevice('desktop')
} }
}) })
function handleClickOutside() { function handleClickOutside() {
store.dispatch('app/closeSideBar') useAppStore().closeSideBar()
} }
const settingRef = ref(null) const settingRef = ref(null)

View File

@ -6,7 +6,6 @@ import 'dayjs/locale/zh-cn'
import '@/assets/styles/index.scss' // global css import '@/assets/styles/index.scss' // global css
import App from './App' import App from './App'
import store from './store'
import router from './router' import router from './router'
import directive from './directive' // directive import directive from './directive' // directive
// 注册指令 // 注册指令
@ -65,6 +64,7 @@ app.component('ImagePreview', ImagePreview)
app.component('RightToolbar', RightToolbar) app.component('RightToolbar', RightToolbar)
app.component('svg-icon', SvgIcon) app.component('svg-icon', SvgIcon)
const store = createPinia()
app.use(router) app.use(router)
app.use(store) app.use(store)
app.use(plugins) app.use(plugins)

View File

@ -1,11 +1,12 @@
import router from './router' import router from './router'
import store from './store'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import NProgress from 'nprogress' import NProgress from 'nprogress'
import 'nprogress/nprogress.css' import 'nprogress/nprogress.css'
import { getToken } from '@/utils/auth' import { getToken } from '@/utils/auth'
import { isHttp } from '@/utils/validate' import { isHttp } from '@/utils/validate'
import useUserStore from '@/store/modules/user'
import useSettingsStore from '@/store/modules/settings'
import usePermissionStore from '@/store/modules/permission'
NProgress.configure({ showSpinner: false }); NProgress.configure({ showSpinner: false });
const whiteList = ['/login', '/auth-redirect', '/bind', '/register']; const whiteList = ['/login', '/auth-redirect', '/bind', '/register'];
@ -13,16 +14,16 @@ const whiteList = ['/login', '/auth-redirect', '/bind', '/register'];
router.beforeEach((to, from, next) => { router.beforeEach((to, from, next) => {
NProgress.start() NProgress.start()
if (getToken()) { if (getToken()) {
to.meta.title && store.dispatch('settings/setTitle', to.meta.title) to.meta.title && useSettingsStore().setTitle(to.meta.title)
/* has token*/ /* has token*/
if (to.path === '/login') { if (to.path === '/login') {
next({ path: '/' }) next({ path: '/' })
NProgress.done() NProgress.done()
} else { } else {
if (store.getters.roles.length === 0) { if (useUserStore().roles.length === 0) {
// 判断当前用户是否已拉取完user_info信息 // 判断当前用户是否已拉取完user_info信息
store.dispatch('GetInfo').then(() => { useUserStore().getInfo().then(() => {
store.dispatch('GenerateRoutes').then(accessRoutes => { usePermissionStore().generateRoutes().then(accessRoutes => {
// 根据roles权限生成可访问的路由表 // 根据roles权限生成可访问的路由表
accessRoutes.forEach(route => { accessRoutes.forEach(route => {
if (!isHttp(route.path)) { if (!isHttp(route.path)) {
@ -32,7 +33,7 @@ router.beforeEach((to, from, next) => {
next({ ...to, replace: true }) // hack方法 确保addRoutes已完成 next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
}) })
}).catch(err => { }).catch(err => {
store.dispatch('LogOut').then(() => { useUserStore().logOut().then(() => {
ElMessage.error(err != undefined ? err : '登录失败') ElMessage.error(err != undefined ? err : '登录失败')
next({ path: '/' }) next({ path: '/' })
}) })

View File

@ -1,8 +1,8 @@
import store from '@/store' import useUserStore from '@/store/modules/user'
function authPermission(permission) { function authPermission(permission) {
const all_permission = "*:*:*"; const all_permission = "*:*:*";
const permissions = store.getters && store.getters.permissions const permissions = useUserStore() && useUserStore().permissions
if (permission && permission.length > 0) { if (permission && permission.length > 0) {
return permissions.some(v => { return permissions.some(v => {
return all_permission === v || v === permission return all_permission === v || v === permission
@ -14,7 +14,7 @@ function authPermission(permission) {
function authRole(role) { function authRole(role) {
const super_admin = "admin"; const super_admin = "admin";
const roles = store.getters && store.getters.roles const roles = useUserStore().roles
if (role && role.length > 0) { if (role && role.length > 0) {
return roles.some(v => { return roles.some(v => {
return super_admin === v || v === role return super_admin === v || v === role

View File

@ -1,4 +1,4 @@
import store from '@/store' import useTagsViewStore from '@/store/modules/tagsView'
import router from '@/router' import router from '@/router'
export default { export default {
@ -14,7 +14,7 @@ export default {
} }
}); });
} }
return store.dispatch('tagsView/delCachedView', obj).then(() => { return useTagsViewStore().delCachedView(obj).then(() => {
const { path, query } = obj const { path, query } = obj
router.replace({ router.replace({
path: '/redirect' + path, path: '/redirect' + path,
@ -24,7 +24,7 @@ export default {
}, },
// 关闭当前tab页签打开新页签 // 关闭当前tab页签打开新页签
closeOpenPage(obj) { closeOpenPage(obj) {
store.dispatch("tagsView/delView", router.currentRoute.value); useTagsViewStore().delView(router.currentRoute.value);
if (obj !== undefined) { if (obj !== undefined) {
return router.push(obj); return router.push(obj);
} }
@ -32,27 +32,27 @@ export default {
// 关闭指定tab页签 // 关闭指定tab页签
closePage(obj) { closePage(obj) {
if (obj === undefined) { if (obj === undefined) {
return store.dispatch('tagsView/delView', router.currentRoute.value).then(({ lastPath }) => { return useTagsViewStore().delView(router.currentRoute.value).then(({ lastPath }) => {
return router.push(lastPath || '/index'); return router.push(lastPath || '/index');
}); });
} }
return store.dispatch('tagsView/delView', obj); return useTagsViewStore().delView(obj);
}, },
// 关闭所有tab页签 // 关闭所有tab页签
closeAllPage() { closeAllPage() {
return store.dispatch('tagsView/delAllViews'); return useTagsViewStore().delAllViews();
}, },
// 关闭左侧tab页签 // 关闭左侧tab页签
closeLeftPage(obj) { closeLeftPage(obj) {
return store.dispatch('tagsView/delLeftTags', obj || router.currentRoute.value); return useTagsViewStore().delLeftTags(obj || router.currentRoute.value);
}, },
// 关闭右侧tab页签 // 关闭右侧tab页签
closeRightPage(obj) { closeRightPage(obj) {
return store.dispatch('tagsView/delRightTags', obj || router.currentRoute.value); return useTagsViewStore().delRightTags(obj || router.currentRoute.value);
}, },
// 关闭其他tab页签 // 关闭其他tab页签
closeOtherPage(obj) { closeOtherPage(obj) {
return store.dispatch('tagsView/delOthersViews', obj || router.currentRoute.value); return useTagsViewStore().delOthersViews(obj || router.currentRoute.value);
}, },
// 打开tab页签 // 打开tab页签
openPage(url) { openPage(url) {
@ -60,6 +60,6 @@ export default {
}, },
// 修改tab页签 // 修改tab页签
updatePage(obj) { updatePage(obj) {
return store.dispatch('tagsView/updateVisitedView', obj); return useTagsViewStore().updateVisitedView(obj);
} }
} }

View File

@ -1,25 +0,0 @@
const getters = {
sidebar: state => state.app.sidebar,
size: state => state.app.size,
device: state => state.app.device,
language: state => state.app.lang,
visitedViews: state => state.tagsView.visitedViews,
cachedViews: state => state.tagsView.cachedViews,
token: state => state.user.token,
avatar: state => state.user.avatar,
name: state => state.user.name,
userId: state => state.user.userInfo.userId,
introduction: state => state.user.introduction,
roles: state => state.user.roles,
permissions: state => state.user.permissions,
permission_routes: state => state.permission.routes,
userinfo: state => state.user.userInfo,
topbarRouters: state => state.permission.topbarRouters,
defaultRoutes: state => state.permission.defaultRoutes,
sidebarRouters: state => state.permission.sidebarRouters,
onlineUserNum: state => state.socket.onlineNum,
noticeList: state => state.socket.noticeList,
noticeDot: state => state.socket.noticeList.length > 0,
onlineUsers: state => state.socket.onlineUsers
}
export default getters

View File

@ -1,23 +1,3 @@
import { createStore } from 'vuex' const store = createPinia()
import app from './modules/app'
import user from './modules/user'
import tagsView from './modules/tagsView'
import permission from './modules/permission'
import settings from './modules/settings'
import getters from './getters'
import socket from './modules/socket'
const store = createStore({
modules: {
app,
user,
tagsView,
permission,
settings,
socket
},
getters
});
export default store export default store

View File

@ -1,75 +1,122 @@
import Cookies from 'js-cookie' import Cookies from 'js-cookie'
const state = { // const state = {
sidebar: { // sidebar: {
opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true, // opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true,
withoutAnimation: false, // withoutAnimation: false,
hide: false // hide: false
}, // },
device: 'desktop', // device: 'desktop',
size: Cookies.get('size') || 'small', // size: Cookies.get('size') || 'small',
lang: Cookies.get('lang') || 'zh-cn' // lang: Cookies.get('lang') || 'zh-cn'
} // }
const mutations = { // const mutations = {
TOGGLE_SIDEBAR: state => { // TOGGLE_SIDEBAR: state => {
if (state.sidebar.hide) { // if (state.sidebar.hide) {
return false; // return false;
} // }
state.sidebar.opened = !state.sidebar.opened // state.sidebar.opened = !state.sidebar.opened
state.sidebar.withoutAnimation = true // state.sidebar.withoutAnimation = true
if (state.sidebar.opened) { // if (state.sidebar.opened) {
Cookies.set('sidebarStatus', 1) // Cookies.set('sidebarStatus', 1)
} else { // } else {
// Cookies.set('sidebarStatus', 0)
// }
// },
// CLOSE_SIDEBAR: (state, withoutAnimation) => {
// Cookies.set('sidebarStatus', 0)
// state.sidebar.opened = false
// state.sidebar.withoutAnimation = withoutAnimation
// },
// TOGGLE_DEVICE: (state, device) => {
// state.device = device
// },
// SET_SIZE: (state, size) => {
// state.size = size
// Cookies.set('size', size)
// },
// SET_SIDEBAR_HIDE: (state, status) => {
// state.sidebar.hide = status
// },
// SET_LANG: (state, lang) => {
// state.lang = lang
// Cookies.set('lang', lang)
// },
// }
// const actions = {
// toggleSideBar({ commit }) {
// commit('TOGGLE_SIDEBAR')
// },
// closeSideBar({ commit }) {
// commit('CLOSE_SIDEBAR', '')
// },
// toggleDevice({ commit }, device) {
// commit('TOGGLE_DEVICE', device)
// },
// setSize({ commit }, size) {
// commit('SET_SIZE', size)
// },
// toggleSideBarHide({ commit }, status) {
// commit('SET_SIDEBAR_HIDE', status)
// },
// setLang({ commit }, lang) {
// commit('SET_LANG', lang)
// },
// }
// export default {
// namespaced: true,
// state,
// mutations,
// actions
// }
const useAppStore = defineStore('app', {
state: () => ({
sidebar: {
opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true,
withoutAnimation: false,
hide: false
},
device: 'desktop',
size: Cookies.get('size') || 'small',
lang: Cookies.get('lang') || 'zh-cn'
}),
actions: {
toggleSideBar(withoutAnimation) {
if (this.sidebar.hide) {
return false
}
this.sidebar.opened = !this.sidebar.opened
this.sidebar.withoutAnimation = withoutAnimation
if (this.sidebar.opened) {
Cookies.set('sidebarStatus', 1)
} else {
Cookies.set('sidebarStatus', 0)
}
},
closeSideBar(withoutAnimation) {
Cookies.set('sidebarStatus', 0) Cookies.set('sidebarStatus', 0)
this.sidebar.opened = false
this.sidebar.withoutAnimation = withoutAnimation
},
toggleDevice(device) {
this.device = device
},
setSize(size) {
this.size = size;
Cookies.set('size', size)
},
toggleSideBarHide(status) {
this.sidebar.hide = status
},
setLang(lang) {
this.lang = lang
Cookies.set('lang', lang)
} }
}, }
CLOSE_SIDEBAR: (state, withoutAnimation) => { })
Cookies.set('sidebarStatus', 0)
state.sidebar.opened = false
state.sidebar.withoutAnimation = withoutAnimation
},
TOGGLE_DEVICE: (state, device) => {
state.device = device
},
SET_SIZE: (state, size) => {
state.size = size
Cookies.set('size', size)
},
SET_SIDEBAR_HIDE: (state, status) => {
state.sidebar.hide = status
},
SET_LANG: (state, lang) => {
state.lang = lang
Cookies.set('lang', lang)
},
}
const actions = { export default useAppStore
toggleSideBar({ commit }) {
commit('TOGGLE_SIDEBAR')
},
closeSideBar({ commit }) {
commit('CLOSE_SIDEBAR', '')
},
toggleDevice({ commit }, device) {
commit('TOGGLE_DEVICE', device)
},
setSize({ commit }, size) {
commit('SET_SIZE', size)
},
toggleSideBarHide({ commit }, status) {
commit('SET_SIDEBAR_HIDE', status)
},
setLang({ commit }, lang) {
commit('SET_LANG', lang)
},
}
export default {
namespaced: true,
state,
mutations,
actions
}

View File

@ -8,30 +8,29 @@ import InnerLink from '@/layout/components/InnerLink'
const modules = const modules =
import.meta.glob('./../../views/**/*.vue') import.meta.glob('./../../views/**/*.vue')
const permission = { const usePermissionStore = defineStore('permission', {
state: { state: () => ({
routes: [], routes: [],
defaultRoutes: [], defaultRoutes: [],
topbarRouters: [], topbarRouters: [],
sidebarRouters: [] sidebarRouters: []
}, }),
mutations: {
SET_ROUTES: (state, routes) => {
state.routes = constantRoutes.concat(routes)
},
SET_DEFAULT_ROUTES: (state, routes) => {
state.defaultRoutes = constantRoutes.concat(routes)
},
SET_TOPBAR_ROUTES: (state, routes) => {
state.topbarRouters = routes
},
SET_SIDEBAR_ROUTERS: (state, routes) => {
state.sidebarRouters = routes
},
},
actions: { actions: {
setRoutes(routes) {
this.addRoutes = routes
this.routes = constantRoutes.concat(routes)
},
setDefaultRoutes(routes) {
this.defaultRoutes = constantRoutes.concat(routes)
},
setTopbarRoutes(routes) {
this.topbarRouters = routes
},
setSidebarRouters(routes) {
this.sidebarRouters = routes
},
// 生成路由 // 生成路由
GenerateRoutes({ commit }) { generateRoutes() {
return new Promise(resolve => { return new Promise(resolve => {
// 向后端请求路由数据 // 向后端请求路由数据
getRouters().then(res => { getRouters().then(res => {
@ -41,16 +40,16 @@ const permission = {
const sidebarRoutes = filterAsyncRouter(sdata) const sidebarRoutes = filterAsyncRouter(sdata)
const rewriteRoutes = filterAsyncRouter(rdata, false, true) const rewriteRoutes = filterAsyncRouter(rdata, false, true)
//const defaultRoutes = filterAsyncRouter(defaultData) //const defaultRoutes = filterAsyncRouter(defaultData)
commit('SET_ROUTES', rewriteRoutes) this.setRoutes(rewriteRoutes)
commit('SET_SIDEBAR_ROUTERS', constantRoutes.concat(sidebarRoutes)) this.setSidebarRouters(constantRoutes.concat(sidebarRoutes))
commit('SET_DEFAULT_ROUTES', sidebarRoutes) this.setDefaultRoutes(sidebarRoutes)
commit('SET_TOPBAR_ROUTES', sidebarRoutes) this.setTopbarRoutes(sidebarRoutes)
resolve(rewriteRoutes) resolve(rewriteRoutes)
}) })
}) })
} }
} }
} })
// 遍历后台传来的路由字符串,转换为组件对象 // 遍历后台传来的路由字符串,转换为组件对象
function filterAsyncRouter(asyncRouterMap, lastRouter = false, type = false) { function filterAsyncRouter(asyncRouterMap, lastRouter = false, type = false) {
@ -117,4 +116,4 @@ export const loadView = (view) => {
return res; return res;
} }
export default permission export default usePermissionStore

View File

@ -4,41 +4,58 @@ import { useDynamicTitle } from '@/utils/dynamicTitle'
const { sideTheme, theme, showSettings, topNav, tagsView, fixedHeader, sidebarLogo, dynamicTitle, showFooter } = defaultSettings const { sideTheme, theme, showSettings, topNav, tagsView, fixedHeader, sidebarLogo, dynamicTitle, showFooter } = defaultSettings
const storageSetting = JSON.parse(localStorage.getItem('layout-setting')) || '' const storageSetting = JSON.parse(localStorage.getItem('layout-setting')) || ''
const state = { const useSettingsStore = defineStore('settings', {
title: '', state: () => ({
theme: storageSetting.theme || theme, title: '',
sideTheme: storageSetting.sideTheme || sideTheme, theme: storageSetting.theme || theme,
showSettings: showSettings, sideTheme: storageSetting.sideTheme || sideTheme,
topNav: storageSetting.topNav === undefined ? topNav : storageSetting.topNav, showSettings: showSettings,
tagsView: storageSetting.tagsView === undefined ? tagsView : storageSetting.tagsView, topNav: storageSetting.topNav === undefined ? topNav : storageSetting.topNav,
fixedHeader: storageSetting.fixedHeader === undefined ? fixedHeader : storageSetting.fixedHeader, tagsView: storageSetting.tagsView === undefined ? tagsView : storageSetting.tagsView,
sidebarLogo: storageSetting.sidebarLogo === undefined ? sidebarLogo : storageSetting.sidebarLogo, fixedHeader: storageSetting.fixedHeader === undefined ? fixedHeader : storageSetting.fixedHeader,
dynamicTitle: storageSetting.dynamicTitle === undefined ? dynamicTitle : storageSetting.dynamicTitle, sidebarLogo: storageSetting.sidebarLogo === undefined ? sidebarLogo : storageSetting.sidebarLogo,
showFooter: storageSetting.showFooter === undefined ? showFooter : storageSetting.showFooter dynamicTitle: storageSetting.dynamicTitle === undefined ? dynamicTitle : storageSetting.dynamicTitle,
} showFooter: storageSetting.showFooter === undefined ? showFooter : storageSetting.showFooter
const mutations = { }),
CHANGE_SETTING: (state, { key, value }) => { actions: {
if (state.hasOwnProperty(key)) { // 修改布局设置
state[key] = value changeSetting(data) {
const { key, value } = data
if (this.hasOwnProperty(key)) {
this[key] = value
}
},
// 设置网页标题
setTitle(title) {
this.title = title
useDynamicTitle();
} }
} }
} })
export default useSettingsStore
// const mutations = {
// CHANGE_SETTING: (state, { key, value }) => {
// if (state.hasOwnProperty(key)) {
// state[key] = value
// }
// }
// }
const actions = { // const actions = {
// 修改布局设置 // // 修改布局设置
changeSetting({ commit }, data) { // changeSetting({ commit }, data) {
commit('CHANGE_SETTING', data) // commit('CHANGE_SETTING', data)
}, // },
// 设置网页标题 // // 设置网页标题
setTitle({ commit }, title) { // setTitle({ commit }, title) {
state.title = title // state.title = title
useDynamicTitle(); // useDynamicTitle();
} // }
} // }
export default { // export default {
namespaced: true, // namespaced: true,
state, // state,
mutations, // mutations,
actions // actions
} // }

View File

@ -1,37 +1,23 @@
const state = { const useSocketStore = defineStore('socket', {
onlineNum: 0, state: () => ({
onlineUsers: [], onlineNum: 0,
noticeList: [] onlineUsers: [],
} noticeList: [],
const mutations = { noticeDot: false
SET_ONLINEUSER_NUM: (state, num) => { }),
state.onlineNum = num actions: {
}, //更新在线人数
SET_NOTICE_list: (state, data) => { setOnlineUserNum(num) {
state.noticeList = data; this.onlineNum = num
}, },
SET_ONLINE_USERS: (state, data) => { // 更新系统通知
state.onlineUsers = data; setNoticeList(data) {
this.noticeList = data
this.noticeDot = data.length > 0
},
setOnlineUsers(data) {
this.onlineUsers = data
}
} }
} })
export default useSocketStore
const actions = {
//更新在线人数
changeOnlineNum({ commit }, data) {
commit('SET_ONLINEUSER_NUM', data)
},
// 更新系统通知
getNoticeList({ commit }, data) {
commit('SET_NOTICE_list', data)
},
getOnlineUsers({ commit }, data) {
commit('SET_ONLINE_USERS', data)
}
}
export default {
namespaced: true,
state,
mutations,
actions
}

View File

@ -1,207 +1,156 @@
const state = { const useTagsViewStore = defineStore(
visitedViews: [], 'tagsView',
cachedViews: [] {
} state: () => ({
visitedViews: [],
const mutations = { cachedViews: []
ADD_VISITED_VIEW: (state, view) => { }),
if (state.visitedViews.some(v => v.path === view.path)) return actions: {
state.visitedViews.push( addView(view) {
Object.assign({}, view, { this.addVisitedView(view)
title: view.meta.title || 'no-name' this.addCachedView(view)
}) },
) addVisitedView(view) {
}, if (this.visitedViews.some(v => v.path === view.path)) return
ADD_CACHED_VIEW: (state, view) => { this.visitedViews.push(
if (state.cachedViews.includes(view.name)) return Object.assign({}, view, {
if (!view.meta.noCache) { title: view.meta.title || 'no-name'
state.cachedViews.push(view.name) })
} )
}, },
addCachedView(view) {
DEL_VISITED_VIEW: (state, view) => { if (this.cachedViews.includes(view.name)) return
for (const [i, v] of state.visitedViews.entries()) { if (!view.meta.noCache) {
if (v.path === view.path) { this.cachedViews.push(view.name)
state.visitedViews.splice(i, 1) }
break },
delView(view) {
return new Promise(resolve => {
this.delVisitedView(view)
this.delCachedView(view)
resolve({
visitedViews: [...this.visitedViews],
cachedViews: [...this.cachedViews]
})
})
},
delVisitedView(view) {
return new Promise(resolve => {
for (const [i, v] of this.visitedViews.entries()) {
if (v.path === view.path) {
this.visitedViews.splice(i, 1)
break
}
}
resolve([...this.visitedViews])
})
},
delCachedView(view) {
return new Promise(resolve => {
const index = this.cachedViews.indexOf(view.name)
index > -1 && this.cachedViews.splice(index, 1)
resolve([...this.cachedViews])
})
},
delOthersViews(view) {
return new Promise(resolve => {
this.delOthersVisitedViews(view)
this.delOthersCachedViews(view)
resolve({
visitedViews: [...this.visitedViews],
cachedViews: [...this.cachedViews]
})
})
},
delOthersVisitedViews(view) {
return new Promise(resolve => {
this.visitedViews = this.visitedViews.filter(v => {
return v.meta.affix || v.path === view.path
})
resolve([...this.visitedViews])
})
},
delOthersCachedViews(view) {
return new Promise(resolve => {
const index = this.cachedViews.indexOf(view.name)
if (index > -1) {
this.cachedViews = this.cachedViews.slice(index, index + 1)
} else {
this.cachedViews = []
}
resolve([...this.cachedViews])
})
},
delAllViews(view) {
return new Promise(resolve => {
this.delAllVisitedViews(view)
this.delAllCachedViews(view)
resolve({
visitedViews: [...this.visitedViews],
cachedViews: [...this.cachedViews]
})
})
},
delAllVisitedViews(view) {
return new Promise(resolve => {
const affixTags = this.visitedViews.filter(tag => tag.meta.affix)
this.visitedViews = affixTags
resolve([...this.visitedViews])
})
},
delAllCachedViews(view) {
return new Promise(resolve => {
this.cachedViews = []
resolve([...this.cachedViews])
})
},
updateVisitedView(view) {
for (let v of this.visitedViews) {
if (v.path === view.path) {
v = Object.assign(v, view)
break
}
}
},
delRightTags(view) {
return new Promise(resolve => {
const index = this.visitedViews.findIndex(v => v.path === view.path)
if (index === -1) {
return
}
this.visitedViews = this.visitedViews.filter((item, idx) => {
if (idx <= index || (item.meta && item.meta.affix)) {
return true
}
const i = this.cachedViews.indexOf(item.name)
if (i > -1) {
this.cachedViews.splice(i, 1)
}
return false
})
resolve([...this.visitedViews])
})
},
delLeftTags(view) {
return new Promise(resolve => {
const index = this.visitedViews.findIndex(v => v.path === view.path)
if (index === -1) {
return
}
this.visitedViews = this.visitedViews.filter((item, idx) => {
if (idx >= index || (item.meta && item.meta.affix)) {
return true
}
const i = this.cachedViews.indexOf(item.name)
if (i > -1) {
this.cachedViews.splice(i, 1)
}
return false
})
resolve([...this.visitedViews])
})
} }
} }
}, })
DEL_CACHED_VIEW: (state, view) => {
const index = state.cachedViews.indexOf(view.name)
index > -1 && state.cachedViews.splice(index, 1)
},
DEL_OTHERS_VISITED_VIEWS: (state, view) => { export default useTagsViewStore
state.visitedViews = state.visitedViews.filter(v => {
return v.meta.affix || v.path === view.path
})
},
DEL_OTHERS_CACHED_VIEWS: (state, view) => {
const index = state.cachedViews.indexOf(view.name)
if (index > -1) {
state.cachedViews = state.cachedViews.slice(index, index + 1)
} else {
state.cachedViews = []
}
},
DEL_ALL_VISITED_VIEWS: state => {
// keep affix tags
const affixTags = state.visitedViews.filter(tag => tag.meta.affix)
state.visitedViews = affixTags
},
DEL_ALL_CACHED_VIEWS: state => {
state.cachedViews = []
},
UPDATE_VISITED_VIEW: (state, view) => {
for (let v of state.visitedViews) {
if (v.path === view.path) {
v = Object.assign(v, view)
break
}
}
},
DEL_RIGHT_VIEWS: (state, view) => {
const index = state.visitedViews.findIndex(v => v.path === view.path)
if (index === -1) {
return
}
state.visitedViews = state.visitedViews.filter((item, idx) => {
if (idx <= index || (item.meta && item.meta.affix)) {
return true
}
const i = state.cachedViews.indexOf(item.name)
if (i > -1) {
state.cachedViews.splice(i, 1)
}
return false
})
},
DEL_LEFT_VIEWS: (state, view) => {
const index = state.visitedViews.findIndex(v => v.path === view.path)
if (index === -1) {
return
}
state.visitedViews = state.visitedViews.filter((item, idx) => {
if (idx >= index || (item.meta && item.meta.affix)) {
return true
}
const i = state.cachedViews.indexOf(item.name)
if (i > -1) {
state.cachedViews.splice(i, 1)
}
return false
})
}
}
const actions = {
addView({ dispatch }, view) {
dispatch('addVisitedView', view)
dispatch('addCachedView', view)
},
addVisitedView({ commit }, view) {
commit('ADD_VISITED_VIEW', view)
},
addCachedView({ commit }, view) {
commit('ADD_CACHED_VIEW', view)
},
delView({ dispatch, state }, view) {
return new Promise(resolve => {
dispatch('delVisitedView', view)
dispatch('delCachedView', view)
resolve({
visitedViews: [...state.visitedViews],
cachedViews: [...state.cachedViews]
})
})
},
delVisitedView({ commit, state }, view) {
return new Promise(resolve => {
commit('DEL_VISITED_VIEW', view)
resolve([...state.visitedViews])
})
},
delCachedView({ commit, state }, view) {
return new Promise(resolve => {
commit('DEL_CACHED_VIEW', view)
resolve([...state.cachedViews])
})
},
delOthersViews({ dispatch, state }, view) {
return new Promise(resolve => {
dispatch('delOthersVisitedViews', view)
dispatch('delOthersCachedViews', view)
resolve({
visitedViews: [...state.visitedViews],
cachedViews: [...state.cachedViews]
})
})
},
delOthersVisitedViews({ commit, state }, view) {
return new Promise(resolve => {
commit('DEL_OTHERS_VISITED_VIEWS', view)
resolve([...state.visitedViews])
})
},
delOthersCachedViews({ commit, state }, view) {
return new Promise(resolve => {
commit('DEL_OTHERS_CACHED_VIEWS', view)
resolve([...state.cachedViews])
})
},
delAllViews({ dispatch, state }, view) {
return new Promise(resolve => {
dispatch('delAllVisitedViews', view)
dispatch('delAllCachedViews', view)
resolve({
visitedViews: [...state.visitedViews],
cachedViews: [...state.cachedViews]
})
})
},
delAllVisitedViews({ commit, state }) {
return new Promise(resolve => {
commit('DEL_ALL_VISITED_VIEWS')
resolve([...state.visitedViews])
})
},
delAllCachedViews({ commit, state }) {
return new Promise(resolve => {
commit('DEL_ALL_CACHED_VIEWS')
resolve([...state.cachedViews])
})
},
updateVisitedView({ commit }, view) {
commit('UPDATE_VISITED_VIEW', view)
},
delRightTags({ commit }, view) {
return new Promise(resolve => {
commit('DEL_RIGHT_VIEWS', view)
resolve([...state.visitedViews])
})
},
delLeftTags({ commit }, view) {
return new Promise(resolve => {
commit('DEL_LEFT_VIEWS', view)
resolve([...state.visitedViews])
})
},
}
export default {
namespaced: true,
state,
mutations,
actions
}

View File

@ -2,40 +2,19 @@ import { login, logout, getInfo } from '@/api/system/login'
import { getToken, setToken, removeToken } from '@/utils/auth' import { getToken, setToken, removeToken } from '@/utils/auth'
import defAva from '@/assets/images/profile.jpg' import defAva from '@/assets/images/profile.jpg'
const user = { const useUserStore = defineStore('user', {
state: { state: () => ({
userInfo: '', userInfo: '',
token: getToken(), token: getToken(),
name: '', name: '',
avatar: '', avatar: '',
roles: [], roles: [],
permissions: [] permissions: [],
}, userId: 0
}),
mutations: {
SET_TOKEN: (state, token) => {
state.token = token
},
SET_NAME: (state, name) => {
state.name = name
},
SET_AVATAR: (state, avatar) => {
state.avatar = avatar
},
SET_ROLES: (state, roles) => {
state.roles = roles
},
SET_PERMISSIONS: (state, permissions) => {
state.permissions = permissions
},
SET_USERINFO: (state, value) => {
state.userInfo = value
}
},
actions: { actions: {
// 登录 // 登录
Login({ commit }, userInfo) { login(userInfo) {
const username = userInfo.username.trim() const username = userInfo.username.trim()
const password = userInfo.password const password = userInfo.password
const code = userInfo.code const code = userInfo.code
@ -44,8 +23,7 @@ const user = {
login(username, password, code, uuid).then(res => { login(username, password, code, uuid).then(res => {
if (res.code == 200) { if (res.code == 200) {
setToken(res.data) setToken(res.data)
//提交上面的mutaions方法 this.token = res.data
commit('SET_TOKEN', res.data)
resolve() //then处理 resolve() //then处理
} else { } else {
console.log('login error ', res) console.log('login error ', res)
@ -55,25 +33,24 @@ const user = {
reject(error) reject(error)
}) })
}) })
}, }, // 获取用户信息
getInfo() {
// 获取用户信息
GetInfo({ commit, state }) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
getInfo().then(res => { getInfo().then(res => {
const data = res.data const data = res.data
const avatar = data.user.avatar == "" ? defAva : data.user.avatar; const avatar = data.user.avatar == "" ? defAva : data.user.avatar;
if (data.roles && data.roles.length > 0) { // 验证返回的roles是否是一个非空数组 if (data.roles && data.roles.length > 0) { // 验证返回的roles是否是一个非空数组
commit('SET_ROLES', data.roles) this.roles = data.roles
commit('SET_PERMISSIONS', data.permissions) this.permissions = data.permissions
} else { } else {
commit('SET_ROLES', ['ROLE_DEFAULT']) this.roles = ['ROLE_DEFAULT']
} }
commit('SET_NAME', data.user.nickName) this.name = data.user.nickName
commit('SET_AVATAR', avatar) this.avatar = avatar
commit('SET_USERINFO', data.user) //新加 this.userInfo = data.user //新加
this.userId = data.user.userId//新加
resolve(res) resolve(res)
}).catch(error => { }).catch(error => {
console.error(error); console.error(error);
@ -81,14 +58,13 @@ const user = {
}) })
}) })
}, },
// 退出系统 // 退出系统
LogOut({ commit, state }) { logOut() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
logout(state.token).then((res) => { logout(this.token).then((res) => {
commit('SET_TOKEN', '') this.token = ''
commit('SET_ROLES', []) this.roles = []
commit('SET_PERMISSIONS', []) this.permissions = []
removeToken() removeToken()
resolve(res) resolve(res)
}).catch(error => { }).catch(error => {
@ -96,16 +72,14 @@ const user = {
}) })
}) })
}, },
// 前端 登出 // 前端 登出
FedLogOut({ commit }) { fedLogOut() {
return new Promise(resolve => { return new Promise(resolve => {
commit('SET_TOKEN', '') this.token = ''
removeToken() removeToken()
resolve() resolve()
}) })
} }
} }
} })
export default useUserStore
export default user

View File

@ -1,12 +1,14 @@
import store from '@/store' import store from '@/store'
import defaultSettings from '@/settings' import defaultSettings from '@/settings'
import useSettingsStore from '@/store/modules/settings'
/** /**
* 动态修改标题 * 动态修改标题
*/ */
export function useDynamicTitle() { export function useDynamicTitle() {
if (store.state.settings.dynamicTitle) { const settingsStore = useSettingsStore()
document.title = store.state.settings.title + ' - ' + defaultSettings.title; if (settingsStore.dynamicTitle) {
document.title = settingsStore.title + ' - ' + defaultSettings.title;
} else { } else {
document.title = defaultSettings.title; document.title = defaultSettings.title;
} }

View File

@ -1,51 +0,0 @@
import store from '@/store'
/**
* 字符权限校验
* @param {Array} value 校验值
* @returns {Boolean}
*/
export function checkPermi(value) {
if (value && value instanceof Array && value.length > 0) {
const permissions = store.getters && store.getters.permissions
const permissionDatas = value
const all_permission = "*:*:*";
const hasPermission = permissions.some(permission => {
return all_permission === permission || permissionDatas.includes(permission)
})
if (!hasPermission) {
return false
}
return true
} else {
console.error(`need roles! Like checkPermi="['system:user:add','system:user:edit']"`)
return false
}
}
/**
* 角色权限校验
* @param {Array} value 校验值
* @returns {Boolean}
*/
export function checkRole(value) {
if (value && value instanceof Array && value.length > 0) {
const roles = store.getters && store.getters.roles
const permissionRoles = value
const super_admin = "admin";
const hasRole = roles.some(role => {
return super_admin === role || permissionRoles.includes(role)
})
if (!hasRole) {
return false
}
return true
} else {
console.error(`need roles! Like checkRole="['admin','editor']"`)
return false
}
}

View File

@ -1,7 +1,7 @@
import axios from 'axios' import axios from 'axios'
import { ElMessageBox, ElMessage } from 'element-plus' import { ElMessageBox, ElMessage } from 'element-plus'
import store from '@/store'
import { getToken } from '@/utils/auth' import { getToken } from '@/utils/auth'
import useUserStore from '@/store/modules/user'
// 解决后端跨域获取不到cookie问题 // 解决后端跨域获取不到cookie问题
// axios.defaults.withCredentials = true // axios.defaults.withCredentials = true
@ -20,7 +20,7 @@ service.interceptors.request.use(config => {
if (getToken()) { if (getToken()) {
//将token放到请求头发送给服务器,将tokenkey放在请求头中 //将token放到请求头发送给服务器,将tokenkey放在请求头中
config.headers['Authorization'] = 'Bearer ' + getToken(); config.headers['Authorization'] = 'Bearer ' + getToken();
config.headers['userid'] = store.getters.userId; config.headers['userid'] = useUserStore().userId;
} }
return config; return config;
}, error => { }, error => {
@ -46,7 +46,7 @@ service.interceptors.response.use(res => {
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}).then(() => { }).then(() => {
store.dispatch('LogOut').then(() => { useUserStore().logOut().then(() => {
location.href = location.href =
import.meta.env.VITE_APP_ROUTER_PREFIX + 'index'; import.meta.env.VITE_APP_ROUTER_PREFIX + 'index';
}) })

View File

@ -1,10 +1,9 @@
// 官方文档https://docs.microsoft.com/zh-cn/aspnet/core/signalr/javascript-client?view=aspnetcore-6.0&viewFallbackFrom=aspnetcore-2.2&tabs=visual-studio // 官方文档https://docs.microsoft.com/zh-cn/aspnet/core/signalr/javascript-client?view=aspnetcore-6.0&viewFallbackFrom=aspnetcore-2.2&tabs=visual-studio
import * as signalR from '@microsoft/signalr' import * as signalR from '@microsoft/signalr'
import store from '../store'
import { getToken } from '@/utils/auth' import { getToken } from '@/utils/auth'
import { ElNotification } from 'element-plus' import { ElNotification } from 'element-plus'
import { useWebNotification } from '@vueuse/core' import { useWebNotification } from '@vueuse/core'
import useSocketStore from '@/store/modules/socket'
export default { export default {
// signalR对象 // signalR对象
SR: {}, SR: {},
@ -49,8 +48,8 @@ export default {
return true return true
} catch (error) { } catch (error) {
that.failNum--; that.failNum--;
console.log(`失败重试剩余次数${that.failNum}`, error) // console.log(`失败重试剩余次数${that.failNum}`, error)
if (that.failNum > 0) { if (that.failNum > 0 && this.SR.state.Disconnected) {
setTimeout(async () => { setTimeout(async () => {
await this.SR.start() await this.SR.start()
}, 5000) }, 5000)
@ -61,11 +60,10 @@ export default {
// 接收消息处理 // 接收消息处理
receiveMsg(connection) { receiveMsg(connection) {
connection.on("onlineNum", (data) => { connection.on("onlineNum", (data) => {
store.dispatch("socket/changeOnlineNum", data); useSocketStore().setOnlineUserNum(data)
}); });
// 接收欢迎语 // 接收欢迎语
connection.on("welcome", (data) => { connection.on("welcome", (data) => {
console.log('welcome', data)
ElNotification.info(data) ElNotification.info(data)
}); });
// 接收后台手动推送消息 // 接收后台手动推送消息
@ -91,13 +89,13 @@ export default {
// 接收系统通知/公告 // 接收系统通知/公告
connection.on("moreNotice", (data) => { connection.on("moreNotice", (data) => {
if (data.code == 200) { if (data.code == 200) {
store.dispatch("socket/getNoticeList", data.data); useSocketStore().setNoticeList(data.data)
} }
}) })
// 接收在线用户 // 接收在线用户
connection.on("onlineUser", (data) => { connection.on("onlineUser", (data) => {
store.dispatch("socket/getOnlineUsers", data); useSocketStore().setOnlineUsers(data)
}) })
} }
} }

View File

@ -49,13 +49,14 @@
<script setup> <script setup>
import { CountUp } from 'countup.js' import { CountUp } from 'countup.js'
import useSocketStore from '@/store/modules/socket';
const emit = defineEmits() const emit = defineEmits()
const { proxy } = getCurrentInstance() const { proxy } = getCurrentInstance()
const state = reactive({ const state = reactive({
chatNum: 1390, chatNum: 1390,
onlineNum: computed(() => { onlineNum: computed(() => {
return proxy.$store.getters.onlineUserNum return useSocketStore().onlineNum
}), }),
amount: 99998, amount: 99998,
order: 1999, order: 1999,

View File

@ -130,6 +130,9 @@ import WordCloudChat from './dashboard/WordCloud.vue'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import useUserStore from '@/store/modules/user'
import useSocketStore from '@/store/modules/socket'
const data = { const data = {
newVisitis: { newVisitis: {
expectedData: [100, 120, 161, 134, 105, 160, 165], expectedData: [100, 120, 161, 134, 105, 160, 165],
@ -200,13 +203,13 @@ const data = {
} }
const { proxy } = getCurrentInstance() const { proxy } = getCurrentInstance()
const userInfo = computed(() => { const userInfo = computed(() => {
return proxy.$store.getters.userinfo return useUserStore().userInfo
}) })
const currentTime = computed(() => { const currentTime = computed(() => {
return proxy.parseTime(new Date()) return proxy.parseTime(new Date())
}) })
const onlineUsers = computed(() => { const onlineUsers = computed(() => {
return proxy.$store.getters.onlineUsers return useSocketStore().onlineUsers
}) })
let lineChartData = reactive([]) let lineChartData = reactive([])

View File

@ -69,8 +69,9 @@ import { encrypt, decrypt } from '@/utils/jsencrypt'
import defaultSettings from '@/settings' import defaultSettings from '@/settings'
import starBackground from '@/views/components/starBackground.vue' import starBackground from '@/views/components/starBackground.vue'
import LangSelect from '@/components/LangSelect/index.vue' import LangSelect from '@/components/LangSelect/index.vue'
import useUserStore from '@/store/modules/user'
const store = useStore() const userStore = useUserStore()
const router = useRouter() const router = useRouter()
const { proxy } = getCurrentInstance() const { proxy } = getCurrentInstance()
@ -118,8 +119,8 @@ function handleLogin() {
Cookies.remove('rememberMe') Cookies.remove('rememberMe')
} }
// action // action
store userStore
.dispatch('Login', loginForm.value) .login(loginForm.value)
.then(() => { .then(() => {
proxy.$modal.msgSuccess(proxy.$t('login.loginSuccess')) proxy.$modal.msgSuccess(proxy.$t('login.loginSuccess'))
router.push({ path: redirect.value || '/' }) router.push({ path: redirect.value || '/' })

View File

@ -1,50 +1,55 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px"> <el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px">
<el-form-item> <el-form-item>
<el-date-picker v-model="dateRange" size="small" style="width: 240px" value-format="YYYY-MM-DD" type="daterange" <el-date-picker
range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"> v-model="dateRange"
</el-date-picker> size="small"
</el-form-item> style="width: 240px"
<el-form-item> value-format="YYYY-MM-DD"
<el-button type="primary" icon="search" @click="handleQuery">搜索</el-button> type="daterange"
<el-button icon="refresh" @click="resetQuery">重置</el-button> range-separator="-"
</el-form-item> start-placeholder="开始日期"
</el-form> end-placeholder="结束日期">
</el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="search" @click="handleQuery">搜索</el-button>
<el-button icon="refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-table v-loading="loading" :data="list"> <el-table v-loading="loading" :data="list">
<!-- <el-table-column label="编号" align="center" prop="operId" width="60px" :show-overflow-tooltip="true" /> --> <!-- <el-table-column label="编号" align="center" prop="operId" width="60px" :show-overflow-tooltip="true" /> -->
<el-table-column label="系统模块" align="center" prop="title" :show-overflow-tooltip="true" /> <el-table-column label="系统模块" align="center" prop="title" :show-overflow-tooltip="true" />
<el-table-column prop="businessType" label="业务类型" align="center"> <el-table-column prop="businessType" label="业务类型" align="center">
<template #default="scope"> <template #default="scope">
<dict-tag :options="businessTypeOptions" :value="scope.row.businessType" /> <dict-tag :options="businessTypeOptions" :value="scope.row.businessType" />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="请求方式" align="center" prop="requestMethod" /> <el-table-column label="请求方式" align="center" prop="requestMethod" />
<el-table-column label="操作地点" align="center" prop="operLocation" :show-overflow-tooltip="true" /> <el-table-column label="操作地点" align="center" prop="operLocation" :show-overflow-tooltip="true" />
<el-table-column label="操作状态" align="center" prop="status"> <el-table-column label="操作状态" align="center" prop="status">
<template #default="{ row }"> <template #default="{ row }">
<dict-tag :options="statusOptions" :value="row.status"></dict-tag> <dict-tag :options="statusOptions" :value="row.status"></dict-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="日志内容" align="center" prop="errorMsg" :show-overflow-tooltip="true" /> <el-table-column label="日志内容" align="center" prop="errorMsg" :show-overflow-tooltip="true" />
<el-table-column label="操作日期" align="center" prop="operTime" width="180"> <el-table-column label="操作日期" align="center" prop="operTime" width="180">
<template #default="scope"> <template #default="scope">
<span>{{ scope.row.operTime }}</span> <span>{{ scope.row.operTime }}</span>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
v-model:limit="queryParams.pageSize" @pagination="getList" /> </div>
</div>
</template> </template>
<script setup name="operlog"> <script setup name="operlog">
import { list as queryLog } from '@/api/monitor/operlog' import { list as queryLog } from '@/api/monitor/operlog'
import useUserStore from '@/store/modules/user'
// //
const loading = ref(true) const loading = ref(true)
// //
@ -60,53 +65,50 @@ const dateRange = ref([])
// //
const queryParams = reactive({ const queryParams = reactive({
pageNum: 1, pageNum: 1,
pageSize: 10, pageSize: 10,
title: undefined, title: undefined,
operName: undefined, operName: undefined,
businessType: undefined, businessType: undefined,
status: undefined, status: undefined,
}) })
const { proxy } = getCurrentInstance() const { proxy } = getCurrentInstance()
var dictParams = [ var dictParams = [
{ dictType: 'sys_oper_type', columnName: 'businessTypeOptions' }, { dictType: 'sys_oper_type', columnName: 'businessTypeOptions' },
{ dictType: 'sys_common_status', columnName: 'statusOptions' }, { dictType: 'sys_common_status', columnName: 'statusOptions' },
] ]
proxy.getDicts(dictParams).then((response) => { proxy.getDicts(dictParams).then((response) => {
response.data.forEach((element) => { response.data.forEach((element) => {
proxy[element.columnName] = element.list proxy[element.columnName] = element.list
}) })
}) })
/** 查询登录日志 */ /** 查询登录日志 */
function getList() { function getList() {
loading.value = true loading.value = true
queryParams.operName = proxy.$store.getters.userinfo.userName queryParams.operName = useUserStore().userInfo.userName
queryLog(proxy.addDateRange(queryParams, dateRange.value)).then( queryLog(proxy.addDateRange(queryParams, dateRange.value)).then((response) => {
(response) => { loading.value = false
loading.value = false if (response.code == 200) {
if (response.code == 200) { list.value = response.data.result
list.value = response.data.result total.value = response.data.totalNum
total.value = response.data.totalNum } else {
} else { total.value = 0
total.value = 0 list.value = []
list.value = [] }
} })
}
)
} }
/** 重置按钮操作 */ /** 重置按钮操作 */
function resetQuery() { function resetQuery() {
dateRange.value = [] dateRange.value = []
proxy.resetForm('queryForm') proxy.resetForm('queryForm')
handleQuery() handleQuery()
} }
/** 搜索按钮操作 */ /** 搜索按钮操作 */
function handleQuery() { function handleQuery() {
queryParams.pageNum = 1 queryParams.pageNum = 1
getList() getList()
} }
getList() getList()
</script> </script>

View File

@ -57,6 +57,7 @@
import 'vue-cropper/dist/index.css' import 'vue-cropper/dist/index.css'
import { VueCropper } from 'vue-cropper' import { VueCropper } from 'vue-cropper'
import { uploadAvatar } from '@/api/system/user' import { uploadAvatar } from '@/api/system/user'
import useUserStore from '@/store/modules/user'
export default { export default {
components: { components: {
@ -69,7 +70,7 @@ export default {
}, },
}, },
setup() { setup() {
const store = useStore() const useStore = useUserStore()
const { proxy } = getCurrentInstance() const { proxy } = getCurrentInstance()
const open = ref(false) const open = ref(false)
@ -78,7 +79,7 @@ export default {
const fileName = ref('') const fileName = ref('')
// //
const options = reactive({ const options = reactive({
img: store.getters.avatar, // img: useStore.avatar, //
autoCrop: true, // autoCrop: true, //
autoCropWidth: 200, // autoCropWidth: 200, //
autoCropHeight: 200, // autoCropHeight: 200, //
@ -126,12 +127,12 @@ export default {
function uploadImg() { function uploadImg() {
proxy.$refs.cropper.getCropBlob((data) => { proxy.$refs.cropper.getCropBlob((data) => {
let formData = new FormData() let formData = new FormData()
var fileOfBlob = new File([data], fileName.value); var fileOfBlob = new File([data], fileName.value)
formData.append('picture', fileOfBlob) formData.append('picture', fileOfBlob)
uploadAvatar(formData).then((response) => { uploadAvatar(formData).then((response) => {
open.value = false open.value = false
options.img = response.data.imgUrl options.img = response.data.imgUrl
store.commit('SET_AVATAR', options.img) useStore.avatar = options.img
proxy.$modal.msgSuccess('修改成功') proxy.$modal.msgSuccess('修改成功')
visible.value = false visible.value = false
}) })
@ -143,7 +144,7 @@ export default {
} }
/** 关闭窗口 */ /** 关闭窗口 */
function closeDialog() { function closeDialog() {
options.img = store.getters.avatar options.img = useStore.avatar
options.visible = false options.visible = false
} }

View File

@ -5,9 +5,7 @@ export default function createAutoImport() {
imports: [ imports: [
'vue', 'vue',
'vue-router', 'vue-router',
{ 'pinia'
'vuex': ['useStore']
}
], ],
dts: "src/auto-import.d.ts" // 生成 `auto-import.d.ts` 全局声明 dts: "src/auto-import.d.ts" // 生成 `auto-import.d.ts` 全局声明
}) })