diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ae9bfba..a154f7fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # CHANGE LOG +## 4.3.0 + +提供了专用于一些模板的 `hooks`,可以通过这些方法调用模板的特定功能。并且该功能后续是模板维护的重点。 + +改造 `pinia` 使用方式,统一使用 `xxxGetters`, `xxxActions` 去调用仓库数据与方法。 + +### Feats + +- 新增 `store/hooks` 包 +- 新增 `hooks/template` 包 + ## 4.2.9 主要更新了命名问题。并且使用单词检查器,扫描整个项目替换了拼写错误的单词。 diff --git a/src/app-components/app/AppLockScreen/components/LockScreen/index.tsx b/src/app-components/app/AppLockScreen/components/LockScreen/index.tsx index d208d0b9..d583938f 100644 --- a/src/app-components/app/AppLockScreen/components/LockScreen/index.tsx +++ b/src/app-components/app/AppLockScreen/components/LockScreen/index.tsx @@ -14,9 +14,9 @@ import { NInput, NForm, NFormItem, NButton, NSpace } from 'naive-ui' import AppAvatar from '@/app-components/app/AppAvatar/index' -import { useSetting } from '@/store' import useAppLockScreen from '@/app-components/app/AppLockScreen/appLockVar' import { rules, useCondition } from '@/app-components/app/AppLockScreen/hook' +import { useSettingGetters, useSettingActions } from '@/store' import type { FormInst, InputInst } from 'naive-ui' @@ -27,7 +27,7 @@ const LockScreen = defineComponent({ const inputInstRef = ref(null) const { setLockAppScreen } = useAppLockScreen() - const { changeSwitcher } = useSetting() + const { changeSwitcher } = useSettingActions() const state = reactive({ lockCondition: useCondition(), diff --git a/src/app-components/app/AppLockScreen/components/UnlockScreen/index.tsx b/src/app-components/app/AppLockScreen/components/UnlockScreen/index.tsx index 31cf66f0..9b23a573 100644 --- a/src/app-components/app/AppLockScreen/components/UnlockScreen/index.tsx +++ b/src/app-components/app/AppLockScreen/components/UnlockScreen/index.tsx @@ -15,7 +15,7 @@ import { NInput, NForm, NFormItem, NButton, NSpace } from 'naive-ui' import AppAvatar from '@/app-components/app/AppAvatar/index' import dayjs from 'dayjs' -import { useSetting, useSigning } from '@/store' +import { useSigningActions, useSettingActions } from '@/store' import { rules, useCondition } from '@/app-components/app/AppLockScreen/hook' import useAppLockScreen from '@/app-components/app/AppLockScreen/appLockVar' import { useDevice } from '@/hooks/web/index' @@ -28,8 +28,8 @@ export default defineComponent({ const formRef = ref(null) const inputInstRef = ref(null) - const { logout } = useSigning() - const { changeSwitcher } = useSetting() + const { logout } = useSigningActions() + const { changeSwitcher } = useSettingActions() const { setLockAppScreen } = useAppLockScreen() const { isTabletOrSmaller } = useDevice() diff --git a/src/app-components/app/AppLockScreen/index.tsx b/src/app-components/app/AppLockScreen/index.tsx index 9722cc26..b8941f6f 100644 --- a/src/app-components/app/AppLockScreen/index.tsx +++ b/src/app-components/app/AppLockScreen/index.tsx @@ -21,26 +21,25 @@ import { NModal } from 'naive-ui' import LockScreen from './components/LockScreen' import UnlockScreen from './components/UnlockScreen' -import { useSetting } from '@/store' import useAppLockScreen from '@/app-components/app/AppLockScreen/appLockVar' +import { useSettingGetters } from '@/store' const AppLockScreen = defineComponent({ name: 'AppLockScreen', setup() { - const settingStore = useSetting() - const { lockScreenSwitch } = storeToRefs(settingStore) + const { getLockScreenSwitch } = useSettingGetters() const { getLockAppScreen } = useAppLockScreen() return { - lockScreenSwitch, + getLockScreenSwitch, getLockAppScreen, } }, render() { return ( {this.avatarOptions.map((curr) => ( - + {{ trigger: () => ( settingStore.primaryColorOverride, - ) - const modelThemeValue = computed(() => - settingStore.themeValue ? darkTheme : null, - ) const localePackage = computed(() => { - const key = settingStore.localeLanguage + const key = getLocaleLanguage.value return naiveLocales(key) }) @@ -52,7 +47,7 @@ export default defineComponent({ ['message', 'dialog', 'notification', 'loadingBar'], { configProviderProps: computed(() => ({ - theme: modelThemeValue.value, + theme: getAppTheme.value ? darkTheme : null, })), notificationProviderProps: {}, }, @@ -66,16 +61,16 @@ export default defineComponent({ expose() return { - modelPrimaryColorOverride, - modelThemeValue, + getPrimaryColorOverride, localePackage, + getAppTheme, } }, render() { return ( diff --git a/src/app-components/provider/AppStyleProvider/index.tsx b/src/app-components/provider/AppStyleProvider/index.tsx index d60a4edb..bac79840 100644 --- a/src/app-components/provider/AppStyleProvider/index.tsx +++ b/src/app-components/provider/AppStyleProvider/index.tsx @@ -13,17 +13,15 @@ import './index.scss' import { getStorage } from '@/utils/cache' import { get } from 'lodash-es' -import { useSetting } from '@/store' import { addClass, removeClass, addStyle, colorToRgba } from '@/utils/element' +import { useSettingGetters } from '@/store' import type { SettingState } from '@/store/modules/setting/type' const AppStyleProvider = defineComponent({ name: 'AppStyleProvider', setup(_, { expose }) { - const settingStore = useSetting() - - const { themeValue } = storeToRefs(settingStore) + const { getAppTheme } = useSettingGetters() /** 同步主题色变量至 body, 如果未获取到缓存值则已默认值填充 */ const syncPrimaryColorToBody = () => { @@ -72,7 +70,7 @@ const AppStyleProvider = defineComponent({ * * 初始化时根据当前主题色进行初始化 body 的 class 属性 * - * 根据 themeValue 进行初始化 + * 根据 getAppTheme 进行初始化 */ const body = document.body const darkClassName = 'ray-template--dark' @@ -89,7 +87,7 @@ const AppStyleProvider = defineComponent({ hiddenLoadingAnimation() watch( - () => themeValue.value, + () => getAppTheme.value, (ndata) => { updateGlobalThemeClass(ndata) }, diff --git a/src/app-components/provider/AppWatermarkProvider/index.tsx b/src/app-components/provider/AppWatermarkProvider/index.tsx index 5ac67557..bc92390f 100644 --- a/src/app-components/provider/AppWatermarkProvider/index.tsx +++ b/src/app-components/provider/AppWatermarkProvider/index.tsx @@ -12,19 +12,19 @@ import { NWatermark } from 'naive-ui' import { APP_WATERMARK_CONFIG } from '@/app-config/appConfig' -import { useSetting } from '@/store' +import { useSettingGetters } from '@/store' export default defineComponent({ name: 'AppWatermarkProvider', setup() { - const { watermarkSwitch } = storeToRefs(useSetting()) + const { getWatermarkSwitch } = useSettingGetters() return { - watermarkSwitch, + getWatermarkSwitch, } }, render() { - return this.watermarkSwitch ? ( + return this.getWatermarkSwitch ? ( ) : null }, diff --git a/src/components/RChart/index.tsx b/src/components/RChart/index.tsx index 527e8398..6480f912 100644 --- a/src/components/RChart/index.tsx +++ b/src/components/RChart/index.tsx @@ -40,7 +40,6 @@ import { CanvasRenderer } from 'echarts/renderers' // `echarts` 渲染器 import { NCard } from 'naive-ui' import props from './props' -import { useSetting } from '@/store' import { throttle } from 'lodash-es' import { completeSize } from '@/utils/element' import { call } from '@/utils/vue/index' @@ -50,6 +49,7 @@ import { useResizeObserver } from '@vueuse/core' import RMoreDropdown from '@/components/RMoreDropdown/index' import { renderNode } from '@use-utils/vue/index' import { downloadBase64File } from '@use-utils/basic' +import { useSettingGetters } from '@/store' import type { WatchStopHandle } from 'vue' import type { AnyFC } from '@/types/modules/utils' @@ -70,8 +70,7 @@ export default defineComponent({ name: 'RChart', props, setup(props, { expose }) { - const settingStore = useSetting() - const { themeValue: currentTheme } = storeToRefs(settingStore) + const { getAppTheme } = useSettingGetters() const rayChartRef = ref() // echart 容器实例 const rayChartWrapperRef = ref() const echartInstanceRef = ref() // echart 实例 @@ -153,7 +152,7 @@ export default defineComponent({ if (!props.theme) { const theme = props.autoChangeTheme - ? currentTheme.value + ? getAppTheme.value ? `${echartTheme}-dark` : echartTheme : echartTheme @@ -295,7 +294,7 @@ export default defineComponent({ // 避免重复渲染 if (echartInst?.getDom()) { console.warn( - 'RChart mount: There is a chart instance already initialized on the dom. Execution was interrupted', + 'RChart mount: There is a chart instance already initialized on the dom. Execution was interrupted.', ) return @@ -326,7 +325,7 @@ export default defineComponent({ /** 监听全局主题变化, 然后重新渲染对应主题 echarts */ watch( - () => currentTheme.value, + () => getAppTheme.value, () => { /** * diff --git a/src/components/RTransitionComponent/index.vue b/src/components/RTransitionComponent/index.vue index 5affd183..1d85f681 100644 --- a/src/components/RTransitionComponent/index.vue +++ b/src/components/RTransitionComponent/index.vue @@ -11,7 +11,7 @@ @@ -23,7 +23,7 @@ diff --git a/src/global-variable/variable.ts b/src/global-variable/variable.ts index 35ce02c6..e0d20b50 100644 --- a/src/global-variable/variable.ts +++ b/src/global-variable/variable.ts @@ -32,6 +32,8 @@ import type { AnyFC } from '@/types/modules/utils' const variableState = reactive({ globalSpinning: false, globalDrawerValue: false, + globalMainLayoutLoad: true, + layoutContentMaximize: false, }) export type VariableState = typeof variableState diff --git a/src/hooks/template/index.ts b/src/hooks/template/index.ts new file mode 100644 index 00000000..67dc943f --- /dev/null +++ b/src/hooks/template/index.ts @@ -0,0 +1,5 @@ +import { useAppMenu } from './useAppMenu' +import { useMainPage } from './useMainPage' +import { useMenuTag } from './useMenuTag' + +export { useAppMenu, useMainPage, useMenuTag } diff --git a/src/hooks/template/useAppMenu.ts b/src/hooks/template/useAppMenu.ts new file mode 100644 index 00000000..2754d064 --- /dev/null +++ b/src/hooks/template/useAppMenu.ts @@ -0,0 +1,82 @@ +/** + * + * @author Ray + * + * @date 2023-11-03 + * + * @workspace ray-template + * + * @remark 今天也是元气满满撸代码的一天 + */ + +import { useMenuGetters, useMenuActions } from '@/store' + +import type { AppMenuOption } from '@/types/modules/app' + +export type Target = number | AppMenuOption + +/** + * + * 导航函数 + * 但是该方法仅限于在登入后调用 + */ +export function useAppMenu() { + const { changeMenuModelValue } = useMenuActions() + + /** + * + * @param target 需要导航的目标地址 + * + * 当传递参数为 number: + * - 当传入参数值超过最大菜单长度,也会跳转失败并且抛出警告 + * - 如果传递参数需要导航的菜单项为非根菜单项,会自动的递归导航至第一个子菜单项 + * + * 当传递参数为 AppMenuOption 类型,会直接导航至目标页面。该方法可以不区分菜单层级 + */ + const navigationTo = (target: Target) => { + if (typeof target === 'number') { + // 校验是否为 NaN + if (isNaN(target)) { + console.warn(`navigationTo: The ${target} is NaN, expect number.`) + + return + } + + const { getMenuOptions } = useMenuGetters() + + // 校验是否超出最大菜单长度 + if (target > getMenuOptions.value.length) { + console.warn( + `navigationTo: The current ${target} exceeds the maximum number of menus.`, + ) + + return + } + + const option = getMenuOptions.value[target] + + // 递归获取第一级子菜单 + const deepNavigation = (routes: AppMenuOption) => { + if (routes.children && routes.children.length > 0) { + const { + children: [firstChild], + } = routes + + deepNavigation(firstChild) + + return + } + + changeMenuModelValue(routes.key, routes) + } + + deepNavigation(option) + } else { + changeMenuModelValue(target.key, target) + } + } + + return { + navigationTo, + } +} diff --git a/src/hooks/template/useMainPage.ts b/src/hooks/template/useMainPage.ts new file mode 100644 index 00000000..4ca284ce --- /dev/null +++ b/src/hooks/template/useMainPage.ts @@ -0,0 +1,35 @@ +/** + * + * @author Ray + * + * @date 2023-11-03 + * + * @workspace ray-template + * + * @remark 今天也是元气满满撸代码的一天 + */ + +import { getVariableToRefs, setVariable } from '@/global-variable/index' +import { LAYOUT_CONTENT_REF } from '@/app-config/routerConfig' +import { useFullscreen } from 'vue-hooks-plus' +import { useI18n } from '@/hooks/web/index' + +import type { AppMenuOption } from '@/types/modules/app' +import type { Ref } from 'vue' + +export function useMainPage() { + const reload = (wait = 800) => { + setVariable('globalMainLayoutLoad', false) + + setTimeout(() => setVariable('globalMainLayoutLoad', true), wait) + } + + const maximize = (full: boolean) => { + // setVariable('layoutContentMaximize', full) + } + + return { + reload, + maximize, + } +} diff --git a/src/hooks/template/useMenuTag.ts b/src/hooks/template/useMenuTag.ts new file mode 100644 index 00000000..c207f4c5 --- /dev/null +++ b/src/hooks/template/useMenuTag.ts @@ -0,0 +1,165 @@ +/** + * + * @author Ray + * + * @date 2023-11-03 + * + * @workspace ray-template + * + * @remark 今天也是元气满满撸代码的一天 + */ + +import { useMenuGetters, useMenuActions } from '@/store' +import { ROOT_ROUTE } from '@/app-config/appConfig' +import { redirectRouterToDashboard } from '@/router/helper/routerCopilot' + +import type { MenuTagOptions, Key } from '@/types/modules/app' + +export type CloseMenuTag = Key | MenuTagOptions + +export function useMenuTag() { + const { getMenuTagOptions, getMenuKey } = useMenuGetters() + const { + changeMenuModelValue, + spliceMenTagOptions, + emptyMenuTagOptions, + setMenuTagOptions, + } = useMenuActions() + const { path } = ROOT_ROUTE + + /** + * + * 如果为非 root path,直接导航至上一 menuTag + */ + const navigationPreTagOption = () => { + const options = getMenuTagOptions.value + const length = options.length + const preOption = options[length - 1] + + if (getMenuKey.value !== path) { + changeMenuModelValue(preOption.key as string, preOption) + } + } + + /** + * + * @param target 当前关闭项 + * + * 传递参数类型情况: + * - number: 关闭当前项索引 + * - string: 关闭当前项 key + * - AppMenuOption: 关闭当前项 + */ + const close = (target: CloseMenuTag) => { + if (typeof target === 'number') { + if (isNaN(target)) { + console.warn(`close: The ${target} is NaN, expect number.`) + + return + } + + if (target > getMenuTagOptions.value.length) { + console.warn( + `close: The ${target} is greater than menuTagOptions length.`, + ) + + return + } + + spliceMenTagOptions(target) + navigationPreTagOption() + } else if (typeof target === 'string') { + const findOptionIndex = getMenuTagOptions.value.findIndex( + (curr) => curr.key === target, + ) + + if (findOptionIndex !== -1) { + spliceMenTagOptions(findOptionIndex) + navigationPreTagOption() + } else { + console.warn( + `close: The ${target} is not found in current menuTagOptions.`, + ) + + return + } + } else { + changeMenuModelValue(target.key as string, target) + } + } + + /** + * + * 关闭所有标签并且导航至 root path + */ + const closeAll = () => { + emptyMenuTagOptions() + redirectRouterToDashboard(true) + } + + /** + * + * @param currentIndex 开始关闭索引 + * + * 关闭以当前项为索引的右侧标签 + * 如果当前选择标签与 menuKey 不匹配,则会关闭当前标签右侧所有变迁并且跳转至该页面 + */ + const closeRight = (currentIndex: number) => { + const spliceLength = getMenuTagOptions.value.length - currentIndex + const routeOption = getMenuTagOptions.value[currentIndex] + + if (spliceLength > -1 && routeOption) { + spliceMenTagOptions(currentIndex + 1, spliceLength) + + if (getMenuKey.value !== routeOption.key) { + changeMenuModelValue(routeOption.key as string, routeOption) + } + } else { + console.warn( + `closeRight: The ${currentIndex} is not found in current menuTagOptions.`, + ) + } + } + + /** + * + * @param currentIndex 当前选择项的索引 + * + * 关闭以当前项左侧所有标签 + * 如果当前选择标签与 menuKey 不匹配,则会关闭当前标签左侧所有变迁并且跳转至该页面 + */ + const closeLeft = (currentIndex: number) => { + spliceMenTagOptions(0, currentIndex) + } + + /** + * + * @param currentIndex 当前项索引 + * + * 会关闭除了当前索引的所有菜单项 + */ + const closeOther = (currentIndex: number) => { + const routeOption = getMenuTagOptions.value[currentIndex] + + if (routeOption) { + if (getMenuKey.value !== routeOption.key) { + emptyMenuTagOptions() + changeMenuModelValue(routeOption.key, routeOption) + } else { + setMenuTagOptions(routeOption, false) + } + } else { + console.warn( + `closeOther: The ${currentIndex} is not found in current menuTagOptions.`, + ) + } + } + + return { + close, + closeAll, + closeRight, + closeLeft, + closeOther, + } +} diff --git a/src/layout/components/Menu/index.tsx b/src/layout/components/Menu/index.tsx index ed25c9d6..31b91c73 100644 --- a/src/layout/components/Menu/index.tsx +++ b/src/layout/components/Menu/index.tsx @@ -14,10 +14,10 @@ import './index.scss' import { NMenu, NLayoutSider, NDrawer } from 'naive-ui' import SiderBarLogo from './components/SiderBarLogo/index' -import { useMenu } from '@/store' import { APP_MENU_CONFIG } from '@/app-config/appConfig' import { useDevice } from '@/hooks/web/index' import { getVariableToRefs, setVariable } from '@/global-variable/index' +import { useMenuGetters, useMenuActions } from '@/store' import type { MenuInst } from 'naive-ui' import type { NaiveMenuOptions } from '@/types/modules/component' @@ -28,16 +28,16 @@ export default defineComponent({ setup() { const menuRef = ref(null) - const menuStore = useMenu() + const { changeMenuModelValue, collapsedMenu } = useMenuActions() + const { getMenuOptions, getCollapsed, getMenuKey } = useMenuGetters() - const { changeMenuModelValue, collapsedMenu } = menuStore const modelMenuKey = computed({ get: () => { nextTick().then(() => { showMenuOption() }) - return menuStore.menuKey + return getMenuKey.value }, set: () => { if (isTabletOrSmaller.value) { @@ -45,8 +45,6 @@ export default defineComponent({ } }, }) - const modelMenuOptions = computed(() => menuStore.options) - const modelCollapsed = computed(() => menuStore.collapsed) const { isTabletOrSmaller } = useDevice() const modelGlobalDrawerValue = computed({ get: () => getVariableToRefs('globalDrawerValue').value, @@ -72,14 +70,14 @@ export default defineComponent({ onUpdateCollapsed={collapsedMenu.bind(this)} nativeScrollbar={false} > - + { @@ -91,7 +89,6 @@ export default defineComponent({ ) return { - menuRef, isTabletOrSmaller, BasicMenu: BasicMenu, modelGlobalDrawerValue, diff --git a/src/layout/components/MenuTag/index.tsx b/src/layout/components/MenuTag/index.tsx index 71c3172c..ece7b99b 100644 --- a/src/layout/components/MenuTag/index.tsx +++ b/src/layout/components/MenuTag/index.tsx @@ -29,15 +29,17 @@ import { NScrollbar, NTag, NSpace, NLayoutHeader, NDropdown } from 'naive-ui' import RIcon from '@/components/RIcon/index' import RMoreDropdown from '@/components/RMoreDropdown/index' -import { useMenu, useSetting } from '@/store' +import { useMenuGetters, useMenuActions } from '@/store' import { uuid } from '@/utils/basic' import { hasClass } from '@/utils/element' import { redirectRouterToDashboard } from '@/router/helper/routerCopilot' import { ROOT_ROUTE } from '@/app-config/appConfig' import { queryElements } from '@use-utils/element' import { renderNode } from '@/utils/vue/index' +import { useMainPage } from '@/hooks/template/index' +import { useMenuTag } from '@/hooks/template/index' -import type { MenuOption, ScrollbarInst } from 'naive-ui' +import type { ScrollbarInst } from 'naive-ui' import type { MenuTagOptions, AppMenuOption } from '@/types/modules/app' export default defineComponent({ @@ -45,43 +47,28 @@ export default defineComponent({ setup(_, { expose }) { const scrollRef = ref(null) - const menuStore = useMenu() - const settingStore = useSetting() - - const { menuKey, menuTagOptions } = storeToRefs(menuStore) + const { getMenuKey, getMenuTagOptions } = useMenuGetters() const { changeMenuModelValue, spliceMenTagOptions, emptyMenuTagOptions, setMenuTagOptions, - } = menuStore - const { changeSwitcher } = settingStore + } = useMenuActions() const { path } = ROOT_ROUTE + const { reload } = useMainPage() + const { + close, + closeAll: $closeAll, + closeRight: $closeRight, + closeLeft: $closeLeft, + closeOther: $closeOther, + } = useMenuTag() const exclude = ['closeAll', 'closeRight', 'closeLeft', 'closeOther'] let currentContextmenuIndex = -1 // 当前右键标签页索引位置 const iconConfig = { size: 16, } - const modelMenuTagOptions = computed(() => - menuTagOptions.value.map((curr, _idx, currentArray) => { - if (curr.key === menuKey.value && curr.key !== path) { - curr.closeable = true - } else { - curr.closeable = false - } - - if (curr.key === path) { - curr.closeable = false - } - - if (currentArray.length <= 1) { - curr.closeable = false - } - - return curr - }), - ) const moreOptions = ref([ { label: '重新加载', @@ -154,58 +141,22 @@ export default defineComponent({ disabled: false, }, ]) - const scrollBarUUID = uuid(16) + const uuidScrollBar = uuid(16) const actionMap = { reloadCurrentPage: () => { - changeSwitcher(false, 'reloadRouteSwitch') - - setTimeout(() => changeSwitcher(true, 'reloadRouteSwitch')) + reload() }, closeAll: () => { - /** - * - * 关闭全部标签页, 然后重定向至首页(dashboard) - * 如果做了相关更改, 则需要手动更新 - */ - if (moreOptions.value.length > 1) { - emptyMenuTagOptions() - redirectRouterToDashboard(true) - } + $closeAll() }, closeRight: () => { - /** - * - * 关闭右侧标签 - * - * 如果当前选择标签与 menuKey 不匹配, 则会关闭当前标签右侧所有变迁并且跳转至该页面 - */ - const length = moreOptions.value.length - const routeItem = modelMenuTagOptions.value[currentContextmenuIndex] - - spliceMenTagOptions(currentContextmenuIndex + 1, length - 1) - - if (menuKey.value !== routeItem.key) { - changeMenuModelValue(routeItem.key, routeItem) - } + $closeRight(currentContextmenuIndex) }, closeLeft: () => { - spliceMenTagOptions(0, currentContextmenuIndex) + $closeLeft(currentContextmenuIndex) }, closeOther: () => { - /** - * - * 关闭其他标签 - * - * 如果关闭标签与当前 menuKey 不匹配, 则会关闭当前选择标签页以外的所有标签页并且跳转至该页面 - */ - const routeItem = modelMenuTagOptions.value[currentContextmenuIndex] - - if (menuKey.value !== routeItem.key) { - emptyMenuTagOptions() - changeMenuModelValue(routeItem.key, routeItem) - } else { - setMenuTagOptions(routeItem, false) - } + $closeOther(currentContextmenuIndex) }, } /** 右键菜单 */ @@ -223,16 +174,7 @@ export default defineComponent({ * @remark 关闭 `tag` 菜单, 如果仅有一个则不能关闭 */ const closeCurrentMenuTag = (idx: number) => { - spliceMenTagOptions(idx) - - if (menuKey.value !== path) { - const options = modelMenuTagOptions.value - const length = options.length - - const tag = options[length - 1] - - changeMenuModelValue(tag.key as string, tag) - } + close(idx) } const setMoreOptionsDisabled = ( @@ -257,7 +199,7 @@ export default defineComponent({ } const getScrollElement = () => { - const scroll = document.getElementById(scrollBarUUID) // 获取滚动条容器 + const scroll = document.getElementById(uuidScrollBar) // 获取滚动条容器 if (scroll) { const scrollContentElement = Array.from( @@ -320,7 +262,7 @@ export default defineComponent({ } const setDisabledAccordionToIndex = () => { - const length = modelMenuTagOptions.value.length - 1 + const length = getMenuTagOptions.value.length - 1 if (currentContextmenuIndex === length) { setMoreOptionsDisabled('closeRight', true) @@ -342,8 +284,8 @@ export default defineComponent({ * 并且动态设置是否可操作状态 */ const setCurrentContextmenuIndex = () => { - const index = modelMenuTagOptions.value.findIndex( - (curr) => curr.key === menuKey.value, + const index = getMenuTagOptions.value.findIndex( + (curr) => curr.key === getMenuKey.value, ) currentContextmenuIndex = index @@ -351,16 +293,16 @@ export default defineComponent({ setDisabledAccordionToIndex() } - /** 仅有 modelMenuTagOptions 长度大于 1 并且非 root path 时, 才激活关闭按钮 */ + /** 仅有 getMenuTagOptions 长度大于 1 并且非 root path 时, 才激活关闭按钮 */ const menuTagMouseenter = (option: MenuTagOptions) => { - if (modelMenuTagOptions.value.length > 1 && option.key !== path) { + if (getMenuTagOptions.value.length > 1 && option.key !== path) { option.closeable = true } } /** 移出 MenuTag 时, 判断是否为当前已激活 key */ const menuTagMouseleave = (option: MenuTagOptions) => { - if (option.key !== menuKey.value) { + if (option.key !== getMenuKey.value) { option.closeable = false } } @@ -387,7 +329,7 @@ export default defineComponent({ const positionMenuTag = () => { nextTick().then(() => { const tags = queryElements( - `attr:${MENU_TAG_DATA}="${menuKey.value}"`, + `attr:${MENU_TAG_DATA}="${getMenuKey.value}"`, ) if (tags?.length) { @@ -402,7 +344,7 @@ export default defineComponent({ /** 如果有且只有一个标签页时, 禁止全部关闭操作 */ watch( - () => modelMenuTagOptions.value, + () => getMenuTagOptions.value, (newData, oldData) => { moreOptions.value.forEach((curr) => { if (exclude.includes(curr.key)) { @@ -436,15 +378,15 @@ export default defineComponent({ expose({}) return { - modelMenuTagOptions, + getMenuTagOptions, changeMenuModelValue, closeCurrentMenuTag, - menuKey, + getMenuKey, handleTagClick, moreOptions, scrollX, scrollRef, - scrollBarUUID, + uuidScrollBar, actionDropdownSelect, rootPath: path, actionState, @@ -495,7 +437,7 @@ export default defineComponent({ xScrollable ref="scrollRef" {...{ - id: this.scrollBarUUID, + id: this.uuidScrollBar, }} > - {this.modelMenuTagOptions.map((curr, idx) => ( + {this.getMenuTagOptions.map((curr, idx) => ( - {renderNode(curr.label)} + {renderNode(curr.breadcrumbLabel)} ))} diff --git a/src/layout/components/SiderBar/components/Breadcrumb/index.tsx b/src/layout/components/SiderBar/components/Breadcrumb/index.tsx index 40a17487..9451108f 100644 --- a/src/layout/components/SiderBar/components/Breadcrumb/index.tsx +++ b/src/layout/components/SiderBar/components/Breadcrumb/index.tsx @@ -20,24 +20,17 @@ import { NDropdown, NBreadcrumb, NBreadcrumbItem } from 'naive-ui' -import { useMenu } from '@/store' +import { useMenuGetters, useMenuActions } from '@/store' import { useDevice } from '@/hooks/web/index' import type { DropdownOption } from 'naive-ui' -import type { - AppMenuOption, - MenuTagOptions, - AppMenuKey, -} from '@/types/modules/app' +import type { AppMenuOption } from '@/types/modules/app' export default defineComponent({ name: 'RBreadcrumb', setup() { - const menuStore = useMenu() - - const { changeMenuModelValue } = menuStore - const { breadcrumbOptions } = storeToRefs(menuStore) - const modelBreadcrumbOptions = computed(() => breadcrumbOptions.value) + const { changeMenuModelValue } = useMenuActions() + const { getBreadcrumbOptions } = useMenuGetters() const { isTabletOrSmaller } = useDevice() const dropdownSelect = (key: string | number, option: DropdownOption) => { @@ -55,7 +48,7 @@ export default defineComponent({ } return { - modelBreadcrumbOptions, + getBreadcrumbOptions, dropdownSelect, breadcrumbItemClick, isTabletOrSmaller, @@ -68,7 +61,7 @@ export default defineComponent({
) : ( - {this.modelBreadcrumbOptions.map((curr) => ( + {this.getBreadcrumbOptions.map((curr) => ( props.show, set: (val) => { @@ -54,7 +44,8 @@ export default defineComponent({ } }, }) - const modelMenuOptions = computed(() => menuStore.options) + const { getMenuOptions } = useMenuGetters() + const state = reactive({ searchValue: null, searchOptions: [] as AppMenuOption[], @@ -131,7 +122,7 @@ export default defineComponent({ } if (value) { - filterArr(modelMenuOptions.value) + filterArr(getMenuOptions.value) state.searchOptions = arr } else { @@ -326,7 +317,7 @@ export default defineComponent({ {searchOptions.length ? ( {searchOptions.map((curr) => ( - + ))} ) : ( @@ -355,7 +346,7 @@ export default defineComponent({ size={[24, 8]} > {this.helperTipOptions.map((curr) => ( -
+
{curr.plain ? ( {curr.icon} diff --git a/src/layout/components/SiderBar/components/SettingDrawer/components/ThemeSwitch/index.tsx b/src/layout/components/SiderBar/components/SettingDrawer/components/ThemeSwitch/index.tsx index 0fcec632..4cd0fc6e 100644 --- a/src/layout/components/SiderBar/components/SettingDrawer/components/ThemeSwitch/index.tsx +++ b/src/layout/components/SiderBar/components/SettingDrawer/components/ThemeSwitch/index.tsx @@ -12,14 +12,13 @@ import { NSpace, NSwitch, NTooltip } from 'naive-ui' import RIcon from '@/components/RIcon' -import { useSetting } from '@/store' +import { useSettingGetters, useSettingActions } from '@/store' const ThemeSwitch = defineComponent({ name: 'ThemeSwitch', setup() { - const settingStore = useSetting() - const { changeSwitcher } = settingStore - const { themeValue } = storeToRefs(settingStore) + const { changeSwitcher } = useSettingActions() + const { getAppTheme } = useSettingGetters() const handleRailStyle = ({ checked }: { checked: boolean }) => { return checked @@ -33,7 +32,7 @@ const ThemeSwitch = defineComponent({ return { changeSwitcher, - themeValue, + getAppTheme, handleRailStyle, } }, @@ -46,10 +45,10 @@ const ThemeSwitch = defineComponent({ {{ trigger: () => ( - this.changeSwitcher(bool, 'themeValue') + this.changeSwitcher(bool, 'appTheme') } > {{ @@ -75,7 +74,7 @@ const ThemeSwitch = defineComponent({ ), default: () => - this.themeValue + this.getAppTheme ? $t('headerSettingOptions.ThemeOptions.Dark') : $t('headerSettingOptions.ThemeOptions.Light'), }} diff --git a/src/layout/components/SiderBar/components/SettingDrawer/index.tsx b/src/layout/components/SiderBar/components/SettingDrawer/index.tsx index 86c1fe91..2a9daf22 100644 --- a/src/layout/components/SiderBar/components/SettingDrawer/index.tsx +++ b/src/layout/components/SiderBar/components/SettingDrawer/index.tsx @@ -14,7 +14,7 @@ import { import ThemeSwitch from '@/layout/components/SiderBar/components/SettingDrawer/components/ThemeSwitch/index' import { APP_THEME } from '@/app-config/designConfig' -import { useSetting } from '@/store' +import { useSettingGetters, useSettingActions } from '@/store' import type { PropType } from 'vue' import type { Placement } from '@/types/modules/component' @@ -37,19 +37,17 @@ const SettingDrawer = defineComponent({ }, emits: ['update:show'], setup(props, { emit }) { - const settingStore = useSetting() - const { changePrimaryColor, changeSwitcher, updateContentTransition } = - settingStore + useSettingActions() const { - themeValue, - primaryColorOverride, - menuTagSwitch, - breadcrumbSwitch, - footerSwitch, - contentTransition, - watermarkSwitch, - } = storeToRefs(settingStore) + getAppTheme, + getPrimaryColorOverride, + getMenuTagSwitch, + getBreadcrumbSwitch, + getCopyrightSwitch, + getContentTransition, + getWatermarkSwitch, + } = useSettingGetters() const modelShow = computed({ get: () => props.show, @@ -79,16 +77,16 @@ const SettingDrawer = defineComponent({ return { modelShow, changePrimaryColor, - themeValue, - primaryColorOverride, - menuTagSwitch, + getAppTheme, + getPrimaryColorOverride, + getMenuTagSwitch, changeSwitcher, - breadcrumbSwitch, - footerSwitch, + getBreadcrumbSwitch, + getCopyrightSwitch, contentTransitionOptions, - contentTransition, + getContentTransition, updateContentTransition, - watermarkSwitch, + getWatermarkSwitch, } }, render() { @@ -111,14 +109,14 @@ const SettingDrawer = defineComponent({ {$t('headerSettingOptions.ContentTransition')} { this.updateContentTransition(value) @@ -130,7 +128,7 @@ const SettingDrawer = defineComponent({ this.changeSwitcher(bool, 'menuTagSwitch') } @@ -138,7 +136,7 @@ const SettingDrawer = defineComponent({ this.changeSwitcher(bool, 'breadcrumbSwitch') } @@ -146,7 +144,7 @@ const SettingDrawer = defineComponent({ this.changeSwitcher(bool, 'watermarkSwitch') } @@ -154,9 +152,9 @@ const SettingDrawer = defineComponent({ - this.changeSwitcher(bool, 'footerSwitch') + this.changeSwitcher(bool, 'copyrightSwitch') } /> diff --git a/src/layout/components/SiderBar/hook.ts b/src/layout/components/SiderBar/hook.ts index 3a1aeb60..d1010fe5 100644 --- a/src/layout/components/SiderBar/hook.ts +++ b/src/layout/components/SiderBar/hook.ts @@ -1,5 +1,9 @@ -import { useSetting, useSigning } from '@/store' import { useI18n } from '@/hooks/web/index' +import { + useSigningActions, + useSigningGetters, + useSettingActions, +} from '@/store' import type { IconOptionsFC, IconOptions } from './type' @@ -24,8 +28,7 @@ export const createAvatarOptions = () => [ const avatarDropdownActionMap = { logout: () => { - const signingStore = useSigning() - const { logout } = signingStore + const { logout } = useSigningActions() window.$dialog.warning({ title: '提示', @@ -38,8 +41,7 @@ const avatarDropdownActionMap = { }) }, lockScreen: () => { - const settingStore = useSetting() - const { changeSwitcher } = settingStore + const { changeSwitcher } = useSettingActions() changeSwitcher(true, 'lockScreenSwitch') }, @@ -52,7 +54,7 @@ export const avatarDropdownClick = (key: string | number) => { } export const createLeftIconOptions = (opts: IconOptionsFC) => { - const { isTabletOrSmaller, reloadRouteSwitch } = opts + const { isTabletOrSmaller, globalMainLayoutLoad } = opts const { t } = useI18n() const notTableOrSmallerOptions: IconOptions[] = [ @@ -60,7 +62,7 @@ export const createLeftIconOptions = (opts: IconOptionsFC) => { name: 'reload', size: 18, tooltip: t('headerTooltip.Reload'), - iconClass: !reloadRouteSwitch.value ? 'ray-icon__reload--loading' : '', + iconClass: !globalMainLayoutLoad.value ? 'ray-icon__reload--loading' : '', eventKey: 'reload', }, ] diff --git a/src/layout/components/SiderBar/index.tsx b/src/layout/components/SiderBar/index.tsx index dd2f6ada..54f78db3 100644 --- a/src/layout/components/SiderBar/index.tsx +++ b/src/layout/components/SiderBar/index.tsx @@ -27,7 +27,6 @@ import Breadcrumb from './components/Breadcrumb/index' import GlobalSearch from './components/GlobalSearch/index' import AppAvatar from '@/app-components/app/AppAvatar/index' -import { useSetting } from '@/store' import { LOCAL_OPTIONS } from '@/app-config/localConfig' import { createAvatarOptions, @@ -39,22 +38,22 @@ import { useDevice } from '@/hooks/web/index' import { getVariableToRefs, setVariable } from '@/global-variable/index' import { useFullscreen } from 'vue-hooks-plus' import { useI18n } from '@/hooks/web/index' +import { useMainPage } from '@/hooks/template/index' +import { useSettingGetters, useSettingActions } from '@/store' import type { IconEventMapOptions, IconEventMap } from './type' export default defineComponent({ name: 'AppSiderBar', setup() { - const settingStore = useSetting() - - const { updateLocale, changeSwitcher } = settingStore + const { updateLocale, changeSwitcher } = useSettingActions() const { t } = useI18n() + const { reload } = useMainPage() const [isFullscreen, { toggleFullscreen, isEnabled }] = useFullscreen( document.getElementsByTagName('html')[0], ) - const { drawerPlacement, breadcrumbSwitch, reloadRouteSwitch } = - storeToRefs(settingStore) + const { getDrawerPlacement, getBreadcrumbSwitch } = useSettingGetters() const showSettings = ref(false) const spaceItemStyle = { display: 'flex', @@ -62,6 +61,7 @@ export default defineComponent({ const globalSearchShown = ref(false) const { isTabletOrSmaller } = useDevice() const globalDrawerValue = getVariableToRefs('globalDrawerValue') + const globalMainLayoutLoad = getVariableToRefs('globalMainLayoutLoad') /** * @@ -71,7 +71,7 @@ export default defineComponent({ createLeftIconOptions({ isFullscreen, isTabletOrSmaller, - reloadRouteSwitch, + globalMainLayoutLoad, }), ) /** @@ -82,15 +82,13 @@ export default defineComponent({ createRightIconOptions({ isFullscreen, isTabletOrSmaller, - reloadRouteSwitch, + globalMainLayoutLoad, }), ) const iconEventMap: IconEventMapOptions = { // 刷新组件重新加载,手动设置 800ms loading 时长 reload: () => { - changeSwitcher(false, 'reloadRouteSwitch') - - setTimeout(() => changeSwitcher(true, 'reloadRouteSwitch'), 800) + reload() }, setting: () => { showSettings.value = true @@ -127,8 +125,8 @@ export default defineComponent({ showSettings, updateLocale, spaceItemStyle, - drawerPlacement, - breadcrumbSwitch, + getDrawerPlacement, + getBreadcrumbSwitch, globalSearchShown, } }, @@ -148,6 +146,7 @@ export default defineComponent({ > {this.leftIconOptions.map((curr) => ( ))} - {this.breadcrumbSwitch ? : null} + {this.getBreadcrumbSwitch ? : null} {this.rightTooltipIconOptions.map((curr) => ( ) diff --git a/src/layout/components/SiderBar/type.ts b/src/layout/components/SiderBar/type.ts index 1b413a55..cbd26f3f 100644 --- a/src/layout/components/SiderBar/type.ts +++ b/src/layout/components/SiderBar/type.ts @@ -26,5 +26,5 @@ export interface IconOptions { export interface IconOptionsFC { isTabletOrSmaller: Ref isFullscreen: Ref - reloadRouteSwitch: Ref + globalMainLayoutLoad: Ref } diff --git a/src/layout/default/ContentWrapper/index.tsx b/src/layout/default/ContentWrapper/index.tsx index deaf487b..45b84309 100644 --- a/src/layout/default/ContentWrapper/index.tsx +++ b/src/layout/default/ContentWrapper/index.tsx @@ -21,21 +21,22 @@ import { NSpin } from 'naive-ui' import RTransitionComponent from '@/components/RTransitionComponent/index.vue' import AppRequestCancelerProvider from '@/app-components/provider/AppRequestCancelerProvider/index' -import { useSetting } from '@/store' +import { getVariableToRefs } from '@/global-variable/index' +import { useSettingGetters } from '@/store' import type { GlobalThemeOverrides } from 'naive-ui' const ContentWrapper = defineComponent({ name: 'LayoutContentWrapper', setup() { - const settingStore = useSetting() const router = useRouter() - const { reloadRouteSwitch, contentTransition } = storeToRefs(settingStore) + const { getContentTransition } = useSettingGetters() const spinning = ref(false) const themeOverridesSpin: GlobalThemeOverrides['Spin'] = { opacitySpinning: '0', } + const globalMainLayoutLoad = getVariableToRefs('globalMainLayoutLoad') const setupLayoutContentSpin = () => { router.beforeEach(() => { @@ -50,25 +51,27 @@ const ContentWrapper = defineComponent({ setupLayoutContentSpin() return { - reloadRouteSwitch, + globalMainLayoutLoad, spinning, themeOverridesSpin, - contentTransition, + getContentTransition, } }, render() { + const { globalMainLayoutLoad } = this + return ( - {this.reloadRouteSwitch ? ( + {globalMainLayoutLoad ? ( ) : null} diff --git a/src/layout/index.scss b/src/layout/index.scss index ea0d3ff4..ff5fd0be 100644 --- a/src/layout/index.scss +++ b/src/layout/index.scss @@ -9,6 +9,17 @@ & .r-layout-full__viewer-content { height: var(--layout-content-height); padding: 16px; + transition: all 0.3s; + + &.r-layout-full__viewer-content--maximize { + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + transform-origin: center; + z-index: 99; + } & .n-scrollbar-container { height: 100%; diff --git a/src/layout/index.tsx b/src/layout/index.tsx index 9401438f..c853a12b 100644 --- a/src/layout/index.tsx +++ b/src/layout/index.tsx @@ -18,10 +18,11 @@ import FooterWrapper from '@/layout/default/FooterWrapper' import HeaderWrapper from './default/HeaderWrapper' import FeatureWrapper from './default/FeatureWrapper' -import { useSetting } from '@/store' import { LAYOUT_CONTENT_REF } from '@/app-config/routerConfig' import { layoutHeaderCssVars } from '@/layout/layoutResize' import useAppLockScreen from '@/app-components/app/AppLockScreen/appLockVar' +import { getVariableToRefs } from '@/global-variable/index' +import { useSettingGetters } from '@/store' export default defineComponent({ name: 'RLayout', @@ -30,45 +31,54 @@ export default defineComponent({ const layoutMenuTagRef = ref() const layoutFooterRef = ref() - const settingStore = useSetting() - - const { menuTagSwitch: modelMenuTagSwitch, footerSwitch } = - storeToRefs(settingStore) + const { getMenuTagSwitch, getCopyrightSwitch } = useSettingGetters() const { getLockAppScreen } = useAppLockScreen() const cssVarsRef = layoutHeaderCssVars([ layoutSiderBarRef, layoutMenuTagRef, layoutFooterRef, ]) + const layoutContentMaximize = getVariableToRefs('layoutContentMaximize') return { - modelMenuTagSwitch, + getMenuTagSwitch, cssVarsRef, getLockAppScreen, - LAYOUT_CONTENT_REF, layoutSiderBarRef, layoutMenuTagRef, layoutFooterRef, - footerSwitch, + getCopyrightSwitch, + layoutContentMaximize, } }, render() { - return !this.getLockAppScreen() ? ( - + const { + layoutContentMaximize, + getMenuTagSwitch, + cssVarsRef, + getCopyrightSwitch, + } = this + const { getLockAppScreen } = this + + return !getLockAppScreen() ? ( + - {this.modelMenuTagSwitch ? ( - - ) : null} + {getMenuTagSwitch ? : null} - {this.footerSwitch ? : null} + {getCopyrightSwitch ? : null} ) : null diff --git a/src/locales/lang/en-US/menu.json b/src/locales/lang/en-US/menu.json index 7cbb596a..8497168d 100644 --- a/src/locales/lang/en-US/menu.json +++ b/src/locales/lang/en-US/menu.json @@ -20,5 +20,6 @@ "RouterDemo": "Same Level Router Demo", "Mock": "Mock", "QRCode": "QRCode", - "SvgIcon": "SVG Icon" + "SvgIcon": "SVG Icon", + "TemplateHooks": "Template Api" } diff --git a/src/locales/lang/en-US/views/login/index.json b/src/locales/lang/en-US/views/login/index.json index efeece16..d91a6d81 100644 --- a/src/locales/lang/en-US/views/login/index.json +++ b/src/locales/lang/en-US/views/login/index.json @@ -1,7 +1,7 @@ { "Register": "Register", - "Signin": "Signin", - "QRCodeSignin": "QRCode Signin", + "Signing": "Signing", + "QRCodeSigning": "QRCode Signing", "NamePlaceholder": "please enter user name", "PasswordPlaceholder": "please enter password", "Login": "Login", diff --git a/src/locales/lang/zh-CN/menu.json b/src/locales/lang/zh-CN/menu.json index a83a914b..56828747 100644 --- a/src/locales/lang/zh-CN/menu.json +++ b/src/locales/lang/zh-CN/menu.json @@ -18,7 +18,8 @@ "CalculatePrecision": "数字精度", "Directive": "指令", "RouterDemo": "页面详情模式", - "Mock": "mock 数据", + "Mock": "Mock 数据", "QRCode": "二维码", - "SvgIcon": "SVG图标" + "SvgIcon": "SVG 图标", + "TemplateHooks": "模板内置 Api" } diff --git a/src/locales/lang/zh-CN/views/login/index.json b/src/locales/lang/zh-CN/views/login/index.json index 87bf08a6..ed0b14f0 100644 --- a/src/locales/lang/zh-CN/views/login/index.json +++ b/src/locales/lang/zh-CN/views/login/index.json @@ -1,7 +1,7 @@ { "Register": "注册", - "Signin": "登录", - "QRCodeSignin": "扫码登陆", + "Signing": "登录", + "QRCodeSigning": "扫码登陆", "NamePlaceholder": "请输入用户名", "PasswordPlaceholder": "请输入密码", "Login": "登 陆", diff --git a/src/router/helper/routerCopilot.ts b/src/router/helper/routerCopilot.ts index 4272e716..24d94a6a 100644 --- a/src/router/helper/routerCopilot.ts +++ b/src/router/helper/routerCopilot.ts @@ -11,11 +11,11 @@ import { permissionRouter } from './permission' import { SETUP_ROUTER_ACTION, SUPER_ADMIN } from '@/app-config/routerConfig' -import { useSigning } from '@/store' import { useVueRouter } from '@/hooks/web/index' import { ROOT_ROUTE } from '@/app-config/appConfig' import { setStorage } from '@/utils/cache' import { getAppEnvironment } from '@/utils/basic' +import { useSigningGetters } from '@/store' import type { Router } from 'vue-router' import type { AppRouteMeta } from '@/router/type' @@ -29,11 +29,13 @@ import type { AppMenuOption } from '@/types/modules/app' * 如果为超级管理员, 则会默认获取所有权限 */ export const validRole = (meta: AppRouteMeta) => { - const { signingCallback } = storeToRefs(useSigning()) - const modelRole = computed(() => signingCallback.value.role) + const { getSigningCallback } = useSigningGetters() const { role: metaRole } = meta - if (SUPER_ADMIN?.length && SUPER_ADMIN.includes(modelRole.value)) { + if ( + SUPER_ADMIN?.length && + SUPER_ADMIN.includes(getSigningCallback.value.role) + ) { return true } else { // 如果 role 为 undefined 或者空数组, 则认为该路由不做权限过滤 @@ -43,7 +45,7 @@ export const validRole = (meta: AppRouteMeta) => { // 判断是否含有该权限 if (metaRole) { - return metaRole.includes(modelRole.value) + return metaRole.includes(getSigningCallback.value.role) } return true diff --git a/src/router/modules/demo/template-hooks.ts b/src/router/modules/demo/template-hooks.ts new file mode 100644 index 00000000..8e6a7adb --- /dev/null +++ b/src/router/modules/demo/template-hooks.ts @@ -0,0 +1,17 @@ +import { t } from '@/hooks/web/index' +import { LAYOUT } from '@/router/constant/index' + +import type { AppRouteRecordRaw } from '@/router/type' + +const axios: AppRouteRecordRaw = { + path: '/template-hooks', + name: 'TemplateHooks', + component: () => import('@/views/demo/template-hooks/index'), + meta: { + i18nKey: t('menu.TemplateHooks'), + icon: 'other', + order: 1, + }, +} + +export default axios diff --git a/src/store/hooks/useKeepAliveStore.ts b/src/store/hooks/useKeepAliveStore.ts new file mode 100644 index 00000000..33c02a48 --- /dev/null +++ b/src/store/hooks/useKeepAliveStore.ts @@ -0,0 +1,35 @@ +/** + * + * @author Ray + * + * @date 2023-11-06 + * + * @workspace ray-template + * + * @remark 今天也是元气满满撸代码的一天 + */ + +import { piniaKeepAliveStore } from '../index' + +export const useKeepAliveGetters = () => { + const variable = piniaKeepAliveStore() + + /** + * + * @remark 获取当前可缓存项 name + */ + const getKeepAliveInclude = computed(() => variable.keepAliveInclude) + + return { + getKeepAliveInclude, + } +} + +export const useKeepAliveActions = () => { + const { setKeepAliveInclude, getKeepAliveInclude } = piniaKeepAliveStore() + + return { + setKeepAliveInclude, + getKeepAliveInclude, + } +} diff --git a/src/store/hooks/useMenuStore.ts b/src/store/hooks/useMenuStore.ts new file mode 100644 index 00000000..08d52426 --- /dev/null +++ b/src/store/hooks/useMenuStore.ts @@ -0,0 +1,97 @@ +/** + * + * @author Ray + * + * @date 2023-11-05 + * + * @workspace ray-template + * + * @remark 今天也是元气满满撸代码的一天 + */ + +import { piniaMenuStore } from '../modules/menu' +import { ROOT_ROUTE } from '@/app-config/appConfig' + +export const useMenuGetters = () => { + const variable = piniaMenuStore() + + /** + * + * @remark 获取菜单列表 + */ + const getMenuOptions = computed(() => variable.options) + /** + * + * @remark 获取面包屑列表 + */ + const getBreadcrumbOptions = computed(() => variable.breadcrumbOptions) + /** + * + * @remark 获取菜单当前 key + */ + const getMenuKey = computed(() => variable.menuKey) + /** + * + * @remark 获取菜单标签列表 + */ + const getMenuTagOptions = computed(() => { + const { path } = ROOT_ROUTE + + return variable.menuTagOptions.map((curr, _idx, currentArray) => { + if (curr.key === getMenuKey.value && curr.key !== path) { + curr.closeable = true + } else { + curr.closeable = false + } + + if (curr.key === path) { + curr.closeable = false + } + + if (currentArray.length <= 1) { + curr.closeable = false + } + + return curr + }) + }) + /** + * + * @remark 获取当前菜单项 + */ + const getCurrentMenuOption = computed(() => variable.currentMenuOption) + /** + * + * @remark 获取是否折叠 + */ + const getCollapsed = computed(() => variable.collapsed) + + return { + getMenuOptions, + getBreadcrumbOptions, + getMenuKey, + getMenuTagOptions, + getCurrentMenuOption, + getCollapsed, + } +} + +export const useMenuActions = () => { + const { + changeMenuModelValue, + setupAppMenu, + collapsedMenu, + spliceMenTagOptions, + emptyMenuTagOptions, + setMenuTagOptions, + } = piniaMenuStore() + + return { + changeMenuModelValue, + setupAppMenu, + collapsedMenu, + spliceMenTagOptions, + emptyMenuTagOptions, + setMenuTagOptions, + } +} diff --git a/src/store/hooks/useSettingStore.ts b/src/store/hooks/useSettingStore.ts new file mode 100644 index 00000000..edfccc84 --- /dev/null +++ b/src/store/hooks/useSettingStore.ts @@ -0,0 +1,96 @@ +/** + * + * @author Ray + * + * @date 2023-11-06 + * + * @workspace ray-template + * + * @remark 今天也是元气满满撸代码的一天 + */ + +import { piniaSettingStore } from '../modules/setting' + +export const useSettingGetters = () => { + const variable = piniaSettingStore() + + /** + * + * @remark 获取设置抽屉方向 + */ + const getDrawerPlacement = computed(() => variable.drawerPlacement) + /** + * + * @remark 获取 Naive UI 覆盖配置 + */ + const getPrimaryColorOverride = computed(() => variable.primaryColorOverride) + /** + * + * @remark 获取 app 主题 + */ + const getAppTheme = computed(() => variable.appTheme) + /** + * + * @remark 获取菜单标签开关 + */ + const getMenuTagSwitch = computed(() => variable.menuTagSwitch) + /** + * + * @remark 获取面包屑开关 + */ + const getBreadcrumbSwitch = computed(() => variable.breadcrumbSwitch) + /** + * + * @remark 获取 app 当前语言 + */ + const getLocaleLanguage = computed(() => variable.localeLanguage) + /** + * + * @remark 获取锁屏开关 + */ + const getLockScreenSwitch = computed(() => variable.lockScreenSwitch) + /** + * + * @remark 获取版权信息开关 + */ + const getCopyrightSwitch = computed(() => variable.copyrightSwitch) + /** + * + * @remark 获取 app 内容区域过渡动画效果 + */ + const getContentTransition = computed(() => variable.contentTransition) + /** + * + * @remark 获取水印开关 + */ + const getWatermarkSwitch = computed(() => variable.watermarkSwitch) + + return { + getDrawerPlacement, + getPrimaryColorOverride, + getAppTheme, + getMenuTagSwitch, + getBreadcrumbSwitch, + getLocaleLanguage, + getLockScreenSwitch, + getCopyrightSwitch, + getContentTransition, + getWatermarkSwitch, + } +} + +export const useSettingActions = () => { + const { + updateLocale, + changePrimaryColor, + changeSwitcher, + updateContentTransition, + } = piniaSettingStore() + + return { + updateLocale, + changePrimaryColor, + changeSwitcher, + updateContentTransition, + } +} diff --git a/src/store/hooks/useSigningStore.ts b/src/store/hooks/useSigningStore.ts new file mode 100644 index 00000000..c88263ce --- /dev/null +++ b/src/store/hooks/useSigningStore.ts @@ -0,0 +1,35 @@ +/** + * + * @author Ray + * + * @date 2023-11-06 + * + * @workspace ray-template + * + * @remark 今天也是元气满满撸代码的一天 + */ + +import { piniaSigningStore } from '../index' + +export const useSigningGetters = () => { + const variable = piniaSigningStore() + + /** + * + * @remark 获取登陆返回信息 + */ + const getSigningCallback = computed(() => variable.signingCallback) + + return { + getSigningCallback, + } +} + +export const useSigningActions = () => { + const { signing, logout } = piniaSigningStore() + + return { + signing, + logout, + } +} diff --git a/src/store/index.ts b/src/store/index.ts index 936bc6d2..175a7ac2 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -18,10 +18,20 @@ */ import piniaPluginPersistedstate from 'pinia-plugin-persistedstate' -export { useSetting } from './modules/setting/index' // import { useSetting } from '@/store' 即可使用 -export { useMenu } from './modules/menu/index' -export { useSigning } from './modules/signing/index' -export { useKeepAlive } from './modules/keep-alive/index' +// 导出仓库实例 +export { piniaSettingStore } from './modules/setting/index' // import { piniaSettingStore } from '@/store' 即可使用 +export { piniaMenuStore } from './modules/menu/index' +export { piniaSigningStore } from './modules/signing/index' +export { piniaKeepAliveStore } from './modules/keep-alive/index' + +// 导出 getters, actions +export { useMenuGetters, useMenuActions } from './hooks/useMenuStore' +export { useSettingGetters, useSettingActions } from './hooks/useSettingStore' +export { useSigningGetters, useSigningActions } from './hooks/useSigningStore' +export { + useKeepAliveGetters, + useKeepAliveActions, +} from './hooks/useKeepAliveStore' import type { App } from 'vue' diff --git a/src/store/modules/keep-alive/index.ts b/src/store/modules/keep-alive/index.ts index 1cf41ebb..35cbe4ee 100644 --- a/src/store/modules/keep-alive/index.ts +++ b/src/store/modules/keep-alive/index.ts @@ -23,7 +23,7 @@ import { APP_KEEP_ALIVE } from '@/app-config/appConfig' import type { KeepAliveStoreState } from './type' import type { AppMenuOption } from '@/types/modules/app' -export const useKeepAlive = defineStore( +export const piniaKeepAliveStore = defineStore( 'keepAlive', () => { const { maxKeepAliveLength } = APP_KEEP_ALIVE diff --git a/src/store/modules/menu/index.ts b/src/store/modules/menu/index.ts index eb7acb7a..6ef8e418 100644 --- a/src/store/modules/menu/index.ts +++ b/src/store/modules/menu/index.ts @@ -20,6 +20,7 @@ * 缓存(sessionStorage): * - breadcrumbOptions * - menuKey + * - menuTagOptions */ import { NEllipsis } from 'naive-ui' @@ -34,9 +35,9 @@ import { } from './helper' import { useI18n } from '@/hooks/web/index' import { getAppRawRoutes } from '@/router/appRouteModules' -import { useKeepAlive } from '@/store' import { useVueRouter } from '@/hooks/web/index' import { throttle } from 'lodash-es' +import { useKeepAliveActions } from '@/store' import type { AppRouteMeta, AppRouteRecordRaw } from '@/router/type' import type { @@ -46,13 +47,13 @@ import type { } from '@/types/modules/app' import type { MenuState } from '@/store/modules/menu/type' -export const useMenu = defineStore( +export const piniaMenuStore = defineStore( 'menu', () => { const { router } = useVueRouter() const route = useRoute() const { t } = useI18n() - const { setKeepAliveInclude } = useKeepAlive() + const { setKeepAliveInclude } = useKeepAliveActions() const menuState = reactive({ menuKey: getCatchMenuKey(), // 当前菜单 `key` @@ -60,6 +61,7 @@ export const useMenu = defineStore( collapsed: false, // 是否折叠菜单 menuTagOptions: [], // tag 标签菜单 breadcrumbOptions: [], // 面包屑菜单 + currentMenuOption: null, // 当前激活菜单项 }) const isSetupAppMenuLock = ref(true) @@ -191,6 +193,8 @@ export const useMenu = defineStore( } else { setBreadcrumbOptions(menuState.menuKey || '', option) } + + menuState.currentMenuOption = option } } @@ -367,7 +371,7 @@ export const useMenu = defineStore( persist: { key: 'piniaMenuStore', storage: window.sessionStorage, - paths: ['breadcrumbOptions', 'menuKey'], + paths: ['breadcrumbOptions', 'menuKey', 'menuTagOptions'], }, }, ) diff --git a/src/store/modules/menu/type.ts b/src/store/modules/menu/type.ts index c1cc0cfc..0a5247ce 100644 --- a/src/store/modules/menu/type.ts +++ b/src/store/modules/menu/type.ts @@ -10,4 +10,5 @@ export interface MenuState { collapsed: boolean menuTagOptions: MenuTagOptions[] breadcrumbOptions: AppMenuOption[] + currentMenuOption: AppMenuOption | null } diff --git a/src/store/modules/setting/index.ts b/src/store/modules/setting/index.ts index 974a7480..c9e46776 100644 --- a/src/store/modules/setting/index.ts +++ b/src/store/modules/setting/index.ts @@ -10,7 +10,7 @@ import type { ConditionalPick } from '@/types/modules/helper' import type { SettingState } from '@/store/modules/setting/type' import type { DayjsLocal } from '@/dayjs/type' -export const useSetting = defineStore( +export const piniaSettingStore = defineStore( 'setting', () => { const { @@ -28,15 +28,12 @@ export const useSetting = defineStore( primaryColorHover: primaryColor, }, }, - themeValue: false, // `true` 为黑夜主题, `false` 为白色主题 - reloadRouteSwitch: true, // 刷新路由开关 + appTheme: false, // `true` 为黑夜主题, `false` 为白色主题 menuTagSwitch: true, // 多标签页开关 - spinSwitch: false, // 全屏加载 breadcrumbSwitch: true, // 面包屑开关 localeLanguage: getAppDefaultLanguage(), lockScreenSwitch: false, // 锁屏开关 - lockScreenInputSwitch: false, // 锁屏输入状态开关(预留该字段是为了方便拓展用, 但是舍弃了该字段, 改为使用 useAppLockScreen 方法) - footerSwitch: true, // 底部区域开关 + copyrightSwitch: true, // 底部区域开关 contentTransition: 'scale', // 切换过渡效果 watermarkSwitch: false, // 水印开关, }) diff --git a/src/store/modules/setting/type.ts b/src/store/modules/setting/type.ts index f328855e..9b3585db 100644 --- a/src/store/modules/setting/type.ts +++ b/src/store/modules/setting/type.ts @@ -4,15 +4,12 @@ import type { Placement } from '@/types/modules/component' export interface SettingState { drawerPlacement: Placement primaryColorOverride: GlobalThemeOverrides - themeValue: boolean - reloadRouteSwitch: boolean + appTheme: boolean menuTagSwitch: boolean - spinSwitch: boolean breadcrumbSwitch: boolean localeLanguage: string lockScreenSwitch: boolean - lockScreenInputSwitch: boolean watermarkSwitch: boolean - footerSwitch: boolean + copyrightSwitch: boolean contentTransition: string } diff --git a/src/store/modules/signing/index.ts b/src/store/modules/signing/index.ts index 528a4950..1d19b4cb 100644 --- a/src/store/modules/signing/index.ts +++ b/src/store/modules/signing/index.ts @@ -28,7 +28,7 @@ import type { SigningResponse, } from '@/store/modules/signing/type' -export const useSigning = defineStore( +export const piniaSigningStore = defineStore( 'signing', () => { const state = reactive({ diff --git a/src/views/demo/svg-icons/index.tsx b/src/views/demo/svg-icons/index.tsx index 6b0347e7..be070e8e 100644 --- a/src/views/demo/svg-icons/index.tsx +++ b/src/views/demo/svg-icons/index.tsx @@ -43,6 +43,7 @@ const PreviewSVGIcons = defineComponent({
`} + key={curr} > {{ diff --git a/src/views/demo/template-hooks/index.tsx b/src/views/demo/template-hooks/index.tsx new file mode 100644 index 00000000..d87265e0 --- /dev/null +++ b/src/views/demo/template-hooks/index.tsx @@ -0,0 +1,76 @@ +/** + * + * @author Ray + * + * @date 2023-11-03 + * + * @workspace ray-template + * + * @remark 今天也是元气满满撸代码的一天 + */ + +import { NSpace, NCard, NButton } from 'naive-ui' + +import { useAppMenu, useMainPage } from '@/hooks/template/index' + +export default defineComponent({ + name: 'TemplateHooks', + setup() { + const currentMenuOption = ref('') + const maximizeRef = ref(false) + + const { navigationTo } = useAppMenu() + const { reload, maximize } = useMainPage() + + return { + navigationTo, + reload, + currentMenuOption, + maximize, + maximizeRef, + } + }, + render() { + const { navigationTo, reload, maximize } = this + + return ( + + +

+ navigationTo + 参数为正整数时,会更具当前的菜单顺序进行自动导航匹配。但是此方法仅能导航一级菜单。并且如果导航菜单非根菜单项,会自动递归导航至一子菜单。 +

+
+ navigationTo(14)}>跳转至多级菜单 +
+ + +

+ 手动刷新内容区域,会使得当前路由页面内容强制重新加载(会执行完整的 + vue 生命周期)。默认 800ms 延迟。 +

+
+ { + reload() + }} + > + 刷新 + +
+ + { + this.maximizeRef = !this.maximizeRef + + maximize(this.maximizeRef) + }} + > + 最大化内容区域 + + +
+
+ ) + }, +}) diff --git a/src/views/login/components/QRCodeSignin/index.scss b/src/views/login/components/QRCodeSigning/index.scss similarity index 76% rename from src/views/login/components/QRCodeSignin/index.scss rename to src/views/login/components/QRCodeSigning/index.scss index 24e08824..30dafc15 100644 --- a/src/views/login/components/QRCodeSignin/index.scss +++ b/src/views/login/components/QRCodeSigning/index.scss @@ -1,4 +1,4 @@ -.qrcode-signin { +.qrcode-signing { width: 100%; height: 220px; @include flexCenter; diff --git a/src/views/login/components/QRCodeSignin/index.tsx b/src/views/login/components/QRCodeSigning/index.tsx similarity index 84% rename from src/views/login/components/QRCodeSignin/index.tsx rename to src/views/login/components/QRCodeSigning/index.tsx index 0118f86e..d5334fb7 100644 --- a/src/views/login/components/QRCodeSignin/index.tsx +++ b/src/views/login/components/QRCodeSigning/index.tsx @@ -22,8 +22,8 @@ import LOGO from '@/assets/images/ray.svg' * 可以根据业务需求自行更改 */ -const QRCodeSignin = defineComponent({ - name: 'QRCodeSignin', +const QRCodeSigning = defineComponent({ + name: 'QRCodeSigning', setup() { const qrcodeState = reactive({ qrcodeValue: 'https://github.com/XiaoDaiGua-Ray/xiaodaigua-ray.github.io', @@ -35,11 +35,11 @@ const QRCodeSignin = defineComponent({ }, render() { return ( -