refactor: 统一代码风格 (if 语句 & 箭头函数)
This commit is contained in:
parent
9b359203fc
commit
0f5f16cf0f
@ -9,6 +9,7 @@ const { initGreyAndColorWeakness } = useGreyAndColorWeakness()
|
|||||||
|
|
||||||
// 初始化主题
|
// 初始化主题
|
||||||
initTheme()
|
initTheme()
|
||||||
|
|
||||||
// 初始化灰色模式和色弱模式
|
// 初始化灰色模式和色弱模式
|
||||||
initGreyAndColorWeakness()
|
initGreyAndColorWeakness()
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* dark-blue 主题模式下的 Element Plus CSS 变量
|
* @description dark-blue 主题模式下的 Element Plus CSS 变量
|
||||||
* 在此查阅所有可自定义的变量:https://github.com/element-plus/element-plus/blob/dev/packages/theme-chalk/src/common/var.scss
|
* @description 在此查阅所有可自定义的变量:https://github.com/element-plus/element-plus/blob/dev/packages/theme-chalk/src/common/var.scss
|
||||||
* 也可以打开浏览器控制台选择元素,查看要覆盖的变量名
|
* @description 也可以打开浏览器控制台选择元素,查看要覆盖的变量名
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* 基础颜色 */
|
/* 基础颜色 */
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* 所有主题模式下的 Vxe Table CSS 变量
|
* @description 所有主题模式下的 Vxe Table CSS 变量
|
||||||
* 用 Element Plus 的 CSS 变量来覆写 Vxe Table 的 CSS 变量,目的是使 Vxe Table 支持多主题模式且样式统一
|
* @description 用 Element Plus 的 CSS 变量来覆写 Vxe Table 的 CSS 变量,目的是使 Vxe Table 支持多主题模式且样式统一
|
||||||
* 在此查阅所有可自定义的变量:https://github.com/x-extends/vxe-table/blob/master/styles/css-variable.scss
|
* @description 在此查阅所有可自定义的变量:https://github.com/x-extends/vxe-table/blob/master/styles/css-variable.scss
|
||||||
*/
|
*/
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
|
@ -16,12 +16,16 @@ interface DataItem {
|
|||||||
|
|
||||||
/** 角标当前值 */
|
/** 角标当前值 */
|
||||||
const badgeValue = computed(() => data.value.reduce((sum, item) => sum + item.list.length, 0))
|
const badgeValue = computed(() => data.value.reduce((sum, item) => sum + item.list.length, 0))
|
||||||
|
|
||||||
/** 角标最大值 */
|
/** 角标最大值 */
|
||||||
const badgeMax = 99
|
const badgeMax = 99
|
||||||
|
|
||||||
/** 面板宽度 */
|
/** 面板宽度 */
|
||||||
const popoverWidth = 350
|
const popoverWidth = 350
|
||||||
|
|
||||||
/** 当前 Tab */
|
/** 当前 Tab */
|
||||||
const activeName = ref<TabName>("通知")
|
const activeName = ref<TabName>("通知")
|
||||||
|
|
||||||
/** 所有数据 */
|
/** 所有数据 */
|
||||||
const data = ref<DataItem[]>([
|
const data = ref<DataItem[]>([
|
||||||
// 通知数据
|
// 通知数据
|
||||||
|
@ -22,7 +22,9 @@ const props = withDefaults(defineProps<Props>(), {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const CONTENT_LARGE = "content-large"
|
const CONTENT_LARGE = "content-large"
|
||||||
|
|
||||||
const CONTENT_FULL = "content-full"
|
const CONTENT_FULL = "content-full"
|
||||||
|
|
||||||
const classList = document.body.classList
|
const classList = document.body.classList
|
||||||
|
|
||||||
// #region 全屏
|
// #region 全屏
|
||||||
@ -35,17 +37,21 @@ function handleFullscreenClick() {
|
|||||||
const dom = document.querySelector(props.element) || undefined
|
const dom = document.querySelector(props.element) || undefined
|
||||||
isEnabled ? screenfull.toggle(dom) : ElMessage.warning("您的浏览器无法工作")
|
isEnabled ? screenfull.toggle(dom) : ElMessage.warning("您的浏览器无法工作")
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleFullscreenChange() {
|
function handleFullscreenChange() {
|
||||||
isFullscreen.value = screenfull.isFullscreen
|
isFullscreen.value = screenfull.isFullscreen
|
||||||
// 退出全屏时清除相关的 class
|
// 退出全屏时清除相关的 class
|
||||||
isFullscreen.value || classList.remove(CONTENT_LARGE, CONTENT_FULL)
|
isFullscreen.value || classList.remove(CONTENT_LARGE, CONTENT_FULL)
|
||||||
}
|
}
|
||||||
|
|
||||||
watchEffect((onCleanup) => {
|
watchEffect((onCleanup) => {
|
||||||
if (isEnabled) {
|
if (isEnabled) {
|
||||||
// 挂载组件时自动执行
|
// 挂载组件时自动执行
|
||||||
screenfull.on("change", handleFullscreenChange)
|
screenfull.on("change", handleFullscreenChange)
|
||||||
// 卸载组件时自动执行
|
// 卸载组件时自动执行
|
||||||
onCleanup(() => screenfull.off("change", handleFullscreenChange))
|
onCleanup(() => {
|
||||||
|
screenfull.off("change", handleFullscreenChange)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
// #endregion
|
// #endregion
|
||||||
@ -54,11 +60,13 @@ watchEffect((onCleanup) => {
|
|||||||
const isContentLarge = ref<boolean>(false)
|
const isContentLarge = ref<boolean>(false)
|
||||||
const contentLargeTips = computed(() => (isContentLarge.value ? "内容区复原" : "内容区放大"))
|
const contentLargeTips = computed(() => (isContentLarge.value ? "内容区复原" : "内容区放大"))
|
||||||
const contentLargeSvgName = computed(() => (isContentLarge.value ? "fullscreen-exit" : "fullscreen"))
|
const contentLargeSvgName = computed(() => (isContentLarge.value ? "fullscreen-exit" : "fullscreen"))
|
||||||
|
|
||||||
function handleContentLargeClick() {
|
function handleContentLargeClick() {
|
||||||
isContentLarge.value = !isContentLarge.value
|
isContentLarge.value = !isContentLarge.value
|
||||||
// 内容区放大时,将不需要的组件隐藏
|
// 内容区放大时,将不需要的组件隐藏
|
||||||
classList.toggle(CONTENT_LARGE, isContentLarge.value)
|
classList.toggle(CONTENT_LARGE, isContentLarge.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleContentFullClick() {
|
function handleContentFullClick() {
|
||||||
// 取消内容区放大
|
// 取消内容区放大
|
||||||
isContentLarge.value && handleContentLargeClick()
|
isContentLarge.value && handleContentLargeClick()
|
||||||
|
@ -130,7 +130,7 @@ function handleEnter() {
|
|||||||
try {
|
try {
|
||||||
router.push({ name })
|
router.push({ name })
|
||||||
} catch {
|
} catch {
|
||||||
return ElMessage.error("该菜单有必填的动态参数,无法通过搜索进入")
|
return ElMessage.warning("该菜单有必填的动态参数,无法通过搜索进入")
|
||||||
}
|
}
|
||||||
handleClose()
|
handleClose()
|
||||||
}
|
}
|
||||||
|
@ -8,10 +8,12 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<Props>()
|
const props = defineProps<Props>()
|
||||||
|
|
||||||
/** 选中的菜单 */
|
/** 选中的菜单 */
|
||||||
const modelValue = defineModel<RouteRecordName | undefined>({ required: true })
|
const modelValue = defineModel<RouteRecordName | undefined>({ required: true })
|
||||||
|
|
||||||
const instance = getCurrentInstance()
|
const instance = getCurrentInstance()
|
||||||
|
|
||||||
const scrollbarHeight = ref<number>(0)
|
const scrollbarHeight = ref<number>(0)
|
||||||
|
|
||||||
/** 菜单的样式 */
|
/** 菜单的样式 */
|
||||||
@ -47,13 +49,19 @@ function getScrollTop(index: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 在组件挂载前添加窗口大小变化事件监听器
|
// 在组件挂载前添加窗口大小变化事件监听器
|
||||||
onBeforeMount(() => window.addEventListener("resize", getScrollbarHeight))
|
onBeforeMount(() => {
|
||||||
|
window.addEventListener("resize", getScrollbarHeight)
|
||||||
|
})
|
||||||
|
|
||||||
// 在组件挂载时立即计算滚动可视区高度
|
// 在组件挂载时立即计算滚动可视区高度
|
||||||
onMounted(() => getScrollbarHeight())
|
onMounted(() => {
|
||||||
|
getScrollbarHeight()
|
||||||
|
})
|
||||||
|
|
||||||
// 在组件卸载前移除窗口大小变化事件监听器
|
// 在组件卸载前移除窗口大小变化事件监听器
|
||||||
onBeforeUnmount(() => window.removeEventListener("resize", getScrollbarHeight))
|
onBeforeUnmount(() => {
|
||||||
|
window.removeEventListener("resize", getScrollbarHeight)
|
||||||
|
})
|
||||||
|
|
||||||
defineExpose({ getScrollTop })
|
defineExpose({ getScrollTop })
|
||||||
</script>
|
</script>
|
||||||
|
@ -14,7 +14,9 @@ function handleChangeTheme({ clientX, clientY }: MouseEvent, themeName: ThemeNam
|
|||||||
style.setProperty("--v3-theme-x", `${clientX}px`)
|
style.setProperty("--v3-theme-x", `${clientX}px`)
|
||||||
style.setProperty("--v3-theme-y", `${clientY}px`)
|
style.setProperty("--v3-theme-y", `${clientY}px`)
|
||||||
style.setProperty("--v3-theme-r", `${maxRadius}px`)
|
style.setProperty("--v3-theme-r", `${maxRadius}px`)
|
||||||
const handler = () => setTheme(themeName)
|
const handler = () => {
|
||||||
|
setTheme(themeName)
|
||||||
|
}
|
||||||
document.startViewTransition ? document.startViewTransition(handler) : handler()
|
document.startViewTransition ? document.startViewTransition(handler) : handler()
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -3,6 +3,7 @@ import { useAppStore } from "@/pinia/stores/app"
|
|||||||
import { computed } from "vue"
|
import { computed } from "vue"
|
||||||
|
|
||||||
const appStore = useAppStore()
|
const appStore = useAppStore()
|
||||||
|
|
||||||
const isMobile = computed(() => appStore.device === DeviceEnum.Mobile)
|
const isMobile = computed(() => appStore.device === DeviceEnum.Mobile)
|
||||||
const isDesktop = computed(() => appStore.device === DeviceEnum.Desktop)
|
const isDesktop = computed(() => appStore.device === DeviceEnum.Desktop)
|
||||||
|
|
||||||
|
@ -29,16 +29,16 @@ export function useFetchSelect(props: FetchSelectProps) {
|
|||||||
const loadData = () => {
|
const loadData = () => {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
options.value = []
|
options.value = []
|
||||||
api()
|
api().then((res) => {
|
||||||
.then((res) => {
|
|
||||||
options.value = res.data
|
options.value = res.data
|
||||||
})
|
}).finally(() => {
|
||||||
.finally(() => {
|
|
||||||
loading.value = false
|
loading.value = false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => loadData())
|
onMounted(() => {
|
||||||
|
loadData()
|
||||||
|
})
|
||||||
|
|
||||||
return { loading, options, value }
|
return { loading, options, value }
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ import { watchEffect } from "vue"
|
|||||||
|
|
||||||
const GREY_MODE = "grey-mode"
|
const GREY_MODE = "grey-mode"
|
||||||
const COLOR_WEAKNESS = "color-weakness"
|
const COLOR_WEAKNESS = "color-weakness"
|
||||||
|
|
||||||
const classList = document.documentElement.classList
|
const classList = document.documentElement.classList
|
||||||
|
|
||||||
/** 初始化 */
|
/** 初始化 */
|
||||||
|
@ -3,6 +3,7 @@ import { useSettingsStore } from "@/pinia/stores/settings"
|
|||||||
import { computed } from "vue"
|
import { computed } from "vue"
|
||||||
|
|
||||||
const settingsStore = useSettingsStore()
|
const settingsStore = useSettingsStore()
|
||||||
|
|
||||||
const isLeft = computed(() => settingsStore.layoutMode === LayoutModeEnum.Left)
|
const isLeft = computed(() => settingsStore.layoutMode === LayoutModeEnum.Left)
|
||||||
const isTop = computed(() => settingsStore.layoutMode === LayoutModeEnum.Top)
|
const isTop = computed(() => settingsStore.layoutMode === LayoutModeEnum.Top)
|
||||||
const isLeftTop = computed(() => settingsStore.layoutMode === LayoutModeEnum.LeftTop)
|
const isLeftTop = computed(() => settingsStore.layoutMode === LayoutModeEnum.LeftTop)
|
||||||
|
@ -6,7 +6,9 @@ import { onBeforeUnmount } from "vue"
|
|||||||
type Callback = (route: RouteLocationNormalized) => void
|
type Callback = (route: RouteLocationNormalized) => void
|
||||||
|
|
||||||
const emitter = mitt()
|
const emitter = mitt()
|
||||||
|
|
||||||
const key = Symbol("ROUTE_CHANGE")
|
const key = Symbol("ROUTE_CHANGE")
|
||||||
|
|
||||||
let latestRoute: RouteLocationNormalized
|
let latestRoute: RouteLocationNormalized
|
||||||
|
|
||||||
/** 设置最新的路由信息,触发路由变化事件 */
|
/** 设置最新的路由信息,触发路由变化事件 */
|
||||||
@ -18,9 +20,9 @@ export function setRouteChange(to: RouteLocationNormalized) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 订阅路由变化 Composable
|
* @name 订阅路由变化 Composable
|
||||||
* 1. 单独用 watch 监听路由会浪费渲染性能
|
* @description 1. 单独用 watch 监听路由会浪费渲染性能
|
||||||
* 2. 可优先选择使用该发布订阅模式去进行分发管理
|
* @description 2. 可优先选择使用该发布订阅模式去进行分发管理
|
||||||
*/
|
*/
|
||||||
export function useRouteListener() {
|
export function useRouteListener() {
|
||||||
// 回调函数集合
|
// 回调函数集合
|
||||||
@ -43,9 +45,7 @@ export function useRouteListener() {
|
|||||||
|
|
||||||
// 组件销毁前移除监听器
|
// 组件销毁前移除监听器
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
for (let i = 0; i < callbackList.length; i++) {
|
callbackList.forEach(removeRouteListener)
|
||||||
removeRouteListener(callbackList[i])
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return { listenerRouteChange, removeRouteListener }
|
return { listenerRouteChange, removeRouteListener }
|
||||||
|
@ -2,14 +2,6 @@ import type { Ref } from "vue"
|
|||||||
import { debounce } from "lodash-es"
|
import { debounce } from "lodash-es"
|
||||||
import { onBeforeUnmount, ref } from "vue"
|
import { onBeforeUnmount, ref } from "vue"
|
||||||
|
|
||||||
interface Observer {
|
|
||||||
watermarkElMutationObserver?: MutationObserver
|
|
||||||
parentElMutationObserver?: MutationObserver
|
|
||||||
parentElResizeObserver?: ResizeObserver
|
|
||||||
}
|
|
||||||
|
|
||||||
type DefaultConfig = typeof DEFAULT_CONFIG
|
|
||||||
|
|
||||||
/** 默认配置 */
|
/** 默认配置 */
|
||||||
const DEFAULT_CONFIG = {
|
const DEFAULT_CONFIG = {
|
||||||
/** 防御(默认开启,能防御水印被删除或隐藏,但可能会有性能损耗) */
|
/** 防御(默认开启,能防御水印被删除或隐藏,但可能会有性能损耗) */
|
||||||
@ -30,13 +22,21 @@ const DEFAULT_CONFIG = {
|
|||||||
height: 200
|
height: 200
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DefaultConfig = typeof DEFAULT_CONFIG
|
||||||
|
|
||||||
|
interface Observer {
|
||||||
|
watermarkElMutationObserver?: MutationObserver
|
||||||
|
parentElMutationObserver?: MutationObserver
|
||||||
|
parentElResizeObserver?: ResizeObserver
|
||||||
|
}
|
||||||
|
|
||||||
/** body 元素 */
|
/** body 元素 */
|
||||||
const bodyEl = ref<HTMLElement>(document.body)
|
const bodyEl = ref<HTMLElement>(document.body)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 水印 Composable
|
* @name 水印 Composable
|
||||||
* 1. 可以选择传入挂载水印的容器元素,默认是 body
|
* @description 1. 可以选择传入挂载水印的容器元素,默认是 body
|
||||||
* 2. 做了水印防御,能有效防御别人打开控制台删除或隐藏水印
|
* @description 2. 做了水印防御,能有效防御别人打开控制台删除或隐藏水印
|
||||||
*/
|
*/
|
||||||
export function useWatermark(parentEl: Ref<HTMLElement | null> = bodyEl) {
|
export function useWatermark(parentEl: Ref<HTMLElement | null> = bodyEl) {
|
||||||
// 备份文本
|
// 备份文本
|
||||||
@ -226,7 +226,9 @@ export function useWatermark(parentEl: Ref<HTMLElement | null> = bodyEl) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 在组件卸载前移除水印以及各种监听
|
// 在组件卸载前移除水印以及各种监听
|
||||||
onBeforeUnmount(() => clearWatermark())
|
onBeforeUnmount(() => {
|
||||||
|
clearWatermark()
|
||||||
|
})
|
||||||
|
|
||||||
return { setWatermark, clearWatermark }
|
return { setWatermark, clearWatermark }
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,22 @@
|
|||||||
/** 路由配置 */
|
/** 路由配置 */
|
||||||
interface RouteSettings {
|
interface RouteSettings {
|
||||||
/**
|
/**
|
||||||
* 是否开启动态路由功能?
|
* @name 是否开启动态路由功能
|
||||||
* 1. 开启后需要后端配合,在查询用户详情接口返回当前用户可以用来判断并加载动态路由的字段(该项目用的是角色 roles 字段)
|
* @description 1. 开启后需要后端配合,在查询用户详情接口返回当前用户可以用来判断并加载动态路由的字段(该项目用的是角色 roles 字段)
|
||||||
* 2. 假如项目不需要根据不同的用户来显示不同的页面,则应该将 dynamic: false
|
* @description 2. 假如项目不需要根据不同的用户来显示不同的页面,则应该将 dynamic: false
|
||||||
*/
|
*/
|
||||||
dynamic: boolean
|
dynamic: boolean
|
||||||
/**
|
/**
|
||||||
* 当动态路由功能关闭时:
|
* @name 默认角色
|
||||||
* 1. 应该将所有路由都写到常驻路由里面(表明所有登录的用户能访问的页面都是一样的)
|
* @description 当动态路由功能关闭时:
|
||||||
* 2. 系统自动给当前登录用户赋值一个没有任何作用的默认角色
|
* @description 1. 应该将所有路由都写到常驻路由里面(表明所有登录的用户能访问的页面都是一样的)
|
||||||
|
* @description 2. 系统自动给当前登录用户赋值一个没有任何作用的默认角色
|
||||||
*/
|
*/
|
||||||
defaultRoles: Array<string>
|
defaultRoles: Array<string>
|
||||||
/**
|
/**
|
||||||
* 是否开启三级及其以上路由缓存功能?
|
* @name 是否开启三级及其以上路由缓存功能
|
||||||
* 1. 开启后会进行路由降级(把三级及其以上的路由转化为二级路由)
|
* @description 1. 开启后会进行路由降级(把三级及其以上的路由转化为二级路由)
|
||||||
* 2. 由于都会转成二级路由,所以二级及其以上路由有内嵌子路由将会失效
|
* @description 2. 由于都会转成二级路由,所以二级及其以上路由有内嵌子路由将会失效
|
||||||
*/
|
*/
|
||||||
thirdLevelRouteCache: boolean
|
thirdLevelRouteCache: boolean
|
||||||
}
|
}
|
||||||
|
@ -13,8 +13,10 @@ export enum LayoutModeEnum {
|
|||||||
|
|
||||||
/** 侧边栏打开状态常量 */
|
/** 侧边栏打开状态常量 */
|
||||||
export const SIDEBAR_OPENED = "opened"
|
export const SIDEBAR_OPENED = "opened"
|
||||||
|
|
||||||
/** 侧边栏关闭状态常量 */
|
/** 侧边栏关闭状态常量 */
|
||||||
export const SIDEBAR_CLOSED = "closed"
|
export const SIDEBAR_CLOSED = "closed"
|
||||||
|
|
||||||
export type SidebarOpened = typeof SIDEBAR_OPENED
|
export type SidebarOpened = typeof SIDEBAR_OPENED
|
||||||
|
|
||||||
export type SidebarClosed = typeof SIDEBAR_CLOSED
|
export type SidebarClosed = typeof SIDEBAR_CLOSED
|
||||||
|
@ -2,7 +2,10 @@ import type { Directive } from "vue"
|
|||||||
import { useUserStore } from "@/pinia/stores/user"
|
import { useUserStore } from "@/pinia/stores/user"
|
||||||
import { isArray } from "@/utils/validate"
|
import { isArray } from "@/utils/validate"
|
||||||
|
|
||||||
/** 权限指令,和权限判断函数 checkPermission 功能类似 */
|
/**
|
||||||
|
* @name 权限指令
|
||||||
|
* @description 和权限判断函数 checkPermission 功能类似
|
||||||
|
*/
|
||||||
export const permission: Directive = {
|
export const permission: Directive = {
|
||||||
mounted(el, binding) {
|
mounted(el, binding) {
|
||||||
const { value: permissionRoles } = binding
|
const { value: permissionRoles } = binding
|
||||||
|
@ -88,8 +88,6 @@ function createInstance() {
|
|||||||
case 505:
|
case 505:
|
||||||
error.message = "HTTP 版本不受支持"
|
error.message = "HTTP 版本不受支持"
|
||||||
break
|
break
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
ElMessage.error(error.message)
|
ElMessage.error(error.message)
|
||||||
return Promise.reject(error)
|
return Promise.reject(error)
|
||||||
|
@ -6,7 +6,9 @@ import { ref } from "vue"
|
|||||||
import { useRoute, useRouter } from "vue-router"
|
import { useRoute, useRouter } from "vue-router"
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
const { listenerRouteChange } = useRouteListener()
|
const { listenerRouteChange } = useRouteListener()
|
||||||
|
|
||||||
/** 定义响应式数据 breadcrumbs,用于存储面包屑导航信息 */
|
/** 定义响应式数据 breadcrumbs,用于存储面包屑导航信息 */
|
||||||
@ -26,10 +28,7 @@ function pathCompile(path: string) {
|
|||||||
/** 处理面包屑导航点击事件 */
|
/** 处理面包屑导航点击事件 */
|
||||||
function handleLink(item: RouteLocationMatched) {
|
function handleLink(item: RouteLocationMatched) {
|
||||||
const { redirect, path } = item
|
const { redirect, path } = item
|
||||||
if (redirect) {
|
if (redirect) return router.push(redirect as string)
|
||||||
router.push(redirect as string)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
router.push(pathCompile(path))
|
router.push(pathCompile(path))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ const props = withDefaults(defineProps<Props>(), {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const buttonTopCss = `${props.buttonTop}px`
|
const buttonTopCss = `${props.buttonTop}px`
|
||||||
|
|
||||||
const show = ref(false)
|
const show = ref(false)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ import { watchEffect } from "vue"
|
|||||||
import SelectLayoutMode from "./SelectLayoutMode.vue"
|
import SelectLayoutMode from "./SelectLayoutMode.vue"
|
||||||
|
|
||||||
const { isLeft } = useLayoutMode()
|
const { isLeft } = useLayoutMode()
|
||||||
|
|
||||||
const settingsStore = useSettingsStore()
|
const settingsStore = useSettingsStore()
|
||||||
|
|
||||||
// 使用 storeToRefs 将提取的属性保持其响应性
|
// 使用 storeToRefs 将提取的属性保持其响应性
|
||||||
|
@ -18,14 +18,10 @@ const props = withDefaults(defineProps<Props>(), {
|
|||||||
const alwaysShowRootMenu = computed(() => props.item.meta?.alwaysShow)
|
const alwaysShowRootMenu = computed(() => props.item.meta?.alwaysShow)
|
||||||
|
|
||||||
/** 显示的子菜单 */
|
/** 显示的子菜单 */
|
||||||
const showingChildren = computed(() => {
|
const showingChildren = computed(() => props.item.children?.filter(child => !child.meta?.hidden) ?? [])
|
||||||
return props.item.children?.filter(child => !child.meta?.hidden) ?? []
|
|
||||||
})
|
|
||||||
|
|
||||||
/** 显示的子菜单数量 */
|
/** 显示的子菜单数量 */
|
||||||
const showingChildNumber = computed(() => {
|
const showingChildNumber = computed(() => showingChildren.value.length)
|
||||||
return showingChildren.value.length
|
|
||||||
})
|
|
||||||
|
|
||||||
/** 唯一的子菜单项 */
|
/** 唯一的子菜单项 */
|
||||||
const theOnlyOneChild = computed(() => {
|
const theOnlyOneChild = computed(() => {
|
||||||
|
@ -21,28 +21,16 @@ const appStore = useAppStore()
|
|||||||
const permissionStore = usePermissionStore()
|
const permissionStore = usePermissionStore()
|
||||||
const settingsStore = useSettingsStore()
|
const settingsStore = useSettingsStore()
|
||||||
|
|
||||||
const activeMenu = computed(() => {
|
const activeMenu = computed(() => route.meta.activeMenu || route.path)
|
||||||
const {
|
|
||||||
meta: { activeMenu },
|
|
||||||
path
|
|
||||||
} = route
|
|
||||||
return activeMenu || path
|
|
||||||
})
|
|
||||||
const noHiddenRoutes = computed(() => permissionStore.routes.filter(item => !item.meta?.hidden))
|
const noHiddenRoutes = computed(() => permissionStore.routes.filter(item => !item.meta?.hidden))
|
||||||
const isCollapse = computed(() => !appStore.sidebar.opened)
|
const isCollapse = computed(() => !appStore.sidebar.opened)
|
||||||
const isLogo = computed(() => isLeft.value && settingsStore.showLogo)
|
const isLogo = computed(() => isLeft.value && settingsStore.showLogo)
|
||||||
const backgroundColor = computed(() => (isLeft.value ? v3SidebarMenuBgColor : undefined))
|
const backgroundColor = computed(() => (isLeft.value ? v3SidebarMenuBgColor : undefined))
|
||||||
const textColor = computed(() => (isLeft.value ? v3SidebarMenuTextColor : undefined))
|
const textColor = computed(() => (isLeft.value ? v3SidebarMenuTextColor : undefined))
|
||||||
const activeTextColor = computed(() => (isLeft.value ? v3SidebarMenuActiveTextColor : undefined))
|
const activeTextColor = computed(() => (isLeft.value ? v3SidebarMenuActiveTextColor : undefined))
|
||||||
const sidebarMenuItemHeight = computed(() => {
|
const sidebarMenuItemHeight = computed(() => !isTop.value ? "var(--v3-sidebar-menu-item-height)" : "var(--v3-navigationbar-height)")
|
||||||
return !isTop.value ? "var(--v3-sidebar-menu-item-height)" : "var(--v3-navigationbar-height)"
|
const sidebarMenuHoverBgColor = computed(() => !isTop.value ? "var(--v3-sidebar-menu-hover-bg-color)" : "transparent")
|
||||||
})
|
const tipLineWidth = computed(() => !isTop.value ? "2px" : "0px")
|
||||||
const sidebarMenuHoverBgColor = computed(() => {
|
|
||||||
return !isTop.value ? "var(--v3-sidebar-menu-hover-bg-color)" : "transparent"
|
|
||||||
})
|
|
||||||
const tipLineWidth = computed(() => {
|
|
||||||
return !isTop.value ? "2px" : "0px"
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -15,16 +15,20 @@ interface Props {
|
|||||||
const props = defineProps<Props>()
|
const props = defineProps<Props>()
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
|
||||||
const settingsStore = useSettingsStore()
|
const settingsStore = useSettingsStore()
|
||||||
|
|
||||||
const { listenerRouteChange } = useRouteListener()
|
const { listenerRouteChange } = useRouteListener()
|
||||||
|
|
||||||
/** 滚动条组件元素的引用 */
|
/** 滚动条组件元素的引用 */
|
||||||
const scrollbarRef = ref<InstanceType<typeof ElScrollbar>>()
|
const scrollbarRef = ref<InstanceType<typeof ElScrollbar>>()
|
||||||
|
|
||||||
/** 滚动条内容元素的引用 */
|
/** 滚动条内容元素的引用 */
|
||||||
const scrollbarContentRef = ref<HTMLDivElement>()
|
const scrollbarContentRef = ref<HTMLDivElement>()
|
||||||
|
|
||||||
/** 当前滚动条距离左边的距离 */
|
/** 当前滚动条距离左边的距离 */
|
||||||
let currentScrollLeft = 0
|
let currentScrollLeft = 0
|
||||||
|
|
||||||
/** 每次滚动距离 */
|
/** 每次滚动距离 */
|
||||||
const translateDistance = 200
|
const translateDistance = 200
|
||||||
|
|
||||||
|
@ -11,9 +11,13 @@ import { useRoute, useRouter } from "vue-router"
|
|||||||
import ScrollPane from "./ScrollPane.vue"
|
import ScrollPane from "./ScrollPane.vue"
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
|
||||||
const tagsViewStore = useTagsViewStore()
|
const tagsViewStore = useTagsViewStore()
|
||||||
|
|
||||||
const permissionStore = usePermissionStore()
|
const permissionStore = usePermissionStore()
|
||||||
|
|
||||||
const { listenerRouteChange } = useRouteListener()
|
const { listenerRouteChange } = useRouteListener()
|
||||||
|
|
||||||
/** 标签页组件元素的引用数组 */
|
/** 标签页组件元素的引用数组 */
|
||||||
@ -21,12 +25,16 @@ const tagRefs = ref<InstanceType<typeof RouterLink>[]>([])
|
|||||||
|
|
||||||
/** 右键菜单的状态 */
|
/** 右键菜单的状态 */
|
||||||
const visible = ref(false)
|
const visible = ref(false)
|
||||||
|
|
||||||
/** 右键菜单的 top 位置 */
|
/** 右键菜单的 top 位置 */
|
||||||
const top = ref(0)
|
const top = ref(0)
|
||||||
|
|
||||||
/** 右键菜单的 left 位置 */
|
/** 右键菜单的 left 位置 */
|
||||||
const left = ref(0)
|
const left = ref(0)
|
||||||
|
|
||||||
/** 当前正在右键操作的标签页 */
|
/** 当前正在右键操作的标签页 */
|
||||||
const selectedTag = ref<TagView>({})
|
const selectedTag = ref<TagView>({})
|
||||||
|
|
||||||
/** 固定的标签页 */
|
/** 固定的标签页 */
|
||||||
let affixTags: TagView[] = []
|
let affixTags: TagView[] = []
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ const MAX_MOBILE_WIDTH = 992
|
|||||||
* @name 浏览器宽度变化 Composable
|
* @name 浏览器宽度变化 Composable
|
||||||
* @description 根据浏览器宽度变化,变换 Layout 布局
|
* @description 根据浏览器宽度变化,变换 Layout 布局
|
||||||
*/
|
*/
|
||||||
export default () => {
|
export function useResize() {
|
||||||
const appStore = useAppStore()
|
const appStore = useAppStore()
|
||||||
const { listenerRouteChange } = useRouteListener()
|
const { listenerRouteChange } = useRouteListener()
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import { getCssVar, setCssVar } from "@/utils/css"
|
|||||||
import { storeToRefs } from "pinia"
|
import { storeToRefs } from "pinia"
|
||||||
import { watchEffect } from "vue"
|
import { watchEffect } from "vue"
|
||||||
import { RightPanel, Settings } from "./components"
|
import { RightPanel, Settings } from "./components"
|
||||||
import useResize from "./composables/useResize"
|
import { useResize } from "./composables/useResize"
|
||||||
import LeftMode from "./LeftMode.vue"
|
import LeftMode from "./LeftMode.vue"
|
||||||
import LeftTopMode from "./LeftTopMode.vue"
|
import LeftTopMode from "./LeftTopMode.vue"
|
||||||
import TopMode from "./TopMode.vue"
|
import TopMode from "./TopMode.vue"
|
||||||
|
@ -20,6 +20,7 @@ const app = createApp(App)
|
|||||||
|
|
||||||
// 加载插件
|
// 加载插件
|
||||||
loadPlugins(app)
|
loadPlugins(app)
|
||||||
|
|
||||||
// 加载自定义指令
|
// 加载自定义指令
|
||||||
loadDirectives(app)
|
loadDirectives(app)
|
||||||
|
|
||||||
|
@ -5,12 +5,14 @@ import ThemeSwitch from "@/components/ThemeSwitch/index.vue"
|
|||||||
import { getLoginCodeApi } from "@/http/login"
|
import { getLoginCodeApi } from "@/http/login"
|
||||||
import { useUserStore } from "@/pinia/stores/user"
|
import { useUserStore } from "@/pinia/stores/user"
|
||||||
import { Key, Loading, Lock, Picture, User } from "@element-plus/icons-vue"
|
import { Key, Loading, Lock, Picture, User } from "@element-plus/icons-vue"
|
||||||
|
import { ElMessage } from "element-plus"
|
||||||
import { reactive, ref } from "vue"
|
import { reactive, ref } from "vue"
|
||||||
import { useRouter } from "vue-router"
|
import { useRouter } from "vue-router"
|
||||||
import Owl from "./components/Owl.vue"
|
import Owl from "./components/Owl.vue"
|
||||||
import { useFocus } from "./composables/useFocus"
|
import { useFocus } from "./composables/useFocus"
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
const { isFocus, handleBlur, handleFocus } = useFocus()
|
const { isFocus, handleBlur, handleFocus } = useFocus()
|
||||||
|
|
||||||
/** 登录表单元素的引用 */
|
/** 登录表单元素的引用 */
|
||||||
@ -18,51 +20,57 @@ const loginFormRef = ref<FormInstance | null>(null)
|
|||||||
|
|
||||||
/** 登录按钮 Loading */
|
/** 登录按钮 Loading */
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
|
|
||||||
/** 验证码图片 URL */
|
/** 验证码图片 URL */
|
||||||
const codeUrl = ref("")
|
const codeUrl = ref("")
|
||||||
|
|
||||||
/** 登录表单数据 */
|
/** 登录表单数据 */
|
||||||
const loginFormData: LoginRequestData = reactive({
|
const loginFormData: LoginRequestData = reactive({
|
||||||
username: "admin",
|
username: "admin",
|
||||||
password: "12345678",
|
password: "12345678",
|
||||||
code: ""
|
code: ""
|
||||||
})
|
})
|
||||||
|
|
||||||
/** 登录表单校验规则 */
|
/** 登录表单校验规则 */
|
||||||
const loginFormRules: FormRules = {
|
const loginFormRules: FormRules = {
|
||||||
username: [{ required: true, message: "请输入用户名", trigger: "blur" }],
|
username: [
|
||||||
|
{ required: true, message: "请输入用户名", trigger: "blur" }
|
||||||
|
],
|
||||||
password: [
|
password: [
|
||||||
{ required: true, message: "请输入密码", trigger: "blur" },
|
{ required: true, message: "请输入密码", trigger: "blur" },
|
||||||
{ min: 8, max: 16, message: "长度在 8 到 16 个字符", trigger: "blur" }
|
{ min: 8, max: 16, message: "长度在 8 到 16 个字符", trigger: "blur" }
|
||||||
],
|
],
|
||||||
code: [{ required: true, message: "请输入验证码", trigger: "blur" }]
|
code: [
|
||||||
|
{ required: true, message: "请输入验证码", trigger: "blur" }
|
||||||
|
]
|
||||||
}
|
}
|
||||||
/** 登录逻辑 */
|
|
||||||
|
/** 登录 */
|
||||||
function handleLogin() {
|
function handleLogin() {
|
||||||
loginFormRef.value?.validate((valid: boolean, fields) => {
|
loginFormRef.value?.validate((valid) => {
|
||||||
if (valid) {
|
if (!valid) {
|
||||||
|
ElMessage.error("表单校验不通过")
|
||||||
|
return
|
||||||
|
}
|
||||||
loading.value = true
|
loading.value = true
|
||||||
useUserStore()
|
useUserStore().login(loginFormData).then(() => {
|
||||||
.login(loginFormData)
|
|
||||||
.then(() => {
|
|
||||||
router.push({ path: "/" })
|
router.push({ path: "/" })
|
||||||
})
|
}).catch(() => {
|
||||||
.catch(() => {
|
|
||||||
createCode()
|
createCode()
|
||||||
loginFormData.password = ""
|
loginFormData.password = ""
|
||||||
})
|
}).finally(() => {
|
||||||
.finally(() => {
|
|
||||||
loading.value = false
|
loading.value = false
|
||||||
})
|
})
|
||||||
} else {
|
|
||||||
console.error("表单校验不通过", fields)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 创建验证码 */
|
/** 创建验证码 */
|
||||||
function createCode() {
|
function createCode() {
|
||||||
// 先清空验证码的输入
|
// 清空已输入的验证码
|
||||||
loginFormData.code = ""
|
loginFormData.code = ""
|
||||||
// 获取验证码
|
// 清空验证图片
|
||||||
codeUrl.value = ""
|
codeUrl.value = ""
|
||||||
|
// 获取验证码图片
|
||||||
getLoginCodeApi().then((res) => {
|
getLoginCodeApi().then((res) => {
|
||||||
codeUrl.value = res.data
|
codeUrl.value = res.data
|
||||||
})
|
})
|
||||||
|
@ -3,7 +3,9 @@ import { useUserStore } from "@/pinia/stores/user"
|
|||||||
import { ref, watch } from "vue"
|
import { ref, watch } from "vue"
|
||||||
|
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
|
|
||||||
const switchRoles = ref(userStore.roles[0])
|
const switchRoles = ref(userStore.roles[0])
|
||||||
|
|
||||||
watch(switchRoles, (value) => {
|
watch(switchRoles, (value) => {
|
||||||
userStore.changeRoles(value)
|
userStore.changeRoles(value)
|
||||||
})
|
})
|
||||||
|
@ -30,17 +30,18 @@ const formRules: FormRules<CreateOrUpdateTableRequestData> = {
|
|||||||
password: [{ required: true, trigger: "blur", message: "请输入密码" }]
|
password: [{ required: true, trigger: "blur", message: "请输入密码" }]
|
||||||
}
|
}
|
||||||
function handleCreateOrUpdate() {
|
function handleCreateOrUpdate() {
|
||||||
formRef.value?.validate((valid: boolean, fields) => {
|
formRef.value?.validate((valid) => {
|
||||||
if (!valid) return console.error("表单校验不通过", fields)
|
if (!valid) {
|
||||||
|
ElMessage.error("表单校验不通过")
|
||||||
|
return
|
||||||
|
}
|
||||||
loading.value = true
|
loading.value = true
|
||||||
const api = formData.value.id === undefined ? createTableDataApi : updateTableDataApi
|
const api = formData.value.id === undefined ? createTableDataApi : updateTableDataApi
|
||||||
api(formData.value)
|
api(formData.value).then(() => {
|
||||||
.then(() => {
|
|
||||||
ElMessage.success("操作成功")
|
ElMessage.success("操作成功")
|
||||||
dialogVisible.value = false
|
dialogVisible.value = false
|
||||||
getTableData()
|
getTableData()
|
||||||
})
|
}).finally(() => {
|
||||||
.finally(() => {
|
|
||||||
loading.value = false
|
loading.value = false
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -87,15 +88,12 @@ function getTableData() {
|
|||||||
size: paginationData.pageSize,
|
size: paginationData.pageSize,
|
||||||
username: searchData.username || undefined,
|
username: searchData.username || undefined,
|
||||||
phone: searchData.phone || undefined
|
phone: searchData.phone || undefined
|
||||||
})
|
}).then(({ data }) => {
|
||||||
.then(({ data }) => {
|
|
||||||
paginationData.total = data.total
|
paginationData.total = data.total
|
||||||
tableData.value = data.list
|
tableData.value = data.list
|
||||||
})
|
}).catch(() => {
|
||||||
.catch(() => {
|
|
||||||
tableData.value = []
|
tableData.value = []
|
||||||
})
|
}).finally(() => {
|
||||||
.finally(() => {
|
|
||||||
loading.value = false
|
loading.value = false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -20,13 +20,16 @@ export const useAppStore = defineStore("app", () => {
|
|||||||
opened: getSidebarStatus() !== SIDEBAR_CLOSED,
|
opened: getSidebarStatus() !== SIDEBAR_CLOSED,
|
||||||
withoutAnimation: false
|
withoutAnimation: false
|
||||||
})
|
})
|
||||||
|
|
||||||
// 设备类型
|
// 设备类型
|
||||||
const device = ref<DeviceEnum>(DeviceEnum.Desktop)
|
const device = ref<DeviceEnum>(DeviceEnum.Desktop)
|
||||||
|
|
||||||
// 监听侧边栏 opened 状态
|
// 监听侧边栏 opened 状态
|
||||||
watch(
|
watch(
|
||||||
() => sidebar.opened,
|
() => sidebar.opened,
|
||||||
opened => handleSidebarStatus(opened)
|
(opened) => {
|
||||||
|
handleSidebarStatus(opened)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// 切换侧边栏
|
// 切换侧边栏
|
||||||
@ -34,11 +37,13 @@ export const useAppStore = defineStore("app", () => {
|
|||||||
sidebar.opened = !sidebar.opened
|
sidebar.opened = !sidebar.opened
|
||||||
sidebar.withoutAnimation = withoutAnimation
|
sidebar.withoutAnimation = withoutAnimation
|
||||||
}
|
}
|
||||||
|
|
||||||
// 关闭侧边栏
|
// 关闭侧边栏
|
||||||
const closeSidebar = (withoutAnimation: boolean) => {
|
const closeSidebar = (withoutAnimation: boolean) => {
|
||||||
sidebar.opened = false
|
sidebar.opened = false
|
||||||
sidebar.withoutAnimation = withoutAnimation
|
sidebar.withoutAnimation = withoutAnimation
|
||||||
}
|
}
|
||||||
|
|
||||||
// 切换设备类型
|
// 切换设备类型
|
||||||
const toggleDevice = (value: DeviceEnum) => {
|
const toggleDevice = (value: DeviceEnum) => {
|
||||||
device.value = value
|
device.value = value
|
||||||
|
@ -28,6 +28,7 @@ function filterDynamicRoutes(routes: RouteRecordRaw[], roles: string[]) {
|
|||||||
export const usePermissionStore = defineStore("permission", () => {
|
export const usePermissionStore = defineStore("permission", () => {
|
||||||
// 可访问的路由
|
// 可访问的路由
|
||||||
const routes = ref<RouteRecordRaw[]>([])
|
const routes = ref<RouteRecordRaw[]>([])
|
||||||
|
|
||||||
// 有访问权限的动态路由
|
// 有访问权限的动态路由
|
||||||
const addRoutes = ref<RouteRecordRaw[]>([])
|
const addRoutes = ref<RouteRecordRaw[]>([])
|
||||||
|
|
||||||
|
@ -34,20 +34,26 @@ export const useTagsViewStore = defineStore("tags-view", () => {
|
|||||||
const addCachedView = (view: TagView) => {
|
const addCachedView = (view: TagView) => {
|
||||||
if (typeof view.name !== "string") return
|
if (typeof view.name !== "string") return
|
||||||
if (cachedViews.value.includes(view.name)) return
|
if (cachedViews.value.includes(view.name)) return
|
||||||
if (view.meta?.keepAlive) cachedViews.value.push(view.name)
|
if (view.meta?.keepAlive) {
|
||||||
|
cachedViews.value.push(view.name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// #endregion
|
// #endregion
|
||||||
|
|
||||||
// #region del
|
// #region del
|
||||||
const delVisitedView = (view: TagView) => {
|
const delVisitedView = (view: TagView) => {
|
||||||
const index = visitedViews.value.findIndex(v => v.path === view.path)
|
const index = visitedViews.value.findIndex(v => v.path === view.path)
|
||||||
if (index !== -1) visitedViews.value.splice(index, 1)
|
if (index !== -1) {
|
||||||
|
visitedViews.value.splice(index, 1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const delCachedView = (view: TagView) => {
|
const delCachedView = (view: TagView) => {
|
||||||
if (typeof view.name !== "string") return
|
if (typeof view.name !== "string") return
|
||||||
const index = cachedViews.value.indexOf(view.name)
|
const index = cachedViews.value.indexOf(view.name)
|
||||||
if (index !== -1) cachedViews.value.splice(index, 1)
|
if (index !== -1) {
|
||||||
|
cachedViews.value.splice(index, 1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// #endregion
|
// #endregion
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ export const useUserStore = defineStore("user", () => {
|
|||||||
setToken(data.token)
|
setToken(data.token)
|
||||||
token.value = data.token
|
token.value = data.token
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取用户详情
|
// 获取用户详情
|
||||||
const getInfo = async () => {
|
const getInfo = async () => {
|
||||||
const { data } = await getUserInfoApi()
|
const { data } = await getUserInfoApi()
|
||||||
@ -30,6 +31,7 @@ export const useUserStore = defineStore("user", () => {
|
|||||||
// 验证返回的 roles 是否为一个非空数组,否则塞入一个没有任何作用的默认角色,防止路由守卫逻辑进入无限循环
|
// 验证返回的 roles 是否为一个非空数组,否则塞入一个没有任何作用的默认角色,防止路由守卫逻辑进入无限循环
|
||||||
roles.value = data.roles?.length > 0 ? data.roles : routeSettings.defaultRoles
|
roles.value = data.roles?.length > 0 ? data.roles : routeSettings.defaultRoles
|
||||||
}
|
}
|
||||||
|
|
||||||
// 模拟角色变化
|
// 模拟角色变化
|
||||||
const changeRoles = async (role: string) => {
|
const changeRoles = async (role: string) => {
|
||||||
const newToken = `token-${role}`
|
const newToken = `token-${role}`
|
||||||
@ -38,6 +40,7 @@ export const useUserStore = defineStore("user", () => {
|
|||||||
// 用刷新页面代替重新登录
|
// 用刷新页面代替重新登录
|
||||||
window.location.reload()
|
window.location.reload()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 登出
|
// 登出
|
||||||
const logout = () => {
|
const logout = () => {
|
||||||
removeToken()
|
removeToken()
|
||||||
@ -46,12 +49,14 @@ export const useUserStore = defineStore("user", () => {
|
|||||||
resetRouter()
|
resetRouter()
|
||||||
_resetTagsView()
|
_resetTagsView()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 重置 Token
|
// 重置 Token
|
||||||
const resetToken = () => {
|
const resetToken = () => {
|
||||||
removeToken()
|
removeToken()
|
||||||
token.value = ""
|
token.value = ""
|
||||||
roles.value = []
|
roles.value = []
|
||||||
}
|
}
|
||||||
|
|
||||||
// 重置 Visited Views 和 Cached Views
|
// 重置 Visited Views 和 Cached Views
|
||||||
const _resetTagsView = () => {
|
const _resetTagsView = () => {
|
||||||
if (!settingsStore.cacheTagsView) {
|
if (!settingsStore.cacheTagsView) {
|
||||||
|
@ -20,10 +20,8 @@ export function flatMultiLevelRoutes(routes: RouteRecordRaw[]) {
|
|||||||
/** 判断路由层级是否大于 2 */
|
/** 判断路由层级是否大于 2 */
|
||||||
function isMultipleRoute(route: RouteRecordRaw) {
|
function isMultipleRoute(route: RouteRecordRaw) {
|
||||||
const children = route.children
|
const children = route.children
|
||||||
if (children?.length) {
|
|
||||||
// 只要有一个子路由的 children 长度大于 0,就说明是三级及其以上路由
|
// 只要有一个子路由的 children 长度大于 0,就说明是三级及其以上路由
|
||||||
return children.some(child => child.children?.length)
|
if (children?.length) return children.some(child => child.children?.length)
|
||||||
}
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,9 +26,7 @@ router.beforeEach(async (to, _from, next) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 如果已经登录,并准备进入 Login 页面,则重定向到主页
|
// 如果已经登录,并准备进入 Login 页面,则重定向到主页
|
||||||
if (to.path === "/login") {
|
if (to.path === "/login") return next({ path: "/" })
|
||||||
return next({ path: "/" })
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果用户已经获得其权限角色
|
// 如果用户已经获得其权限角色
|
||||||
if (userStore.roles.length !== 0) return next()
|
if (userStore.roles.length !== 0) return next()
|
||||||
@ -47,7 +45,7 @@ router.beforeEach(async (to, _from, next) => {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
// 过程中发生任何错误,都直接重置 Token,并重定向到登录页面
|
// 过程中发生任何错误,都直接重置 Token,并重定向到登录页面
|
||||||
userStore.resetToken()
|
userStore.resetToken()
|
||||||
ElMessage.error((error as Error).message || "路由守卫过程发生错误")
|
ElMessage.error((error as Error).message || "路由守卫发生错误")
|
||||||
next("/login")
|
next("/login")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
2
src/utils/cache/cookies.ts
vendored
2
src/utils/cache/cookies.ts
vendored
@ -6,9 +6,11 @@ import Cookies from "js-cookie"
|
|||||||
export function getToken() {
|
export function getToken() {
|
||||||
return Cookies.get(CacheKey.TOKEN)
|
return Cookies.get(CacheKey.TOKEN)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setToken(token: string) {
|
export function setToken(token: string) {
|
||||||
Cookies.set(CacheKey.TOKEN, token)
|
Cookies.set(CacheKey.TOKEN, token)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function removeToken() {
|
export function removeToken() {
|
||||||
Cookies.remove(CacheKey.TOKEN)
|
Cookies.remove(CacheKey.TOKEN)
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/** 获取指定元素(默认全局)上的 CSS 变量的值 */
|
/** 获取指定元素(默认全局)上的 CSS 变量的值 */
|
||||||
export function getCssVar(varName: string, element: HTMLElement = document.documentElement) {
|
export function getCssVar(varName: string, element: HTMLElement = document.documentElement) {
|
||||||
if (!varName?.startsWith("--")) {
|
if (!varName?.startsWith("--")) {
|
||||||
console.warn("CSS 变量名应以 '--' 开头")
|
console.error("CSS 变量名应以 '--' 开头")
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
// 没有拿到值时,会返回空串
|
// 没有拿到值时,会返回空串
|
||||||
@ -11,7 +11,7 @@ export function getCssVar(varName: string, element: HTMLElement = document.docum
|
|||||||
/** 设置指定元素(默认全局)上的 CSS 变量的值 */
|
/** 设置指定元素(默认全局)上的 CSS 变量的值 */
|
||||||
export function setCssVar(varName: string, value: string, element: HTMLElement = document.documentElement) {
|
export function setCssVar(varName: string, value: string, element: HTMLElement = document.documentElement) {
|
||||||
if (!varName?.startsWith("--")) {
|
if (!varName?.startsWith("--")) {
|
||||||
console.warn("CSS 变量名应以 '--' 开头")
|
console.error("CSS 变量名应以 '--' 开头")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
element.style.setProperty(varName, value)
|
element.style.setProperty(varName, value)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user