docs: 统一注释风格 (允许顶层变量采用 /** 内层变量采用默认的 //)
This commit is contained in:
parent
0b517855b6
commit
23ab6b7ab5
@ -6,6 +6,7 @@ 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)
|
||||||
|
|
||||||
|
/** 设备类型 Composable */
|
||||||
export function useDevice() {
|
export function useDevice() {
|
||||||
return { isMobile, isDesktop }
|
return { isMobile, isDesktop }
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ interface FetchSelectProps {
|
|||||||
api: () => Promise<ApiData>
|
api: () => Promise<ApiData>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 下拉选择器 Composable */
|
||||||
export function useFetchSelect(props: FetchSelectProps) {
|
export function useFetchSelect(props: FetchSelectProps) {
|
||||||
const { api } = props
|
const { api } = props
|
||||||
|
|
||||||
@ -24,7 +25,7 @@ export function useFetchSelect(props: FetchSelectProps) {
|
|||||||
const options = ref<SelectOption[]>([])
|
const options = ref<SelectOption[]>([])
|
||||||
const value = ref<OptionValue>("")
|
const value = ref<OptionValue>("")
|
||||||
|
|
||||||
/** 调用接口获取数据 */
|
// 调用接口获取数据
|
||||||
const loadData = () => {
|
const loadData = () => {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
options.value = []
|
options.value = []
|
||||||
|
@ -18,7 +18,8 @@ const DEFAULT_OPTIONS = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 传入一个函数 fn,在它执行周期内,加上「全屏」Loading
|
* @name 全屏加载 Composable
|
||||||
|
* @description 传入一个函数 fn,在它执行周期内,加上「全屏」Loading
|
||||||
* @param fn 要执行的函数
|
* @param fn 要执行的函数
|
||||||
* @param options LoadingOptions
|
* @param options LoadingOptions
|
||||||
* @returns 返回一个新的函数,该函数返回一个 Promise
|
* @returns 返回一个新的函数,该函数返回一个 Promise
|
||||||
|
@ -11,6 +11,7 @@ function setLayoutMode(mode: LayoutModeEnum) {
|
|||||||
settingsStore.layoutMode = mode
|
settingsStore.layoutMode = mode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 布局模式 Composable */
|
||||||
export function useLayoutMode() {
|
export function useLayoutMode() {
|
||||||
return { isLeft, isTop, isLeftTop, setLayoutMode }
|
return { isLeft, isTop, isLeftTop, setLayoutMode }
|
||||||
}
|
}
|
||||||
|
@ -17,14 +17,15 @@ const DEFAULT_PAGINATION_DATA = {
|
|||||||
layout: "total, sizes, prev, pager, next, jumper"
|
layout: "total, sizes, prev, pager, next, jumper"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 分页 Composable */
|
||||||
export function usePagination(initPaginationData: PaginationData = {}) {
|
export function usePagination(initPaginationData: PaginationData = {}) {
|
||||||
/** 合并分页参数 */
|
// 合并分页参数
|
||||||
const paginationData = reactive({ ...DEFAULT_PAGINATION_DATA, ...initPaginationData })
|
const paginationData = reactive({ ...DEFAULT_PAGINATION_DATA, ...initPaginationData })
|
||||||
/** 改变当前页码 */
|
// 改变当前页码
|
||||||
const handleCurrentChange = (value: number) => {
|
const handleCurrentChange = (value: number) => {
|
||||||
paginationData.currentPage = value
|
paginationData.currentPage = value
|
||||||
}
|
}
|
||||||
/** 改变页面大小 */
|
// 改变每页显示条数
|
||||||
const handleSizeChange = (value: number) => {
|
const handleSizeChange = (value: number) => {
|
||||||
paginationData.pageSize = value
|
paginationData.pageSize = value
|
||||||
}
|
}
|
||||||
|
@ -17,12 +17,16 @@ export function setRouteChange(to: RouteLocationNormalized) {
|
|||||||
latestRoute = to
|
latestRoute = to
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 单独监听路由会浪费渲染性能,使用发布订阅模式去进行分发管理 */
|
/**
|
||||||
|
* 订阅路由变化 Composable
|
||||||
|
* 1. 单独用 watch 监听路由会浪费渲染性能
|
||||||
|
* 2. 可优先选择使用该发布订阅模式去进行分发管理
|
||||||
|
*/
|
||||||
export function useRouteListener() {
|
export function useRouteListener() {
|
||||||
// 回调函数集合
|
// 回调函数集合
|
||||||
const callbackList: Callback[] = []
|
const callbackList: Callback[] = []
|
||||||
|
|
||||||
/** 监听路由变化(可以选择立即执行) */
|
// 监听路由变化(可以选择立即执行)
|
||||||
const listenerRouteChange = (callback: Callback, immediate = false) => {
|
const listenerRouteChange = (callback: Callback, immediate = false) => {
|
||||||
// 缓存回调函数
|
// 缓存回调函数
|
||||||
callbackList.push(callback)
|
callbackList.push(callback)
|
||||||
@ -32,12 +36,12 @@ export function useRouteListener() {
|
|||||||
immediate && latestRoute && callback(latestRoute)
|
immediate && latestRoute && callback(latestRoute)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 移除路由变化事件监听器 */
|
// 移除路由变化事件监听器
|
||||||
const removeRouteListener = (callback: Callback) => {
|
const removeRouteListener = (callback: Callback) => {
|
||||||
emitter.off(key, callback as Handler)
|
emitter.off(key, callback as Handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 组件销毁前移除监听器 */
|
// 组件销毁前移除监听器
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
for (let i = 0; i < callbackList.length; i++) {
|
for (let i = 0; i < callbackList.length; i++) {
|
||||||
removeRouteListener(callbackList[i])
|
removeRouteListener(callbackList[i])
|
||||||
|
@ -18,6 +18,7 @@ watch(dynamicTitle, (value, oldValue) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/** 标题 Composable */
|
||||||
export function useTitle() {
|
export function useTitle() {
|
||||||
return { setTitle }
|
return { setTitle }
|
||||||
}
|
}
|
||||||
|
@ -34,25 +34,25 @@ const DEFAULT_CONFIG = {
|
|||||||
const bodyEl = ref<HTMLElement>(document.body)
|
const bodyEl = ref<HTMLElement>(document.body)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建水印
|
* 水印 Composable
|
||||||
* 1. 可以选择传入挂载水印的容器元素,默认是 body
|
* 1. 可以选择传入挂载水印的容器元素,默认是 body
|
||||||
* 2. 做了水印防御,能有效防御别人打开控制台删除或隐藏水印
|
* 2. 做了水印防御,能有效防御别人打开控制台删除或隐藏水印
|
||||||
*/
|
*/
|
||||||
export function useWatermark(parentEl: Ref<HTMLElement | null> = bodyEl) {
|
export function useWatermark(parentEl: Ref<HTMLElement | null> = bodyEl) {
|
||||||
/** 备份文本 */
|
// 备份文本
|
||||||
let backupText: string
|
let backupText: string
|
||||||
/** 最终配置 */
|
// 最终配置
|
||||||
let mergeConfig: DefaultConfig
|
let mergeConfig: DefaultConfig
|
||||||
/** 水印元素 */
|
// 水印元素
|
||||||
let watermarkEl: HTMLElement | null = null
|
let watermarkEl: HTMLElement | null = null
|
||||||
/** 观察器 */
|
// 观察器
|
||||||
const observer: Observer = {
|
const observer: Observer = {
|
||||||
watermarkElMutationObserver: undefined,
|
watermarkElMutationObserver: undefined,
|
||||||
parentElMutationObserver: undefined,
|
parentElMutationObserver: undefined,
|
||||||
parentElResizeObserver: undefined
|
parentElResizeObserver: undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 设置水印 */
|
// 设置水印
|
||||||
const setWatermark = (text: string, config: Partial<DefaultConfig> = {}) => {
|
const setWatermark = (text: string, config: Partial<DefaultConfig> = {}) => {
|
||||||
if (!parentEl.value) return console.warn("请在 DOM 挂载完成后再调用 setWatermark 方法设置水印")
|
if (!parentEl.value) return console.warn("请在 DOM 挂载完成后再调用 setWatermark 方法设置水印")
|
||||||
// 备份文本
|
// 备份文本
|
||||||
@ -65,7 +65,7 @@ export function useWatermark(parentEl: Ref<HTMLElement | null> = bodyEl) {
|
|||||||
addElListener(parentEl.value)
|
addElListener(parentEl.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 创建水印元素 */
|
// 创建水印元素
|
||||||
const createWatermarkEl = () => {
|
const createWatermarkEl = () => {
|
||||||
const isBody = parentEl.value!.tagName.toLowerCase() === bodyEl.value.tagName.toLowerCase()
|
const isBody = parentEl.value!.tagName.toLowerCase() === bodyEl.value.tagName.toLowerCase()
|
||||||
const watermarkElPosition = isBody ? "fixed" : "absolute"
|
const watermarkElPosition = isBody ? "fixed" : "absolute"
|
||||||
@ -84,7 +84,7 @@ export function useWatermark(parentEl: Ref<HTMLElement | null> = bodyEl) {
|
|||||||
parentEl.value!.appendChild(watermarkEl)
|
parentEl.value!.appendChild(watermarkEl)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 更新水印元素 */
|
// 更新水印元素
|
||||||
const updateWatermarkEl = (
|
const updateWatermarkEl = (
|
||||||
options: Partial<{
|
options: Partial<{
|
||||||
width: number
|
width: number
|
||||||
@ -97,7 +97,7 @@ export function useWatermark(parentEl: Ref<HTMLElement | null> = bodyEl) {
|
|||||||
options.height && (watermarkEl.style.height = `${options.height}px`)
|
options.height && (watermarkEl.style.height = `${options.height}px`)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 创建 base64 图片 */
|
// 创建 base64 图片
|
||||||
const createBase64 = () => {
|
const createBase64 = () => {
|
||||||
const { color, opacity, size, family, angle, width, height } = mergeConfig
|
const { color, opacity, size, family, angle, width, height } = mergeConfig
|
||||||
const canvasEl = document.createElement("canvas")
|
const canvasEl = document.createElement("canvas")
|
||||||
@ -114,7 +114,7 @@ export function useWatermark(parentEl: Ref<HTMLElement | null> = bodyEl) {
|
|||||||
return canvasEl.toDataURL()
|
return canvasEl.toDataURL()
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 清除水印 */
|
// 清除水印
|
||||||
const clearWatermark = () => {
|
const clearWatermark = () => {
|
||||||
if (!parentEl.value || !watermarkEl) return
|
if (!parentEl.value || !watermarkEl) return
|
||||||
// 移除对水印元素和容器元素的监听
|
// 移除对水印元素和容器元素的监听
|
||||||
@ -130,14 +130,14 @@ export function useWatermark(parentEl: Ref<HTMLElement | null> = bodyEl) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 刷新水印(防御时调用) */
|
// 刷新水印(防御时调用)
|
||||||
const updateWatermark = debounce(() => {
|
const updateWatermark = debounce(() => {
|
||||||
clearWatermark()
|
clearWatermark()
|
||||||
createWatermarkEl()
|
createWatermarkEl()
|
||||||
addElListener(parentEl.value!)
|
addElListener(parentEl.value!)
|
||||||
}, 100)
|
}, 100)
|
||||||
|
|
||||||
/** 监听水印元素和容器元素的变化(DOM 变化 & DOM 大小变化) */
|
// 监听水印元素和容器元素的变化(DOM 变化 & DOM 大小变化)
|
||||||
const addElListener = (targetNode: HTMLElement) => {
|
const addElListener = (targetNode: HTMLElement) => {
|
||||||
// 判断是否开启防御
|
// 判断是否开启防御
|
||||||
if (mergeConfig.defense) {
|
if (mergeConfig.defense) {
|
||||||
@ -157,7 +157,7 @@ export function useWatermark(parentEl: Ref<HTMLElement | null> = bodyEl) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 移除对水印元素和容器元素的监听,传参可指定要移除哪个监听,不传默认移除全部监听 */
|
// 移除对水印元素和容器元素的监听,传参可指定要移除哪个监听,不传默认移除全部监听
|
||||||
const removeListener = (kind: "mutation" | "resize" | "all" = "all") => {
|
const removeListener = (kind: "mutation" | "resize" | "all" = "all") => {
|
||||||
// 移除 mutation 监听
|
// 移除 mutation 监听
|
||||||
if (kind === "mutation" || kind === "all") {
|
if (kind === "mutation" || kind === "all") {
|
||||||
@ -173,7 +173,7 @@ export function useWatermark(parentEl: Ref<HTMLElement | null> = bodyEl) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 监听 DOM 变化 */
|
// 监听 DOM 变化
|
||||||
const addMutationListener = (targetNode: HTMLElement) => {
|
const addMutationListener = (targetNode: HTMLElement) => {
|
||||||
// 当观察到变动时执行的回调
|
// 当观察到变动时执行的回调
|
||||||
const mutationCallback = debounce((mutationList: MutationRecord[]) => {
|
const mutationCallback = debounce((mutationList: MutationRecord[]) => {
|
||||||
@ -212,7 +212,7 @@ export function useWatermark(parentEl: Ref<HTMLElement | null> = bodyEl) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 监听 DOM 大小变化 */
|
// 监听 DOM 大小变化
|
||||||
const addResizeListener = (targetNode: HTMLElement) => {
|
const addResizeListener = (targetNode: HTMLElement) => {
|
||||||
// 当 targetNode 元素大小变化时去更新整个水印的大小
|
// 当 targetNode 元素大小变化时去更新整个水印的大小
|
||||||
const resizeCallback = debounce(() => {
|
const resizeCallback = debounce(() => {
|
||||||
|
@ -33,7 +33,7 @@ function handleLink(item: RouteLocationMatched) {
|
|||||||
router.push(pathCompile(path))
|
router.push(pathCompile(path))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 监听路由变化,更新面包屑导航信息 */
|
// 监听路由变化,更新面包屑导航信息
|
||||||
listenerRouteChange((route) => {
|
listenerRouteChange((route) => {
|
||||||
if (route.path.startsWith("/redirect/")) return
|
if (route.path.startsWith("/redirect/")) return
|
||||||
getBreadcrumb()
|
getBreadcrumb()
|
||||||
|
@ -44,11 +44,11 @@ function wheelScroll({ deltaY }: WheelEvent) {
|
|||||||
|
|
||||||
/** 获取可能需要的宽度 */
|
/** 获取可能需要的宽度 */
|
||||||
function getWidth() {
|
function getWidth() {
|
||||||
/** 可滚动内容的长度 */
|
// 可滚动内容的长度
|
||||||
const scrollbarContentRefWidth = scrollbarContentRef.value!.clientWidth
|
const scrollbarContentRefWidth = scrollbarContentRef.value!.clientWidth
|
||||||
/** 滚动可视区宽度 */
|
// 滚动可视区宽度
|
||||||
const scrollbarRefWidth = scrollbarRef.value!.wrapRef!.clientWidth
|
const scrollbarRefWidth = scrollbarRef.value!.wrapRef!.clientWidth
|
||||||
/** 最后剩余可滚动的宽度 */
|
// 最后剩余可滚动的宽度
|
||||||
const lastDistance = scrollbarContentRefWidth - scrollbarRefWidth - currentScrollLeft
|
const lastDistance = scrollbarContentRefWidth - scrollbarRefWidth - currentScrollLeft
|
||||||
|
|
||||||
return { scrollbarContentRefWidth, scrollbarRefWidth, lastDistance }
|
return { scrollbarContentRefWidth, scrollbarRefWidth, lastDistance }
|
||||||
@ -96,7 +96,7 @@ function moveTo() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 监听路由变化,移动到目标位置 */
|
// 监听路由变化,移动到目标位置
|
||||||
listenerRouteChange(() => {
|
listenerRouteChange(() => {
|
||||||
nextTick(moveTo)
|
nextTick(moveTo)
|
||||||
})
|
})
|
||||||
|
@ -6,18 +6,21 @@ import { onBeforeMount, onBeforeUnmount, onMounted } from "vue"
|
|||||||
/** 参考 Bootstrap 的响应式设计将最大移动端宽度设置为 992 */
|
/** 参考 Bootstrap 的响应式设计将最大移动端宽度设置为 992 */
|
||||||
const MAX_MOBILE_WIDTH = 992
|
const MAX_MOBILE_WIDTH = 992
|
||||||
|
|
||||||
/** 根据浏览器宽度变化,变换 Layout 布局 */
|
/**
|
||||||
|
* @name 浏览器宽度变化 Composable
|
||||||
|
* @description 根据浏览器宽度变化,变换 Layout 布局
|
||||||
|
*/
|
||||||
export default () => {
|
export default () => {
|
||||||
const appStore = useAppStore()
|
const appStore = useAppStore()
|
||||||
const { listenerRouteChange } = useRouteListener()
|
const { listenerRouteChange } = useRouteListener()
|
||||||
|
|
||||||
/** 用于判断当前设备是否为移动端 */
|
// 用于判断当前设备是否为移动端
|
||||||
const _isMobile = () => {
|
const _isMobile = () => {
|
||||||
const rect = document.body.getBoundingClientRect()
|
const rect = document.body.getBoundingClientRect()
|
||||||
return rect.width - 1 < MAX_MOBILE_WIDTH
|
return rect.width - 1 < MAX_MOBILE_WIDTH
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 用于处理窗口大小变化事件 */
|
// 用于处理窗口大小变化事件
|
||||||
const _resizeHandler = () => {
|
const _resizeHandler = () => {
|
||||||
if (!document.hidden) {
|
if (!document.hidden) {
|
||||||
const isMobile = _isMobile()
|
const isMobile = _isMobile()
|
||||||
@ -25,19 +28,20 @@ export default () => {
|
|||||||
isMobile && appStore.closeSidebar(true)
|
isMobile && appStore.closeSidebar(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/** 监听路由变化,根据设备类型调整布局 */
|
|
||||||
|
// 监听路由变化,根据设备类型调整布局
|
||||||
listenerRouteChange(() => {
|
listenerRouteChange(() => {
|
||||||
if (appStore.device === DeviceEnum.Mobile && appStore.sidebar.opened) {
|
if (appStore.device === DeviceEnum.Mobile && appStore.sidebar.opened) {
|
||||||
appStore.closeSidebar(false)
|
appStore.closeSidebar(false)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
/** 在组件挂载前添加窗口大小变化事件监听器 */
|
// 在组件挂载前添加窗口大小变化事件监听器
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
window.addEventListener("resize", _resizeHandler)
|
window.addEventListener("resize", _resizeHandler)
|
||||||
})
|
})
|
||||||
|
|
||||||
/** 在组件挂载后根据窗口大小判断设备类型并调整布局 */
|
// 在组件挂载后根据窗口大小判断设备类型并调整布局
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (_isMobile()) {
|
if (_isMobile()) {
|
||||||
appStore.toggleDevice(DeviceEnum.Mobile)
|
appStore.toggleDevice(DeviceEnum.Mobile)
|
||||||
@ -45,7 +49,7 @@ export default () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
/** 在组件卸载前移除窗口大小变化事件监听器 */
|
// 在组件卸载前移除窗口大小变化事件监听器
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
window.removeEventListener("resize", _resizeHandler)
|
window.removeEventListener("resize", _resizeHandler)
|
||||||
})
|
})
|
||||||
|
@ -1,14 +1,16 @@
|
|||||||
import { ref } from "vue"
|
import { ref } from "vue"
|
||||||
|
|
||||||
|
/** 焦点 Composable */
|
||||||
export function useFocus() {
|
export function useFocus() {
|
||||||
/** 是否有焦点 */
|
// 是否有焦点
|
||||||
const isFocus = ref<boolean>(false)
|
const isFocus = ref<boolean>(false)
|
||||||
|
|
||||||
/** 失去焦点 */
|
// 失去焦点
|
||||||
const handleBlur = () => {
|
const handleBlur = () => {
|
||||||
isFocus.value = false
|
isFocus.value = false
|
||||||
}
|
}
|
||||||
/** 获取焦点 */
|
|
||||||
|
// 获取焦点
|
||||||
const handleFocus = () => {
|
const handleFocus = () => {
|
||||||
isFocus.value = true
|
isFocus.value = true
|
||||||
}
|
}
|
||||||
|
@ -15,12 +15,12 @@ function handleSidebarStatus(opened: boolean) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const useAppStore = defineStore("app", () => {
|
export const useAppStore = defineStore("app", () => {
|
||||||
/** 侧边栏状态 */
|
// 侧边栏状态
|
||||||
const sidebar: Sidebar = reactive({
|
const sidebar: Sidebar = reactive({
|
||||||
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 状态
|
||||||
@ -29,17 +29,17 @@ export const useAppStore = defineStore("app", () => {
|
|||||||
opened => handleSidebarStatus(opened)
|
opened => handleSidebarStatus(opened)
|
||||||
)
|
)
|
||||||
|
|
||||||
/** 切换侧边栏 */
|
// 切换侧边栏
|
||||||
const toggleSidebar = (withoutAnimation: boolean) => {
|
const toggleSidebar = (withoutAnimation: boolean) => {
|
||||||
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
|
||||||
}
|
}
|
||||||
@ -48,8 +48,8 @@ export const useAppStore = defineStore("app", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 在 SPA 应用中可用于在 pinia 实例被激活前使用 store
|
* @description 在 SPA 应用中可用于在 pinia 实例被激活前使用 store
|
||||||
* 在 SSR 应用中可用于在 setup 外使用 store
|
* @description 在 SSR 应用中可用于在 setup 外使用 store
|
||||||
*/
|
*/
|
||||||
export function useAppStoreOutside() {
|
export function useAppStoreOutside() {
|
||||||
return useAppStore(pinia)
|
return useAppStore(pinia)
|
||||||
|
@ -26,18 +26,18 @@ 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[]>([])
|
||||||
|
|
||||||
/** 根据角色生成可访问的 Routes(可访问的路由 = 常驻路由 + 有访问权限的动态路由) */
|
// 根据角色生成可访问的 Routes(可访问的路由 = 常驻路由 + 有访问权限的动态路由)
|
||||||
const setRoutes = (roles: string[]) => {
|
const setRoutes = (roles: string[]) => {
|
||||||
const accessedRoutes = filterDynamicRoutes(dynamicRoutes, roles)
|
const accessedRoutes = filterDynamicRoutes(dynamicRoutes, roles)
|
||||||
_set(accessedRoutes)
|
_set(accessedRoutes)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 所有路由 = 所有常驻路由 + 所有动态路由 */
|
// 所有路由 = 所有常驻路由 + 所有动态路由
|
||||||
const setAllRoutes = () => {
|
const setAllRoutes = () => {
|
||||||
_set(dynamicRoutes)
|
_set(dynamicRoutes)
|
||||||
}
|
}
|
||||||
@ -51,8 +51,8 @@ export const usePermissionStore = defineStore("permission", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 在 SPA 应用中可用于在 pinia 实例被激活前使用 store
|
* @description 在 SPA 应用中可用于在 pinia 实例被激活前使用 store
|
||||||
* 在 SSR 应用中可用于在 setup 外使用 store
|
* @description 在 SSR 应用中可用于在 setup 外使用 store
|
||||||
*/
|
*/
|
||||||
export function usePermissionStoreOutside() {
|
export function usePermissionStoreOutside() {
|
||||||
return usePermissionStore(pinia)
|
return usePermissionStore(pinia)
|
||||||
|
@ -14,7 +14,7 @@ type SettingsStore = {
|
|||||||
type SettingsStoreKey = keyof SettingsStore
|
type SettingsStoreKey = keyof SettingsStore
|
||||||
|
|
||||||
export const useSettingsStore = defineStore("settings", () => {
|
export const useSettingsStore = defineStore("settings", () => {
|
||||||
/** 状态对象 */
|
// 状态对象
|
||||||
const state = {} as SettingsStore
|
const state = {} as SettingsStore
|
||||||
// 遍历 layoutSettings 对象的键值对
|
// 遍历 layoutSettings 对象的键值对
|
||||||
for (const [key, value] of Object.entries(layoutSettings)) {
|
for (const [key, value] of Object.entries(layoutSettings)) {
|
||||||
@ -29,7 +29,7 @@ export const useSettingsStore = defineStore("settings", () => {
|
|||||||
setConfigLayout(settings)
|
setConfigLayout(settings)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/** 获取要缓存的数据:将 state 对象转化为 settings 对象 */
|
// 获取要缓存的数据:将 state 对象转化为 settings 对象
|
||||||
const _getCacheData = () => {
|
const _getCacheData = () => {
|
||||||
const settings = {} as LayoutSettings
|
const settings = {} as LayoutSettings
|
||||||
for (const [key, value] of Object.entries(state)) {
|
for (const [key, value] of Object.entries(state)) {
|
||||||
@ -43,8 +43,8 @@ export const useSettingsStore = defineStore("settings", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 在 SPA 应用中可用于在 pinia 实例被激活前使用 store
|
* @description 在 SPA 应用中可用于在 pinia 实例被激活前使用 store
|
||||||
* 在 SSR 应用中可用于在 setup 外使用 store
|
* @description 在 SSR 应用中可用于在 setup 外使用 store
|
||||||
*/
|
*/
|
||||||
export function useSettingsStoreOutside() {
|
export function useSettingsStoreOutside() {
|
||||||
return useSettingsStore(pinia)
|
return useSettingsStore(pinia)
|
||||||
|
@ -96,8 +96,8 @@ export const useTagsViewStore = defineStore("tags-view", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 在 SPA 应用中可用于在 pinia 实例被激活前使用 store
|
* @description 在 SPA 应用中可用于在 pinia 实例被激活前使用 store
|
||||||
* 在 SSR 应用中可用于在 setup 外使用 store
|
* @description 在 SSR 应用中可用于在 setup 外使用 store
|
||||||
*/
|
*/
|
||||||
export function useTagsViewStoreOutside() {
|
export function useTagsViewStoreOutside() {
|
||||||
return useTagsViewStore(pinia)
|
return useTagsViewStore(pinia)
|
||||||
|
@ -17,20 +17,20 @@ export const useUserStore = defineStore("user", () => {
|
|||||||
const tagsViewStore = useTagsViewStore()
|
const tagsViewStore = useTagsViewStore()
|
||||||
const settingsStore = useSettingsStore()
|
const settingsStore = useSettingsStore()
|
||||||
|
|
||||||
/** 登录 */
|
// 登录
|
||||||
const login = async ({ username, password, code }: LoginRequestData) => {
|
const login = async ({ username, password, code }: LoginRequestData) => {
|
||||||
const { data } = await loginApi({ username, password, code })
|
const { data } = await loginApi({ username, password, code })
|
||||||
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()
|
||||||
username.value = data.username
|
username.value = data.username
|
||||||
// 验证返回的 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}`
|
||||||
token.value = newToken
|
token.value = newToken
|
||||||
@ -38,7 +38,7 @@ export const useUserStore = defineStore("user", () => {
|
|||||||
// 用刷新页面代替重新登录
|
// 用刷新页面代替重新登录
|
||||||
window.location.reload()
|
window.location.reload()
|
||||||
}
|
}
|
||||||
/** 登出 */
|
// 登出
|
||||||
const logout = () => {
|
const logout = () => {
|
||||||
removeToken()
|
removeToken()
|
||||||
token.value = ""
|
token.value = ""
|
||||||
@ -46,13 +46,13 @@ 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) {
|
||||||
tagsViewStore.delAllVisitedViews()
|
tagsViewStore.delAllVisitedViews()
|
||||||
@ -64,8 +64,8 @@ export const useUserStore = defineStore("user", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 在 SPA 应用中可用于在 pinia 实例被激活前使用 store
|
* @description 在 SPA 应用中可用于在 pinia 实例被激活前使用 store
|
||||||
* 在 SSR 应用中可用于在 setup 外使用 store
|
* @description 在 SSR 应用中可用于在 setup 外使用 store
|
||||||
*/
|
*/
|
||||||
export function useUserStoreOutside() {
|
export function useUserStoreOutside() {
|
||||||
return useUserStore(pinia)
|
return useUserStore(pinia)
|
||||||
|
@ -6,8 +6,8 @@ import { flatMultiLevelRoutes, history } from "./helper"
|
|||||||
const Layouts = () => import("@/layouts/index.vue")
|
const Layouts = () => import("@/layouts/index.vue")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 常驻路由
|
* @name 常驻路由
|
||||||
* 除了 redirect/403/404/login 等隐藏页面,其他页面建议设置 Name 属性
|
* @description 除了 redirect/403/404/login 等隐藏页面,其他页面建议设置 Name 属性
|
||||||
*/
|
*/
|
||||||
export const constantRoutes: RouteRecordRaw[] = [
|
export const constantRoutes: RouteRecordRaw[] = [
|
||||||
{
|
{
|
||||||
@ -252,9 +252,9 @@ export const constantRoutes: RouteRecordRaw[] = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 动态路由
|
* @name 动态路由
|
||||||
* 用来放置有权限 (Roles 属性) 的路由
|
* @description 用来放置有权限 (Roles 属性) 的路由
|
||||||
* 必须带有 Name 属性
|
* @description 必须带有 Name 属性
|
||||||
*/
|
*/
|
||||||
export const dynamicRoutes: RouteRecordRaw[] = [
|
export const dynamicRoutes: RouteRecordRaw[] = [
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
// https://www.typescriptlang.org/tsconfig
|
/**
|
||||||
// https://cn.vuejs.org/guide/typescript/overview#configuring-tsconfig-json
|
* @link https://www.typescriptlang.org/tsconfig
|
||||||
// https://cn.vite.dev/guide/features#typescript-compiler-options
|
* @link https://cn.vuejs.org/guide/typescript/overview#configuring-tsconfig-json
|
||||||
|
* @link https://cn.vite.dev/guide/features#typescript-compiler-options
|
||||||
|
*/
|
||||||
|
|
||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
|
32
types/vue-router.d.ts
vendored
32
types/vue-router.d.ts
vendored
@ -5,49 +5,49 @@ export {}
|
|||||||
declare module "vue-router" {
|
declare module "vue-router" {
|
||||||
interface RouteMeta {
|
interface RouteMeta {
|
||||||
/**
|
/**
|
||||||
* 设置该路由在侧边栏和面包屑中展示的名字
|
* @description 设置该路由在侧边栏和面包屑中展示的名字
|
||||||
*/
|
*/
|
||||||
title?: string
|
title?: string
|
||||||
/**
|
/**
|
||||||
* 设置该路由的图标,记得将 svg 导入 @/assets/icons
|
* @description 设置该路由的图标,记得将 svg 导入 @/assets/icons
|
||||||
*/
|
*/
|
||||||
svgIcon?: string
|
svgIcon?: string
|
||||||
/**
|
/**
|
||||||
* 设置该路由的图标,直接使用 Element Plus 的 Icon(与 svgIcon 同时设置时,svgIcon 将优先生效)
|
* @description 设置该路由的图标,直接使用 Element Plus 的 Icon(与 svgIcon 同时设置时,svgIcon 将优先生效)
|
||||||
*/
|
*/
|
||||||
elIcon?: string
|
elIcon?: string
|
||||||
/**
|
/**
|
||||||
* 默认 false,设置 true 的时候该路由不会在侧边栏出现
|
* @description 默认 false,设置 true 的时候该路由不会在侧边栏出现
|
||||||
*/
|
*/
|
||||||
hidden?: boolean
|
hidden?: boolean
|
||||||
/**
|
/**
|
||||||
* 设置能进入该路由的角色,支持多个角色叠加
|
* @description 设置能进入该路由的角色,支持多个角色叠加
|
||||||
*/
|
*/
|
||||||
roles?: string[]
|
roles?: string[]
|
||||||
/**
|
/**
|
||||||
* 默认 true,如果设置为 false,则不会在面包屑中显示
|
* @description 默认 true,如果设置为 false,则不会在面包屑中显示
|
||||||
*/
|
*/
|
||||||
breadcrumb?: boolean
|
breadcrumb?: boolean
|
||||||
/**
|
/**
|
||||||
* 默认 false,如果设置为 true,它则会固定在 tags-view 中
|
* @description 默认 false,如果设置为 true,它则会固定在 tags-view 中
|
||||||
*/
|
*/
|
||||||
affix?: boolean
|
affix?: boolean
|
||||||
/**
|
/**
|
||||||
* 当一个路由下面的 children 声明的路由大于 1 个时,自动会变成嵌套的模式,
|
* @description 当一个路由下面的 children 声明的路由大于 1 个时,自动会变成嵌套的模式,
|
||||||
* 只有一个时,会将那个子路由当做根路由显示在侧边栏,
|
* @description 只有一个时,会将那个子路由当做根路由显示在侧边栏,
|
||||||
* 若想不管路由下面的 children 声明的个数都显示你的根路由,
|
* @description 若想不管路由下面的 children 声明的个数都显示你的根路由,
|
||||||
* 可以设置 alwaysShow: true,这样就会忽略之前定义的规则,一直显示根路由
|
* @description 可以设置 alwaysShow: true,这样就会忽略之前定义的规则,一直显示根路由
|
||||||
*/
|
*/
|
||||||
alwaysShow?: boolean
|
alwaysShow?: boolean
|
||||||
/**
|
/**
|
||||||
* 示例: activeMenu: "/xxx/xxx",
|
* @description 示例: activeMenu: "/xxx/xxx",
|
||||||
* 当设置了该属性进入路由时,则会高亮 activeMenu 属性对应的侧边栏。
|
* @description 当设置了该属性进入路由时,则会高亮 activeMenu 属性对应的侧边栏。
|
||||||
* 该属性适合使用在有 hidden: true 属性的路由上
|
* @description 该属性适合使用在有 hidden: true 属性的路由上
|
||||||
*/
|
*/
|
||||||
activeMenu?: string
|
activeMenu?: string
|
||||||
/**
|
/**
|
||||||
* 是否缓存该路由页面
|
* @description 是否缓存该路由页面
|
||||||
* 默认为 false,为 true 时代表需要缓存,此时该路由和该页面都需要设置一致的 Name
|
* @description 默认为 false,为 true 时代表需要缓存,此时该路由和该页面都需要设置一致的 Name
|
||||||
*/
|
*/
|
||||||
keepAlive?: boolean
|
keepAlive?: boolean
|
||||||
}
|
}
|
||||||
|
@ -54,9 +54,9 @@ export default defineConfig(({ mode }) => {
|
|||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
output: {
|
output: {
|
||||||
/**
|
/**
|
||||||
* 分块策略
|
* @name 分块策略
|
||||||
* 1. 注意这些包名必须存在,否则打包会报错
|
* @description 1. 注意这些包名必须存在,否则打包会报错
|
||||||
* 2. 如果你不想自定义 chunk 分割策略,可以直接移除这段配置
|
* @description 2. 如果你不想自定义 chunk 分割策略,可以直接移除这段配置
|
||||||
*/
|
*/
|
||||||
manualChunks: {
|
manualChunks: {
|
||||||
vue: ["vue", "vue-router", "pinia"],
|
vue: ["vue", "vue-router", "pinia"],
|
||||||
|
Loading…
x
Reference in New Issue
Block a user