This commit is contained in:
XiaoDaiGua-Ray 2023-11-06 17:17:44 +08:00
parent f7887989f9
commit 32183d0ab9
52 changed files with 940 additions and 332 deletions

View File

@ -1,5 +1,16 @@
# CHANGE LOG # CHANGE LOG
## 4.3.0
提供了专用于一些模板的 `hooks`,可以通过这些方法调用模板的特定功能。并且该功能后续是模板维护的重点。
改造 `pinia` 使用方式,统一使用 `xxxGetters`, `xxxActions` 去调用仓库数据与方法。
### Feats
- 新增 `store/hooks`
- 新增 `hooks/template`
## 4.2.9 ## 4.2.9
主要更新了命名问题。并且使用单词检查器,扫描整个项目替换了拼写错误的单词。 主要更新了命名问题。并且使用单词检查器,扫描整个项目替换了拼写错误的单词。

View File

@ -14,9 +14,9 @@
import { NInput, NForm, NFormItem, NButton, NSpace } from 'naive-ui' import { NInput, NForm, NFormItem, NButton, NSpace } from 'naive-ui'
import AppAvatar from '@/app-components/app/AppAvatar/index' import AppAvatar from '@/app-components/app/AppAvatar/index'
import { useSetting } from '@/store'
import useAppLockScreen from '@/app-components/app/AppLockScreen/appLockVar' import useAppLockScreen from '@/app-components/app/AppLockScreen/appLockVar'
import { rules, useCondition } from '@/app-components/app/AppLockScreen/hook' import { rules, useCondition } from '@/app-components/app/AppLockScreen/hook'
import { useSettingGetters, useSettingActions } from '@/store'
import type { FormInst, InputInst } from 'naive-ui' import type { FormInst, InputInst } from 'naive-ui'
@ -27,7 +27,7 @@ const LockScreen = defineComponent({
const inputInstRef = ref<InputInst | null>(null) const inputInstRef = ref<InputInst | null>(null)
const { setLockAppScreen } = useAppLockScreen() const { setLockAppScreen } = useAppLockScreen()
const { changeSwitcher } = useSetting() const { changeSwitcher } = useSettingActions()
const state = reactive({ const state = reactive({
lockCondition: useCondition(), lockCondition: useCondition(),

View File

@ -15,7 +15,7 @@ import { NInput, NForm, NFormItem, NButton, NSpace } from 'naive-ui'
import AppAvatar from '@/app-components/app/AppAvatar/index' import AppAvatar from '@/app-components/app/AppAvatar/index'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { useSetting, useSigning } from '@/store' import { useSigningActions, useSettingActions } from '@/store'
import { rules, useCondition } from '@/app-components/app/AppLockScreen/hook' import { rules, useCondition } from '@/app-components/app/AppLockScreen/hook'
import useAppLockScreen from '@/app-components/app/AppLockScreen/appLockVar' import useAppLockScreen from '@/app-components/app/AppLockScreen/appLockVar'
import { useDevice } from '@/hooks/web/index' import { useDevice } from '@/hooks/web/index'
@ -28,8 +28,8 @@ export default defineComponent({
const formRef = ref<FormInst | null>(null) const formRef = ref<FormInst | null>(null)
const inputInstRef = ref<InputInst | null>(null) const inputInstRef = ref<InputInst | null>(null)
const { logout } = useSigning() const { logout } = useSigningActions()
const { changeSwitcher } = useSetting() const { changeSwitcher } = useSettingActions()
const { setLockAppScreen } = useAppLockScreen() const { setLockAppScreen } = useAppLockScreen()
const { isTabletOrSmaller } = useDevice() const { isTabletOrSmaller } = useDevice()

View File

@ -21,26 +21,25 @@ import { NModal } from 'naive-ui'
import LockScreen from './components/LockScreen' import LockScreen from './components/LockScreen'
import UnlockScreen from './components/UnlockScreen' import UnlockScreen from './components/UnlockScreen'
import { useSetting } from '@/store'
import useAppLockScreen from '@/app-components/app/AppLockScreen/appLockVar' import useAppLockScreen from '@/app-components/app/AppLockScreen/appLockVar'
import { useSettingGetters } from '@/store'
const AppLockScreen = defineComponent({ const AppLockScreen = defineComponent({
name: 'AppLockScreen', name: 'AppLockScreen',
setup() { setup() {
const settingStore = useSetting() const { getLockScreenSwitch } = useSettingGetters()
const { lockScreenSwitch } = storeToRefs(settingStore)
const { getLockAppScreen } = useAppLockScreen() const { getLockAppScreen } = useAppLockScreen()
return { return {
lockScreenSwitch, getLockScreenSwitch,
getLockAppScreen, getLockAppScreen,
} }
}, },
render() { render() {
return ( return (
<NModal <NModal
v-model:show={this.lockScreenSwitch} v-model:show={this.getLockScreenSwitch}
transformOrigin="center" transformOrigin="center"
show show
autoFocus={false} autoFocus={false}

View File

@ -62,7 +62,7 @@ const RayLink = defineComponent({
return ( return (
<NSpace> <NSpace>
{this.avatarOptions.map((curr) => ( {this.avatarOptions.map((curr) => (
<NTooltip> <NTooltip key={curr.key}>
{{ {{
trigger: () => ( trigger: () => (
<NAvatar <NAvatar

View File

@ -28,22 +28,17 @@ import {
NGlobalStyle, NGlobalStyle,
} from 'naive-ui' } from 'naive-ui'
import { useSetting } from '@/store'
import { naiveLocales } from '@/locales/helper' import { naiveLocales } from '@/locales/helper'
import { useSettingGetters } from '@/store'
export default defineComponent({ export default defineComponent({
name: 'GlobalProvider', name: 'GlobalProvider',
setup(_, { expose }) { setup(_, { expose }) {
const settingStore = useSetting() const { getPrimaryColorOverride, getAppTheme, getLocaleLanguage } =
useSettingGetters()
const modelPrimaryColorOverride = computed(
() => settingStore.primaryColorOverride,
)
const modelThemeValue = computed(() =>
settingStore.themeValue ? darkTheme : null,
)
const localePackage = computed(() => { const localePackage = computed(() => {
const key = settingStore.localeLanguage const key = getLocaleLanguage.value
return naiveLocales(key) return naiveLocales(key)
}) })
@ -52,7 +47,7 @@ export default defineComponent({
['message', 'dialog', 'notification', 'loadingBar'], ['message', 'dialog', 'notification', 'loadingBar'],
{ {
configProviderProps: computed(() => ({ configProviderProps: computed(() => ({
theme: modelThemeValue.value, theme: getAppTheme.value ? darkTheme : null,
})), })),
notificationProviderProps: {}, notificationProviderProps: {},
}, },
@ -66,16 +61,16 @@ export default defineComponent({
expose() expose()
return { return {
modelPrimaryColorOverride, getPrimaryColorOverride,
modelThemeValue,
localePackage, localePackage,
getAppTheme,
} }
}, },
render() { render() {
return ( return (
<NConfigProvider <NConfigProvider
themeOverrides={this.modelPrimaryColorOverride} themeOverrides={this.getPrimaryColorOverride}
theme={this.modelThemeValue} theme={this.getAppTheme ? darkTheme : null}
locale={this.localePackage.locale} locale={this.localePackage.locale}
dateLocale={this.localePackage.dateLocal} dateLocale={this.localePackage.dateLocal}
> >

View File

@ -13,17 +13,15 @@ import './index.scss'
import { getStorage } from '@/utils/cache' import { getStorage } from '@/utils/cache'
import { get } from 'lodash-es' import { get } from 'lodash-es'
import { useSetting } from '@/store'
import { addClass, removeClass, addStyle, colorToRgba } from '@/utils/element' import { addClass, removeClass, addStyle, colorToRgba } from '@/utils/element'
import { useSettingGetters } from '@/store'
import type { SettingState } from '@/store/modules/setting/type' import type { SettingState } from '@/store/modules/setting/type'
const AppStyleProvider = defineComponent({ const AppStyleProvider = defineComponent({
name: 'AppStyleProvider', name: 'AppStyleProvider',
setup(_, { expose }) { setup(_, { expose }) {
const settingStore = useSetting() const { getAppTheme } = useSettingGetters()
const { themeValue } = storeToRefs(settingStore)
/** 同步主题色变量至 body, 如果未获取到缓存值则已默认值填充 */ /** 同步主题色变量至 body, 如果未获取到缓存值则已默认值填充 */
const syncPrimaryColorToBody = () => { const syncPrimaryColorToBody = () => {
@ -72,7 +70,7 @@ const AppStyleProvider = defineComponent({
* *
* body class * body class
* *
* themeValue * getAppTheme
*/ */
const body = document.body const body = document.body
const darkClassName = 'ray-template--dark' const darkClassName = 'ray-template--dark'
@ -89,7 +87,7 @@ const AppStyleProvider = defineComponent({
hiddenLoadingAnimation() hiddenLoadingAnimation()
watch( watch(
() => themeValue.value, () => getAppTheme.value,
(ndata) => { (ndata) => {
updateGlobalThemeClass(ndata) updateGlobalThemeClass(ndata)
}, },

View File

@ -12,19 +12,19 @@
import { NWatermark } from 'naive-ui' import { NWatermark } from 'naive-ui'
import { APP_WATERMARK_CONFIG } from '@/app-config/appConfig' import { APP_WATERMARK_CONFIG } from '@/app-config/appConfig'
import { useSetting } from '@/store' import { useSettingGetters } from '@/store'
export default defineComponent({ export default defineComponent({
name: 'AppWatermarkProvider', name: 'AppWatermarkProvider',
setup() { setup() {
const { watermarkSwitch } = storeToRefs(useSetting()) const { getWatermarkSwitch } = useSettingGetters()
return { return {
watermarkSwitch, getWatermarkSwitch,
} }
}, },
render() { render() {
return this.watermarkSwitch ? ( return this.getWatermarkSwitch ? (
<NWatermark cross fullscreen {...APP_WATERMARK_CONFIG} /> <NWatermark cross fullscreen {...APP_WATERMARK_CONFIG} />
) : null ) : null
}, },

View File

@ -40,7 +40,6 @@ import { CanvasRenderer } from 'echarts/renderers' // `echarts` 渲染器
import { NCard } from 'naive-ui' import { NCard } from 'naive-ui'
import props from './props' import props from './props'
import { useSetting } from '@/store'
import { throttle } from 'lodash-es' import { throttle } from 'lodash-es'
import { completeSize } from '@/utils/element' import { completeSize } from '@/utils/element'
import { call } from '@/utils/vue/index' import { call } from '@/utils/vue/index'
@ -50,6 +49,7 @@ import { useResizeObserver } from '@vueuse/core'
import RMoreDropdown from '@/components/RMoreDropdown/index' import RMoreDropdown from '@/components/RMoreDropdown/index'
import { renderNode } from '@use-utils/vue/index' import { renderNode } from '@use-utils/vue/index'
import { downloadBase64File } from '@use-utils/basic' import { downloadBase64File } from '@use-utils/basic'
import { useSettingGetters } from '@/store'
import type { WatchStopHandle } from 'vue' import type { WatchStopHandle } from 'vue'
import type { AnyFC } from '@/types/modules/utils' import type { AnyFC } from '@/types/modules/utils'
@ -70,8 +70,7 @@ export default defineComponent({
name: 'RChart', name: 'RChart',
props, props,
setup(props, { expose }) { setup(props, { expose }) {
const settingStore = useSetting() const { getAppTheme } = useSettingGetters()
const { themeValue: currentTheme } = storeToRefs(settingStore)
const rayChartRef = ref<HTMLElement>() // echart 容器实例 const rayChartRef = ref<HTMLElement>() // echart 容器实例
const rayChartWrapperRef = ref<HTMLElement>() const rayChartWrapperRef = ref<HTMLElement>()
const echartInstanceRef = ref<ECharts>() // echart 实例 const echartInstanceRef = ref<ECharts>() // echart 实例
@ -153,7 +152,7 @@ export default defineComponent({
if (!props.theme) { if (!props.theme) {
const theme = props.autoChangeTheme const theme = props.autoChangeTheme
? currentTheme.value ? getAppTheme.value
? `${echartTheme}-dark` ? `${echartTheme}-dark`
: echartTheme : echartTheme
: echartTheme : echartTheme
@ -295,7 +294,7 @@ export default defineComponent({
// 避免重复渲染 // 避免重复渲染
if (echartInst?.getDom()) { if (echartInst?.getDom()) {
console.warn( 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 return
@ -326,7 +325,7 @@ export default defineComponent({
/** 监听全局主题变化, 然后重新渲染对应主题 echarts */ /** 监听全局主题变化, 然后重新渲染对应主题 echarts */
watch( watch(
() => currentTheme.value, () => getAppTheme.value,
() => { () => {
/** /**
* *

View File

@ -11,7 +11,7 @@
<KeepAlive <KeepAlive
v-if="setupKeepAlive" v-if="setupKeepAlive"
:max="maxKeepAliveLength" :max="maxKeepAliveLength"
:include="keepAliveInclude" :include="getKeepAliveInclude"
:exclude="keepAliveExclude" :exclude="keepAliveExclude"
> >
<Component :is="Component" :key="route.fullPath" /> <Component :is="Component" :key="route.fullPath" />
@ -23,7 +23,7 @@
</RouterView> </RouterView>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { useKeepAlive } from '@/store' import { useKeepAliveGetters } from '@/store'
import { APP_KEEP_ALIVE } from '@/app-config/appConfig' import { APP_KEEP_ALIVE } from '@/app-config/appConfig'
import type { TransitionProps } from './type' import type { TransitionProps } from './type'
@ -42,7 +42,6 @@ withDefaults(defineProps<TransitionProps>(), {
transitionAppear: true, transitionAppear: true,
}) })
const keepAliveStore = useKeepAlive() const { getKeepAliveInclude } = useKeepAliveGetters()
const { keepAliveInclude } = storeToRefs(keepAliveStore)
const { setupKeepAlive, maxKeepAliveLength, keepAliveExclude } = APP_KEEP_ALIVE const { setupKeepAlive, maxKeepAliveLength, keepAliveExclude } = APP_KEEP_ALIVE
</script> </script>

View File

@ -32,6 +32,8 @@ import type { AnyFC } from '@/types/modules/utils'
const variableState = reactive({ const variableState = reactive({
globalSpinning: false, globalSpinning: false,
globalDrawerValue: false, globalDrawerValue: false,
globalMainLayoutLoad: true,
layoutContentMaximize: false,
}) })
export type VariableState = typeof variableState export type VariableState = typeof variableState

View File

@ -0,0 +1,5 @@
import { useAppMenu } from './useAppMenu'
import { useMainPage } from './useMainPage'
import { useMenuTag } from './useMenuTag'
export { useAppMenu, useMainPage, useMenuTag }

View File

@ -0,0 +1,82 @@
/**
*
* @author Ray <https://github.com/XiaoDaiGua-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,
}
}

View File

@ -0,0 +1,35 @@
/**
*
* @author Ray <https://github.com/XiaoDaiGua-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,
}
}

View File

@ -0,0 +1,165 @@
/**
*
* @author Ray <https://github.com/XiaoDaiGua-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,
}
}

View File

@ -14,10 +14,10 @@ import './index.scss'
import { NMenu, NLayoutSider, NDrawer } from 'naive-ui' import { NMenu, NLayoutSider, NDrawer } from 'naive-ui'
import SiderBarLogo from './components/SiderBarLogo/index' import SiderBarLogo from './components/SiderBarLogo/index'
import { useMenu } from '@/store'
import { APP_MENU_CONFIG } from '@/app-config/appConfig' import { APP_MENU_CONFIG } from '@/app-config/appConfig'
import { useDevice } from '@/hooks/web/index' import { useDevice } from '@/hooks/web/index'
import { getVariableToRefs, setVariable } from '@/global-variable/index' import { getVariableToRefs, setVariable } from '@/global-variable/index'
import { useMenuGetters, useMenuActions } from '@/store'
import type { MenuInst } from 'naive-ui' import type { MenuInst } from 'naive-ui'
import type { NaiveMenuOptions } from '@/types/modules/component' import type { NaiveMenuOptions } from '@/types/modules/component'
@ -28,16 +28,16 @@ export default defineComponent({
setup() { setup() {
const menuRef = ref<MenuInst | null>(null) const menuRef = ref<MenuInst | null>(null)
const menuStore = useMenu() const { changeMenuModelValue, collapsedMenu } = useMenuActions()
const { getMenuOptions, getCollapsed, getMenuKey } = useMenuGetters()
const { changeMenuModelValue, collapsedMenu } = menuStore
const modelMenuKey = computed({ const modelMenuKey = computed({
get: () => { get: () => {
nextTick().then(() => { nextTick().then(() => {
showMenuOption() showMenuOption()
}) })
return menuStore.menuKey return getMenuKey.value
}, },
set: () => { set: () => {
if (isTabletOrSmaller.value) { if (isTabletOrSmaller.value) {
@ -45,8 +45,6 @@ export default defineComponent({
} }
}, },
}) })
const modelMenuOptions = computed(() => menuStore.options)
const modelCollapsed = computed(() => menuStore.collapsed)
const { isTabletOrSmaller } = useDevice() const { isTabletOrSmaller } = useDevice()
const modelGlobalDrawerValue = computed({ const modelGlobalDrawerValue = computed({
get: () => getVariableToRefs('globalDrawerValue').value, get: () => getVariableToRefs('globalDrawerValue').value,
@ -72,14 +70,14 @@ export default defineComponent({
onUpdateCollapsed={collapsedMenu.bind(this)} onUpdateCollapsed={collapsedMenu.bind(this)}
nativeScrollbar={false} nativeScrollbar={false}
> >
<SiderBarLogo collapsed={modelCollapsed.value} /> <SiderBarLogo collapsed={getCollapsed.value} />
<NMenu <NMenu
ref="menuRef" ref={menuRef}
class="r-menu--app" class="r-menu--app"
v-model:value={modelMenuKey.value} v-model:value={modelMenuKey.value}
options={modelMenuOptions.value as NaiveMenuOptions[]} options={getMenuOptions.value as NaiveMenuOptions[]}
indent={APP_MENU_CONFIG.menuCollapsedIndent} indent={APP_MENU_CONFIG.menuCollapsedIndent}
collapsed={modelCollapsed.value} collapsed={getCollapsed.value}
collapsedIconSize={APP_MENU_CONFIG.menuCollapsedIconSize} collapsedIconSize={APP_MENU_CONFIG.menuCollapsedIconSize}
collapsedWidth={APP_MENU_CONFIG.menuCollapsedWidth} collapsedWidth={APP_MENU_CONFIG.menuCollapsedWidth}
onUpdateValue={(key, op) => { onUpdateValue={(key, op) => {
@ -91,7 +89,6 @@ export default defineComponent({
) )
return { return {
menuRef,
isTabletOrSmaller, isTabletOrSmaller,
BasicMenu: BasicMenu, BasicMenu: BasicMenu,
modelGlobalDrawerValue, modelGlobalDrawerValue,

View File

@ -29,15 +29,17 @@ import { NScrollbar, NTag, NSpace, NLayoutHeader, NDropdown } from 'naive-ui'
import RIcon from '@/components/RIcon/index' import RIcon from '@/components/RIcon/index'
import RMoreDropdown from '@/components/RMoreDropdown/index' import RMoreDropdown from '@/components/RMoreDropdown/index'
import { useMenu, useSetting } from '@/store' import { useMenuGetters, useMenuActions } from '@/store'
import { uuid } from '@/utils/basic' import { uuid } from '@/utils/basic'
import { hasClass } from '@/utils/element' import { hasClass } from '@/utils/element'
import { redirectRouterToDashboard } from '@/router/helper/routerCopilot' import { redirectRouterToDashboard } from '@/router/helper/routerCopilot'
import { ROOT_ROUTE } from '@/app-config/appConfig' import { ROOT_ROUTE } from '@/app-config/appConfig'
import { queryElements } from '@use-utils/element' import { queryElements } from '@use-utils/element'
import { renderNode } from '@/utils/vue/index' 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' import type { MenuTagOptions, AppMenuOption } from '@/types/modules/app'
export default defineComponent({ export default defineComponent({
@ -45,43 +47,28 @@ export default defineComponent({
setup(_, { expose }) { setup(_, { expose }) {
const scrollRef = ref<ScrollbarInst | null>(null) const scrollRef = ref<ScrollbarInst | null>(null)
const menuStore = useMenu() const { getMenuKey, getMenuTagOptions } = useMenuGetters()
const settingStore = useSetting()
const { menuKey, menuTagOptions } = storeToRefs(menuStore)
const { const {
changeMenuModelValue, changeMenuModelValue,
spliceMenTagOptions, spliceMenTagOptions,
emptyMenuTagOptions, emptyMenuTagOptions,
setMenuTagOptions, setMenuTagOptions,
} = menuStore } = useMenuActions()
const { changeSwitcher } = settingStore
const { path } = ROOT_ROUTE const { path } = ROOT_ROUTE
const { reload } = useMainPage()
const {
close,
closeAll: $closeAll,
closeRight: $closeRight,
closeLeft: $closeLeft,
closeOther: $closeOther,
} = useMenuTag()
const exclude = ['closeAll', 'closeRight', 'closeLeft', 'closeOther'] const exclude = ['closeAll', 'closeRight', 'closeLeft', 'closeOther']
let currentContextmenuIndex = -1 // 当前右键标签页索引位置 let currentContextmenuIndex = -1 // 当前右键标签页索引位置
const iconConfig = { const iconConfig = {
size: 16, 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([ const moreOptions = ref([
{ {
label: '重新加载', label: '重新加载',
@ -154,58 +141,22 @@ export default defineComponent({
disabled: false, disabled: false,
}, },
]) ])
const scrollBarUUID = uuid(16) const uuidScrollBar = uuid(16)
const actionMap = { const actionMap = {
reloadCurrentPage: () => { reloadCurrentPage: () => {
changeSwitcher(false, 'reloadRouteSwitch') reload()
setTimeout(() => changeSwitcher(true, 'reloadRouteSwitch'))
}, },
closeAll: () => { closeAll: () => {
/** $closeAll()
*
* , (dashboard)
* ,
*/
if (moreOptions.value.length > 1) {
emptyMenuTagOptions()
redirectRouterToDashboard(true)
}
}, },
closeRight: () => { closeRight: () => {
/** $closeRight(currentContextmenuIndex)
*
*
*
* 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)
}
}, },
closeLeft: () => { closeLeft: () => {
spliceMenTagOptions(0, currentContextmenuIndex) $closeLeft(currentContextmenuIndex)
}, },
closeOther: () => { closeOther: () => {
/** $closeOther(currentContextmenuIndex)
*
*
*
* menuKey ,
*/
const routeItem = modelMenuTagOptions.value[currentContextmenuIndex]
if (menuKey.value !== routeItem.key) {
emptyMenuTagOptions()
changeMenuModelValue(routeItem.key, routeItem)
} else {
setMenuTagOptions(routeItem, false)
}
}, },
} }
/** 右键菜单 */ /** 右键菜单 */
@ -223,16 +174,7 @@ export default defineComponent({
* @remark `tag` , * @remark `tag` ,
*/ */
const closeCurrentMenuTag = (idx: number) => { const closeCurrentMenuTag = (idx: number) => {
spliceMenTagOptions(idx) close(idx)
if (menuKey.value !== path) {
const options = modelMenuTagOptions.value
const length = options.length
const tag = options[length - 1]
changeMenuModelValue(tag.key as string, tag)
}
} }
const setMoreOptionsDisabled = ( const setMoreOptionsDisabled = (
@ -257,7 +199,7 @@ export default defineComponent({
} }
const getScrollElement = () => { const getScrollElement = () => {
const scroll = document.getElementById(scrollBarUUID) // 获取滚动条容器 const scroll = document.getElementById(uuidScrollBar) // 获取滚动条容器
if (scroll) { if (scroll) {
const scrollContentElement = Array.from( const scrollContentElement = Array.from(
@ -320,7 +262,7 @@ export default defineComponent({
} }
const setDisabledAccordionToIndex = () => { const setDisabledAccordionToIndex = () => {
const length = modelMenuTagOptions.value.length - 1 const length = getMenuTagOptions.value.length - 1
if (currentContextmenuIndex === length) { if (currentContextmenuIndex === length) {
setMoreOptionsDisabled('closeRight', true) setMoreOptionsDisabled('closeRight', true)
@ -342,8 +284,8 @@ export default defineComponent({
* *
*/ */
const setCurrentContextmenuIndex = () => { const setCurrentContextmenuIndex = () => {
const index = modelMenuTagOptions.value.findIndex( const index = getMenuTagOptions.value.findIndex(
(curr) => curr.key === menuKey.value, (curr) => curr.key === getMenuKey.value,
) )
currentContextmenuIndex = index currentContextmenuIndex = index
@ -351,16 +293,16 @@ export default defineComponent({
setDisabledAccordionToIndex() setDisabledAccordionToIndex()
} }
/** 仅有 modelMenuTagOptions 长度大于 1 并且非 root path 时, 才激活关闭按钮 */ /** 仅有 getMenuTagOptions 长度大于 1 并且非 root path 时, 才激活关闭按钮 */
const menuTagMouseenter = (option: MenuTagOptions) => { const menuTagMouseenter = (option: MenuTagOptions) => {
if (modelMenuTagOptions.value.length > 1 && option.key !== path) { if (getMenuTagOptions.value.length > 1 && option.key !== path) {
option.closeable = true option.closeable = true
} }
} }
/** 移出 MenuTag 时, 判断是否为当前已激活 key */ /** 移出 MenuTag 时, 判断是否为当前已激活 key */
const menuTagMouseleave = (option: MenuTagOptions) => { const menuTagMouseleave = (option: MenuTagOptions) => {
if (option.key !== menuKey.value) { if (option.key !== getMenuKey.value) {
option.closeable = false option.closeable = false
} }
} }
@ -387,7 +329,7 @@ export default defineComponent({
const positionMenuTag = () => { const positionMenuTag = () => {
nextTick().then(() => { nextTick().then(() => {
const tags = queryElements<HTMLElement>( const tags = queryElements<HTMLElement>(
`attr:${MENU_TAG_DATA}="${menuKey.value}"`, `attr:${MENU_TAG_DATA}="${getMenuKey.value}"`,
) )
if (tags?.length) { if (tags?.length) {
@ -402,7 +344,7 @@ export default defineComponent({
/** 如果有且只有一个标签页时, 禁止全部关闭操作 */ /** 如果有且只有一个标签页时, 禁止全部关闭操作 */
watch( watch(
() => modelMenuTagOptions.value, () => getMenuTagOptions.value,
(newData, oldData) => { (newData, oldData) => {
moreOptions.value.forEach((curr) => { moreOptions.value.forEach((curr) => {
if (exclude.includes(curr.key)) { if (exclude.includes(curr.key)) {
@ -436,15 +378,15 @@ export default defineComponent({
expose({}) expose({})
return { return {
modelMenuTagOptions, getMenuTagOptions,
changeMenuModelValue, changeMenuModelValue,
closeCurrentMenuTag, closeCurrentMenuTag,
menuKey, getMenuKey,
handleTagClick, handleTagClick,
moreOptions, moreOptions,
scrollX, scrollX,
scrollRef, scrollRef,
scrollBarUUID, uuidScrollBar,
actionDropdownSelect, actionDropdownSelect,
rootPath: path, rootPath: path,
actionState, actionState,
@ -495,7 +437,7 @@ export default defineComponent({
xScrollable xScrollable
ref="scrollRef" ref="scrollRef"
{...{ {...{
id: this.scrollBarUUID, id: this.uuidScrollBar,
}} }}
> >
<NSpace <NSpace
@ -504,13 +446,14 @@ export default defineComponent({
align="center" align="center"
justify="start" justify="start"
> >
{this.modelMenuTagOptions.map((curr, idx) => ( {this.getMenuTagOptions.map((curr, idx) => (
<NTag <NTag
key={curr.key}
size="large" size="large"
strong strong
closable={curr.closeable} closable={curr.closeable}
onClose={this.closeCurrentMenuTag.bind(this, idx)} onClose={this.closeCurrentMenuTag.bind(this, idx)}
type={curr.key === this.menuKey ? 'primary' : 'default'} type={curr.key === this.getMenuKey ? 'primary' : 'default'}
bordered={false} bordered={false}
{...{ {...{
onClick: this.handleTagClick.bind(this, curr), onClick: this.handleTagClick.bind(this, curr),
@ -520,7 +463,7 @@ export default defineComponent({
[this.MENU_TAG_DATA]: curr.path, [this.MENU_TAG_DATA]: curr.path,
}} }}
> >
{renderNode(curr.label)} {renderNode(curr.breadcrumbLabel)}
</NTag> </NTag>
))} ))}
</NSpace> </NSpace>

View File

@ -20,24 +20,17 @@
import { NDropdown, NBreadcrumb, NBreadcrumbItem } from 'naive-ui' import { NDropdown, NBreadcrumb, NBreadcrumbItem } from 'naive-ui'
import { useMenu } from '@/store' import { useMenuGetters, useMenuActions } from '@/store'
import { useDevice } from '@/hooks/web/index' import { useDevice } from '@/hooks/web/index'
import type { DropdownOption } from 'naive-ui' import type { DropdownOption } from 'naive-ui'
import type { import type { AppMenuOption } from '@/types/modules/app'
AppMenuOption,
MenuTagOptions,
AppMenuKey,
} from '@/types/modules/app'
export default defineComponent({ export default defineComponent({
name: 'RBreadcrumb', name: 'RBreadcrumb',
setup() { setup() {
const menuStore = useMenu() const { changeMenuModelValue } = useMenuActions()
const { getBreadcrumbOptions } = useMenuGetters()
const { changeMenuModelValue } = menuStore
const { breadcrumbOptions } = storeToRefs(menuStore)
const modelBreadcrumbOptions = computed(() => breadcrumbOptions.value)
const { isTabletOrSmaller } = useDevice() const { isTabletOrSmaller } = useDevice()
const dropdownSelect = (key: string | number, option: DropdownOption) => { const dropdownSelect = (key: string | number, option: DropdownOption) => {
@ -55,7 +48,7 @@ export default defineComponent({
} }
return { return {
modelBreadcrumbOptions, getBreadcrumbOptions,
dropdownSelect, dropdownSelect,
breadcrumbItemClick, breadcrumbItemClick,
isTabletOrSmaller, isTabletOrSmaller,
@ -68,7 +61,7 @@ export default defineComponent({
<div></div> <div></div>
) : ( ) : (
<NBreadcrumb> <NBreadcrumb>
{this.modelBreadcrumbOptions.map((curr) => ( {this.getBreadcrumbOptions.map((curr) => (
<NBreadcrumbItem <NBreadcrumbItem
key={curr.key} key={curr.key}
onClick={this.breadcrumbItemClick.bind(this, curr)} onClick={this.breadcrumbItemClick.bind(this, curr)}

View File

@ -11,20 +11,12 @@
import './index.scss' import './index.scss'
import { import { NInput, NModal, NResult, NScrollbar, NSpace } from 'naive-ui'
NInput,
NModal,
NResult,
NScrollbar,
NSpace,
NDivider,
NButton,
} from 'naive-ui'
import RIcon from '@/components/RIcon/index' import RIcon from '@/components/RIcon/index'
import { on, off, queryElements, addClass, removeClass } from '@/utils/element' import { on, off, queryElements, addClass, removeClass } from '@/utils/element'
import { debounce } from 'lodash-es' import { debounce } from 'lodash-es'
import { useMenu } from '@/store' import { useMenuGetters, useMenuActions } from '@/store'
import { validMenuItemShow } from '@/router/helper/routerCopilot' import { validMenuItemShow } from '@/router/helper/routerCopilot'
import { useDevice } from '@/hooks/web/index' import { useDevice } from '@/hooks/web/index'
@ -41,9 +33,7 @@ export default defineComponent({
}, },
emits: ['update:show'], emits: ['update:show'],
setup(props, { emit }) { setup(props, { emit }) {
const menuStore = useMenu() const { changeMenuModelValue } = useMenuActions()
const { changeMenuModelValue } = menuStore
const modelShow = computed({ const modelShow = computed({
get: () => props.show, get: () => props.show,
set: (val) => { set: (val) => {
@ -54,7 +44,8 @@ export default defineComponent({
} }
}, },
}) })
const modelMenuOptions = computed(() => menuStore.options) const { getMenuOptions } = useMenuGetters()
const state = reactive({ const state = reactive({
searchValue: null, searchValue: null,
searchOptions: [] as AppMenuOption[], searchOptions: [] as AppMenuOption[],
@ -131,7 +122,7 @@ export default defineComponent({
} }
if (value) { if (value) {
filterArr(modelMenuOptions.value) filterArr(getMenuOptions.value)
state.searchOptions = arr state.searchOptions = arr
} else { } else {
@ -326,7 +317,7 @@ export default defineComponent({
{searchOptions.length ? ( {searchOptions.length ? (
<NSpace vertical wrapItem={false} size={[8, 8]}> <NSpace vertical wrapItem={false} size={[8, 8]}>
{searchOptions.map((curr) => ( {searchOptions.map((curr) => (
<SearchItem menuOption={curr} /> <SearchItem menuOption={curr} key={curr.key} />
))} ))}
</NSpace> </NSpace>
) : ( ) : (
@ -355,7 +346,7 @@ export default defineComponent({
size={[24, 8]} size={[24, 8]}
> >
{this.helperTipOptions.map((curr) => ( {this.helperTipOptions.map((curr) => (
<div class="tip-wrapper-item"> <div class="tip-wrapper-item" key={curr.label}>
<div class="item-icon"> <div class="item-icon">
{curr.plain ? ( {curr.plain ? (
<span>{curr.icon}</span> <span>{curr.icon}</span>

View File

@ -12,14 +12,13 @@
import { NSpace, NSwitch, NTooltip } from 'naive-ui' import { NSpace, NSwitch, NTooltip } from 'naive-ui'
import RIcon from '@/components/RIcon' import RIcon from '@/components/RIcon'
import { useSetting } from '@/store' import { useSettingGetters, useSettingActions } from '@/store'
const ThemeSwitch = defineComponent({ const ThemeSwitch = defineComponent({
name: 'ThemeSwitch', name: 'ThemeSwitch',
setup() { setup() {
const settingStore = useSetting() const { changeSwitcher } = useSettingActions()
const { changeSwitcher } = settingStore const { getAppTheme } = useSettingGetters()
const { themeValue } = storeToRefs(settingStore)
const handleRailStyle = ({ checked }: { checked: boolean }) => { const handleRailStyle = ({ checked }: { checked: boolean }) => {
return checked return checked
@ -33,7 +32,7 @@ const ThemeSwitch = defineComponent({
return { return {
changeSwitcher, changeSwitcher,
themeValue, getAppTheme,
handleRailStyle, handleRailStyle,
} }
}, },
@ -46,10 +45,10 @@ const ThemeSwitch = defineComponent({
{{ {{
trigger: () => ( trigger: () => (
<NSwitch <NSwitch
v-model:value={this.themeValue} v-model:value={this.getAppTheme}
railStyle={this.handleRailStyle.bind(this)} railStyle={this.handleRailStyle.bind(this)}
onUpdateValue={(bool: boolean) => onUpdateValue={(bool: boolean) =>
this.changeSwitcher(bool, 'themeValue') this.changeSwitcher(bool, 'appTheme')
} }
> >
{{ {{
@ -75,7 +74,7 @@ const ThemeSwitch = defineComponent({
</NSwitch> </NSwitch>
), ),
default: () => default: () =>
this.themeValue this.getAppTheme
? $t('headerSettingOptions.ThemeOptions.Dark') ? $t('headerSettingOptions.ThemeOptions.Dark')
: $t('headerSettingOptions.ThemeOptions.Light'), : $t('headerSettingOptions.ThemeOptions.Light'),
}} }}

View File

@ -14,7 +14,7 @@ import {
import ThemeSwitch from '@/layout/components/SiderBar/components/SettingDrawer/components/ThemeSwitch/index' import ThemeSwitch from '@/layout/components/SiderBar/components/SettingDrawer/components/ThemeSwitch/index'
import { APP_THEME } from '@/app-config/designConfig' import { APP_THEME } from '@/app-config/designConfig'
import { useSetting } from '@/store' import { useSettingGetters, useSettingActions } from '@/store'
import type { PropType } from 'vue' import type { PropType } from 'vue'
import type { Placement } from '@/types/modules/component' import type { Placement } from '@/types/modules/component'
@ -37,19 +37,17 @@ const SettingDrawer = defineComponent({
}, },
emits: ['update:show'], emits: ['update:show'],
setup(props, { emit }) { setup(props, { emit }) {
const settingStore = useSetting()
const { changePrimaryColor, changeSwitcher, updateContentTransition } = const { changePrimaryColor, changeSwitcher, updateContentTransition } =
settingStore useSettingActions()
const { const {
themeValue, getAppTheme,
primaryColorOverride, getPrimaryColorOverride,
menuTagSwitch, getMenuTagSwitch,
breadcrumbSwitch, getBreadcrumbSwitch,
footerSwitch, getCopyrightSwitch,
contentTransition, getContentTransition,
watermarkSwitch, getWatermarkSwitch,
} = storeToRefs(settingStore) } = useSettingGetters()
const modelShow = computed({ const modelShow = computed({
get: () => props.show, get: () => props.show,
@ -79,16 +77,16 @@ const SettingDrawer = defineComponent({
return { return {
modelShow, modelShow,
changePrimaryColor, changePrimaryColor,
themeValue, getAppTheme,
primaryColorOverride, getPrimaryColorOverride,
menuTagSwitch, getMenuTagSwitch,
changeSwitcher, changeSwitcher,
breadcrumbSwitch, getBreadcrumbSwitch,
footerSwitch, getCopyrightSwitch,
contentTransitionOptions, contentTransitionOptions,
contentTransition, getContentTransition,
updateContentTransition, updateContentTransition,
watermarkSwitch, getWatermarkSwitch,
} }
}, },
render() { render() {
@ -111,14 +109,14 @@ const SettingDrawer = defineComponent({
</NDivider> </NDivider>
<NColorPicker <NColorPicker
swatches={APP_THEME.appThemeColors} swatches={APP_THEME.appThemeColors}
v-model:value={this.primaryColorOverride.common!.primaryColor} v-model:value={this.getPrimaryColorOverride.common!.primaryColor}
onUpdateValue={this.changePrimaryColor.bind(this)} onUpdateValue={this.changePrimaryColor.bind(this)}
/> />
<NDivider titlePlacement="center"> <NDivider titlePlacement="center">
{$t('headerSettingOptions.ContentTransition')} {$t('headerSettingOptions.ContentTransition')}
</NDivider> </NDivider>
<NSelect <NSelect
v-model:value={this.contentTransition} v-model:value={this.getContentTransition}
options={this.contentTransitionOptions} options={this.contentTransitionOptions}
onUpdateValue={(value) => { onUpdateValue={(value) => {
this.updateContentTransition(value) this.updateContentTransition(value)
@ -130,7 +128,7 @@ const SettingDrawer = defineComponent({
<NDescriptions labelPlacement="left" column={1}> <NDescriptions labelPlacement="left" column={1}>
<NDescriptionsItem label="多标签"> <NDescriptionsItem label="多标签">
<NSwitch <NSwitch
v-model:value={this.menuTagSwitch} v-model:value={this.getMenuTagSwitch}
onUpdateValue={(bool: boolean) => onUpdateValue={(bool: boolean) =>
this.changeSwitcher(bool, 'menuTagSwitch') this.changeSwitcher(bool, 'menuTagSwitch')
} }
@ -138,7 +136,7 @@ const SettingDrawer = defineComponent({
</NDescriptionsItem> </NDescriptionsItem>
<NDescriptionsItem label="面包屑"> <NDescriptionsItem label="面包屑">
<NSwitch <NSwitch
v-model:value={this.breadcrumbSwitch} v-model:value={this.getBreadcrumbSwitch}
onUpdateValue={(bool: boolean) => onUpdateValue={(bool: boolean) =>
this.changeSwitcher(bool, 'breadcrumbSwitch') this.changeSwitcher(bool, 'breadcrumbSwitch')
} }
@ -146,7 +144,7 @@ const SettingDrawer = defineComponent({
</NDescriptionsItem> </NDescriptionsItem>
<NDescriptionsItem label="水印"> <NDescriptionsItem label="水印">
<NSwitch <NSwitch
v-model:value={this.watermarkSwitch} v-model:value={this.getWatermarkSwitch}
onUpdateValue={(bool: boolean) => onUpdateValue={(bool: boolean) =>
this.changeSwitcher(bool, 'watermarkSwitch') this.changeSwitcher(bool, 'watermarkSwitch')
} }
@ -154,9 +152,9 @@ const SettingDrawer = defineComponent({
</NDescriptionsItem> </NDescriptionsItem>
<NDescriptionsItem label="版权信息"> <NDescriptionsItem label="版权信息">
<NSwitch <NSwitch
v-model:value={this.footerSwitch} v-model:value={this.getCopyrightSwitch}
onUpdateValue={(bool: boolean) => onUpdateValue={(bool: boolean) =>
this.changeSwitcher(bool, 'footerSwitch') this.changeSwitcher(bool, 'copyrightSwitch')
} }
/> />
</NDescriptionsItem> </NDescriptionsItem>

View File

@ -1,5 +1,9 @@
import { useSetting, useSigning } from '@/store'
import { useI18n } from '@/hooks/web/index' import { useI18n } from '@/hooks/web/index'
import {
useSigningActions,
useSigningGetters,
useSettingActions,
} from '@/store'
import type { IconOptionsFC, IconOptions } from './type' import type { IconOptionsFC, IconOptions } from './type'
@ -24,8 +28,7 @@ export const createAvatarOptions = () => [
const avatarDropdownActionMap = { const avatarDropdownActionMap = {
logout: () => { logout: () => {
const signingStore = useSigning() const { logout } = useSigningActions()
const { logout } = signingStore
window.$dialog.warning({ window.$dialog.warning({
title: '提示', title: '提示',
@ -38,8 +41,7 @@ const avatarDropdownActionMap = {
}) })
}, },
lockScreen: () => { lockScreen: () => {
const settingStore = useSetting() const { changeSwitcher } = useSettingActions()
const { changeSwitcher } = settingStore
changeSwitcher(true, 'lockScreenSwitch') changeSwitcher(true, 'lockScreenSwitch')
}, },
@ -52,7 +54,7 @@ export const avatarDropdownClick = (key: string | number) => {
} }
export const createLeftIconOptions = (opts: IconOptionsFC) => { export const createLeftIconOptions = (opts: IconOptionsFC) => {
const { isTabletOrSmaller, reloadRouteSwitch } = opts const { isTabletOrSmaller, globalMainLayoutLoad } = opts
const { t } = useI18n() const { t } = useI18n()
const notTableOrSmallerOptions: IconOptions[] = [ const notTableOrSmallerOptions: IconOptions[] = [
@ -60,7 +62,7 @@ export const createLeftIconOptions = (opts: IconOptionsFC) => {
name: 'reload', name: 'reload',
size: 18, size: 18,
tooltip: t('headerTooltip.Reload'), tooltip: t('headerTooltip.Reload'),
iconClass: !reloadRouteSwitch.value ? 'ray-icon__reload--loading' : '', iconClass: !globalMainLayoutLoad.value ? 'ray-icon__reload--loading' : '',
eventKey: 'reload', eventKey: 'reload',
}, },
] ]

View File

@ -27,7 +27,6 @@ import Breadcrumb from './components/Breadcrumb/index'
import GlobalSearch from './components/GlobalSearch/index' import GlobalSearch from './components/GlobalSearch/index'
import AppAvatar from '@/app-components/app/AppAvatar/index' import AppAvatar from '@/app-components/app/AppAvatar/index'
import { useSetting } from '@/store'
import { LOCAL_OPTIONS } from '@/app-config/localConfig' import { LOCAL_OPTIONS } from '@/app-config/localConfig'
import { import {
createAvatarOptions, createAvatarOptions,
@ -39,22 +38,22 @@ import { useDevice } from '@/hooks/web/index'
import { getVariableToRefs, setVariable } from '@/global-variable/index' import { getVariableToRefs, setVariable } from '@/global-variable/index'
import { useFullscreen } from 'vue-hooks-plus' import { useFullscreen } from 'vue-hooks-plus'
import { useI18n } from '@/hooks/web/index' import { useI18n } from '@/hooks/web/index'
import { useMainPage } from '@/hooks/template/index'
import { useSettingGetters, useSettingActions } from '@/store'
import type { IconEventMapOptions, IconEventMap } from './type' import type { IconEventMapOptions, IconEventMap } from './type'
export default defineComponent({ export default defineComponent({
name: 'AppSiderBar', name: 'AppSiderBar',
setup() { setup() {
const settingStore = useSetting() const { updateLocale, changeSwitcher } = useSettingActions()
const { updateLocale, changeSwitcher } = settingStore
const { t } = useI18n() const { t } = useI18n()
const { reload } = useMainPage()
const [isFullscreen, { toggleFullscreen, isEnabled }] = useFullscreen( const [isFullscreen, { toggleFullscreen, isEnabled }] = useFullscreen(
document.getElementsByTagName('html')[0], document.getElementsByTagName('html')[0],
) )
const { drawerPlacement, breadcrumbSwitch, reloadRouteSwitch } = const { getDrawerPlacement, getBreadcrumbSwitch } = useSettingGetters()
storeToRefs(settingStore)
const showSettings = ref(false) const showSettings = ref(false)
const spaceItemStyle = { const spaceItemStyle = {
display: 'flex', display: 'flex',
@ -62,6 +61,7 @@ export default defineComponent({
const globalSearchShown = ref(false) const globalSearchShown = ref(false)
const { isTabletOrSmaller } = useDevice() const { isTabletOrSmaller } = useDevice()
const globalDrawerValue = getVariableToRefs('globalDrawerValue') const globalDrawerValue = getVariableToRefs('globalDrawerValue')
const globalMainLayoutLoad = getVariableToRefs('globalMainLayoutLoad')
/** /**
* *
@ -71,7 +71,7 @@ export default defineComponent({
createLeftIconOptions({ createLeftIconOptions({
isFullscreen, isFullscreen,
isTabletOrSmaller, isTabletOrSmaller,
reloadRouteSwitch, globalMainLayoutLoad,
}), }),
) )
/** /**
@ -82,15 +82,13 @@ export default defineComponent({
createRightIconOptions({ createRightIconOptions({
isFullscreen, isFullscreen,
isTabletOrSmaller, isTabletOrSmaller,
reloadRouteSwitch, globalMainLayoutLoad,
}), }),
) )
const iconEventMap: IconEventMapOptions = { const iconEventMap: IconEventMapOptions = {
// 刷新组件重新加载,手动设置 800ms loading 时长 // 刷新组件重新加载,手动设置 800ms loading 时长
reload: () => { reload: () => {
changeSwitcher(false, 'reloadRouteSwitch') reload()
setTimeout(() => changeSwitcher(true, 'reloadRouteSwitch'), 800)
}, },
setting: () => { setting: () => {
showSettings.value = true showSettings.value = true
@ -127,8 +125,8 @@ export default defineComponent({
showSettings, showSettings,
updateLocale, updateLocale,
spaceItemStyle, spaceItemStyle,
drawerPlacement, getDrawerPlacement,
breadcrumbSwitch, getBreadcrumbSwitch,
globalSearchShown, globalSearchShown,
} }
}, },
@ -148,6 +146,7 @@ export default defineComponent({
> >
{this.leftIconOptions.map((curr) => ( {this.leftIconOptions.map((curr) => (
<TooltipIcon <TooltipIcon
key={curr.name}
iconName={curr.name} iconName={curr.name}
tooltipText={ tooltipText={
isRef(curr.tooltip) ? curr.tooltip.value : curr.tooltip isRef(curr.tooltip) ? curr.tooltip.value : curr.tooltip
@ -156,7 +155,7 @@ export default defineComponent({
onClick={this.toolIconClick.bind(this, curr.name)} onClick={this.toolIconClick.bind(this, curr.name)}
/> />
))} ))}
{this.breadcrumbSwitch ? <Breadcrumb /> : null} {this.getBreadcrumbSwitch ? <Breadcrumb /> : null}
</NSpace> </NSpace>
<NSpace <NSpace
align="center" align="center"
@ -165,6 +164,7 @@ export default defineComponent({
> >
{this.rightTooltipIconOptions.map((curr) => ( {this.rightTooltipIconOptions.map((curr) => (
<TooltipIcon <TooltipIcon
key={curr.name}
iconName={curr.name} iconName={curr.name}
tooltipText={ tooltipText={
isRef(curr.tooltip) ? curr.tooltip.value : curr.tooltip isRef(curr.tooltip) ? curr.tooltip.value : curr.tooltip
@ -198,7 +198,7 @@ export default defineComponent({
</NSpace> </NSpace>
<SettingDrawer <SettingDrawer
v-model:show={this.showSettings} v-model:show={this.showSettings}
placement={this.drawerPlacement} placement={this.getDrawerPlacement}
/> />
</NLayoutHeader> </NLayoutHeader>
) )

View File

@ -26,5 +26,5 @@ export interface IconOptions {
export interface IconOptionsFC { export interface IconOptionsFC {
isTabletOrSmaller: Ref<boolean> isTabletOrSmaller: Ref<boolean>
isFullscreen: Ref<boolean> isFullscreen: Ref<boolean>
reloadRouteSwitch: Ref<boolean> globalMainLayoutLoad: Ref<boolean>
} }

View File

@ -21,21 +21,22 @@ import { NSpin } from 'naive-ui'
import RTransitionComponent from '@/components/RTransitionComponent/index.vue' import RTransitionComponent from '@/components/RTransitionComponent/index.vue'
import AppRequestCancelerProvider from '@/app-components/provider/AppRequestCancelerProvider/index' 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' import type { GlobalThemeOverrides } from 'naive-ui'
const ContentWrapper = defineComponent({ const ContentWrapper = defineComponent({
name: 'LayoutContentWrapper', name: 'LayoutContentWrapper',
setup() { setup() {
const settingStore = useSetting()
const router = useRouter() const router = useRouter()
const { reloadRouteSwitch, contentTransition } = storeToRefs(settingStore) const { getContentTransition } = useSettingGetters()
const spinning = ref(false) const spinning = ref(false)
const themeOverridesSpin: GlobalThemeOverrides['Spin'] = { const themeOverridesSpin: GlobalThemeOverrides['Spin'] = {
opacitySpinning: '0', opacitySpinning: '0',
} }
const globalMainLayoutLoad = getVariableToRefs('globalMainLayoutLoad')
const setupLayoutContentSpin = () => { const setupLayoutContentSpin = () => {
router.beforeEach(() => { router.beforeEach(() => {
@ -50,25 +51,27 @@ const ContentWrapper = defineComponent({
setupLayoutContentSpin() setupLayoutContentSpin()
return { return {
reloadRouteSwitch, globalMainLayoutLoad,
spinning, spinning,
themeOverridesSpin, themeOverridesSpin,
contentTransition, getContentTransition,
} }
}, },
render() { render() {
const { globalMainLayoutLoad } = this
return ( return (
<NSpin <NSpin
show={this.spinning || !this.reloadRouteSwitch} show={this.spinning || !globalMainLayoutLoad}
description="loading..." description="loading..."
size="large" size="large"
themeOverrides={this.themeOverridesSpin} themeOverrides={this.themeOverridesSpin}
> >
<AppRequestCancelerProvider /> <AppRequestCancelerProvider />
{this.reloadRouteSwitch ? ( {globalMainLayoutLoad ? (
<RTransitionComponent <RTransitionComponent
class="content-wrapper" class="content-wrapper"
transitionPropName={this.contentTransition + '-transform'} transitionPropName={this.getContentTransition + '-transform'}
/> />
) : null} ) : null}
</NSpin> </NSpin>

View File

@ -9,6 +9,17 @@
& .r-layout-full__viewer-content { & .r-layout-full__viewer-content {
height: var(--layout-content-height); height: var(--layout-content-height);
padding: 16px; 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 { & .n-scrollbar-container {
height: 100%; height: 100%;

View File

@ -18,10 +18,11 @@ import FooterWrapper from '@/layout/default/FooterWrapper'
import HeaderWrapper from './default/HeaderWrapper' import HeaderWrapper from './default/HeaderWrapper'
import FeatureWrapper from './default/FeatureWrapper' import FeatureWrapper from './default/FeatureWrapper'
import { useSetting } from '@/store'
import { LAYOUT_CONTENT_REF } from '@/app-config/routerConfig' import { LAYOUT_CONTENT_REF } from '@/app-config/routerConfig'
import { layoutHeaderCssVars } from '@/layout/layoutResize' import { layoutHeaderCssVars } from '@/layout/layoutResize'
import useAppLockScreen from '@/app-components/app/AppLockScreen/appLockVar' import useAppLockScreen from '@/app-components/app/AppLockScreen/appLockVar'
import { getVariableToRefs } from '@/global-variable/index'
import { useSettingGetters } from '@/store'
export default defineComponent({ export default defineComponent({
name: 'RLayout', name: 'RLayout',
@ -30,45 +31,54 @@ export default defineComponent({
const layoutMenuTagRef = ref<HTMLElement>() const layoutMenuTagRef = ref<HTMLElement>()
const layoutFooterRef = ref<HTMLElement>() const layoutFooterRef = ref<HTMLElement>()
const settingStore = useSetting() const { getMenuTagSwitch, getCopyrightSwitch } = useSettingGetters()
const { menuTagSwitch: modelMenuTagSwitch, footerSwitch } =
storeToRefs(settingStore)
const { getLockAppScreen } = useAppLockScreen() const { getLockAppScreen } = useAppLockScreen()
const cssVarsRef = layoutHeaderCssVars([ const cssVarsRef = layoutHeaderCssVars([
layoutSiderBarRef, layoutSiderBarRef,
layoutMenuTagRef, layoutMenuTagRef,
layoutFooterRef, layoutFooterRef,
]) ])
const layoutContentMaximize = getVariableToRefs('layoutContentMaximize')
return { return {
modelMenuTagSwitch, getMenuTagSwitch,
cssVarsRef, cssVarsRef,
getLockAppScreen, getLockAppScreen,
LAYOUT_CONTENT_REF,
layoutSiderBarRef, layoutSiderBarRef,
layoutMenuTagRef, layoutMenuTagRef,
layoutFooterRef, layoutFooterRef,
footerSwitch, getCopyrightSwitch,
layoutContentMaximize,
} }
}, },
render() { render() {
return !this.getLockAppScreen() ? ( const {
<NLayout class="r-layout-full" style={[this.cssVarsRef]} hasSider> layoutContentMaximize,
getMenuTagSwitch,
cssVarsRef,
getCopyrightSwitch,
} = this
const { getLockAppScreen } = this
return !getLockAppScreen() ? (
<NLayout class="r-layout-full" style={[cssVarsRef]} hasSider>
<Menu /> <Menu />
<NLayoutContent class="r-layout-full__viewer"> <NLayoutContent class="r-layout-full__viewer">
<HeaderWrapper ref="layoutSiderBarRef" /> <HeaderWrapper ref="layoutSiderBarRef" />
{this.modelMenuTagSwitch ? ( {getMenuTagSwitch ? <FeatureWrapper ref="layoutMenuTagRef" /> : null}
<FeatureWrapper ref="layoutMenuTagRef" />
) : null}
<NLayoutContent <NLayoutContent
ref="LAYOUT_CONTENT_REF" ref={LAYOUT_CONTENT_REF}
class="r-layout-full__viewer-content" class={[
'r-layout-full__viewer-content',
layoutContentMaximize
? 'r-layout-full__viewer-content--maximize'
: null,
]}
nativeScrollbar={false} nativeScrollbar={false}
> >
<ContentWrapper /> <ContentWrapper />
</NLayoutContent> </NLayoutContent>
{this.footerSwitch ? <FooterWrapper ref="layoutFooterRef" /> : null} {getCopyrightSwitch ? <FooterWrapper ref="layoutFooterRef" /> : null}
</NLayoutContent> </NLayoutContent>
</NLayout> </NLayout>
) : null ) : null

View File

@ -20,5 +20,6 @@
"RouterDemo": "Same Level Router Demo", "RouterDemo": "Same Level Router Demo",
"Mock": "Mock", "Mock": "Mock",
"QRCode": "QRCode", "QRCode": "QRCode",
"SvgIcon": "SVG Icon" "SvgIcon": "SVG Icon",
"TemplateHooks": "Template Api"
} }

View File

@ -1,7 +1,7 @@
{ {
"Register": "Register", "Register": "Register",
"Signin": "Signin", "Signing": "Signing",
"QRCodeSignin": "QRCode Signin", "QRCodeSigning": "QRCode Signing",
"NamePlaceholder": "please enter user name", "NamePlaceholder": "please enter user name",
"PasswordPlaceholder": "please enter password", "PasswordPlaceholder": "please enter password",
"Login": "Login", "Login": "Login",

View File

@ -18,7 +18,8 @@
"CalculatePrecision": "数字精度", "CalculatePrecision": "数字精度",
"Directive": "指令", "Directive": "指令",
"RouterDemo": "页面详情模式", "RouterDemo": "页面详情模式",
"Mock": "mock 数据", "Mock": "Mock 数据",
"QRCode": "二维码", "QRCode": "二维码",
"SvgIcon": "SVG图标" "SvgIcon": "SVG 图标",
"TemplateHooks": "模板内置 Api"
} }

View File

@ -1,7 +1,7 @@
{ {
"Register": "注册", "Register": "注册",
"Signin": "登录", "Signing": "登录",
"QRCodeSignin": "扫码登陆", "QRCodeSigning": "扫码登陆",
"NamePlaceholder": "请输入用户名", "NamePlaceholder": "请输入用户名",
"PasswordPlaceholder": "请输入密码", "PasswordPlaceholder": "请输入密码",
"Login": "登 陆", "Login": "登 陆",

View File

@ -11,11 +11,11 @@
import { permissionRouter } from './permission' import { permissionRouter } from './permission'
import { SETUP_ROUTER_ACTION, SUPER_ADMIN } from '@/app-config/routerConfig' import { SETUP_ROUTER_ACTION, SUPER_ADMIN } from '@/app-config/routerConfig'
import { useSigning } from '@/store'
import { useVueRouter } from '@/hooks/web/index' import { useVueRouter } from '@/hooks/web/index'
import { ROOT_ROUTE } from '@/app-config/appConfig' import { ROOT_ROUTE } from '@/app-config/appConfig'
import { setStorage } from '@/utils/cache' import { setStorage } from '@/utils/cache'
import { getAppEnvironment } from '@/utils/basic' import { getAppEnvironment } from '@/utils/basic'
import { useSigningGetters } from '@/store'
import type { Router } from 'vue-router' import type { Router } from 'vue-router'
import type { AppRouteMeta } from '@/router/type' import type { AppRouteMeta } from '@/router/type'
@ -29,11 +29,13 @@ import type { AppMenuOption } from '@/types/modules/app'
* , * ,
*/ */
export const validRole = (meta: AppRouteMeta) => { export const validRole = (meta: AppRouteMeta) => {
const { signingCallback } = storeToRefs(useSigning()) const { getSigningCallback } = useSigningGetters()
const modelRole = computed(() => signingCallback.value.role)
const { role: metaRole } = meta 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 return true
} else { } else {
// 如果 role 为 undefined 或者空数组, 则认为该路由不做权限过滤 // 如果 role 为 undefined 或者空数组, 则认为该路由不做权限过滤
@ -43,7 +45,7 @@ export const validRole = (meta: AppRouteMeta) => {
// 判断是否含有该权限 // 判断是否含有该权限
if (metaRole) { if (metaRole) {
return metaRole.includes(modelRole.value) return metaRole.includes(getSigningCallback.value.role)
} }
return true return true

View File

@ -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

View File

@ -0,0 +1,35 @@
/**
*
* @author Ray <https://github.com/XiaoDaiGua-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,
}
}

View File

@ -0,0 +1,97 @@
/**
*
* @author Ray <https://github.com/XiaoDaiGua-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,
}
}

View File

@ -0,0 +1,96 @@
/**
*
* @author Ray <https://github.com/XiaoDaiGua-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,
}
}

View File

@ -0,0 +1,35 @@
/**
*
* @author Ray <https://github.com/XiaoDaiGua-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,
}
}

View File

@ -18,10 +18,20 @@
*/ */
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate' import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
export { useSetting } from './modules/setting/index' // import { useSetting } from '@/store' 即可使用 // 导出仓库实例
export { useMenu } from './modules/menu/index' export { piniaSettingStore } from './modules/setting/index' // import { piniaSettingStore } from '@/store' 即可使用
export { useSigning } from './modules/signing/index' export { piniaMenuStore } from './modules/menu/index'
export { useKeepAlive } from './modules/keep-alive/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' import type { App } from 'vue'

View File

@ -23,7 +23,7 @@ import { APP_KEEP_ALIVE } from '@/app-config/appConfig'
import type { KeepAliveStoreState } from './type' import type { KeepAliveStoreState } from './type'
import type { AppMenuOption } from '@/types/modules/app' import type { AppMenuOption } from '@/types/modules/app'
export const useKeepAlive = defineStore( export const piniaKeepAliveStore = defineStore(
'keepAlive', 'keepAlive',
() => { () => {
const { maxKeepAliveLength } = APP_KEEP_ALIVE const { maxKeepAliveLength } = APP_KEEP_ALIVE

View File

@ -20,6 +20,7 @@
* (sessionStorage): * (sessionStorage):
* - breadcrumbOptions * - breadcrumbOptions
* - menuKey * - menuKey
* - menuTagOptions
*/ */
import { NEllipsis } from 'naive-ui' import { NEllipsis } from 'naive-ui'
@ -34,9 +35,9 @@ import {
} from './helper' } from './helper'
import { useI18n } from '@/hooks/web/index' import { useI18n } from '@/hooks/web/index'
import { getAppRawRoutes } from '@/router/appRouteModules' import { getAppRawRoutes } from '@/router/appRouteModules'
import { useKeepAlive } from '@/store'
import { useVueRouter } from '@/hooks/web/index' import { useVueRouter } from '@/hooks/web/index'
import { throttle } from 'lodash-es' import { throttle } from 'lodash-es'
import { useKeepAliveActions } from '@/store'
import type { AppRouteMeta, AppRouteRecordRaw } from '@/router/type' import type { AppRouteMeta, AppRouteRecordRaw } from '@/router/type'
import type { import type {
@ -46,13 +47,13 @@ import type {
} from '@/types/modules/app' } from '@/types/modules/app'
import type { MenuState } from '@/store/modules/menu/type' import type { MenuState } from '@/store/modules/menu/type'
export const useMenu = defineStore( export const piniaMenuStore = defineStore(
'menu', 'menu',
() => { () => {
const { router } = useVueRouter() const { router } = useVueRouter()
const route = useRoute() const route = useRoute()
const { t } = useI18n() const { t } = useI18n()
const { setKeepAliveInclude } = useKeepAlive() const { setKeepAliveInclude } = useKeepAliveActions()
const menuState = reactive<MenuState>({ const menuState = reactive<MenuState>({
menuKey: getCatchMenuKey(), // 当前菜单 `key` menuKey: getCatchMenuKey(), // 当前菜单 `key`
@ -60,6 +61,7 @@ export const useMenu = defineStore(
collapsed: false, // 是否折叠菜单 collapsed: false, // 是否折叠菜单
menuTagOptions: [], // tag 标签菜单 menuTagOptions: [], // tag 标签菜单
breadcrumbOptions: [], // 面包屑菜单 breadcrumbOptions: [], // 面包屑菜单
currentMenuOption: null, // 当前激活菜单项
}) })
const isSetupAppMenuLock = ref(true) const isSetupAppMenuLock = ref(true)
@ -191,6 +193,8 @@ export const useMenu = defineStore(
} else { } else {
setBreadcrumbOptions(menuState.menuKey || '', option) setBreadcrumbOptions(menuState.menuKey || '', option)
} }
menuState.currentMenuOption = option
} }
} }
@ -367,7 +371,7 @@ export const useMenu = defineStore(
persist: { persist: {
key: 'piniaMenuStore', key: 'piniaMenuStore',
storage: window.sessionStorage, storage: window.sessionStorage,
paths: ['breadcrumbOptions', 'menuKey'], paths: ['breadcrumbOptions', 'menuKey', 'menuTagOptions'],
}, },
}, },
) )

View File

@ -10,4 +10,5 @@ export interface MenuState {
collapsed: boolean collapsed: boolean
menuTagOptions: MenuTagOptions[] menuTagOptions: MenuTagOptions[]
breadcrumbOptions: AppMenuOption[] breadcrumbOptions: AppMenuOption[]
currentMenuOption: AppMenuOption | null
} }

View File

@ -10,7 +10,7 @@ import type { ConditionalPick } from '@/types/modules/helper'
import type { SettingState } from '@/store/modules/setting/type' import type { SettingState } from '@/store/modules/setting/type'
import type { DayjsLocal } from '@/dayjs/type' import type { DayjsLocal } from '@/dayjs/type'
export const useSetting = defineStore( export const piniaSettingStore = defineStore(
'setting', 'setting',
() => { () => {
const { const {
@ -28,15 +28,12 @@ export const useSetting = defineStore(
primaryColorHover: primaryColor, primaryColorHover: primaryColor,
}, },
}, },
themeValue: false, // `true` 为黑夜主题, `false` 为白色主题 appTheme: false, // `true` 为黑夜主题, `false` 为白色主题
reloadRouteSwitch: true, // 刷新路由开关
menuTagSwitch: true, // 多标签页开关 menuTagSwitch: true, // 多标签页开关
spinSwitch: false, // 全屏加载
breadcrumbSwitch: true, // 面包屑开关 breadcrumbSwitch: true, // 面包屑开关
localeLanguage: getAppDefaultLanguage(), localeLanguage: getAppDefaultLanguage(),
lockScreenSwitch: false, // 锁屏开关 lockScreenSwitch: false, // 锁屏开关
lockScreenInputSwitch: false, // 锁屏输入状态开关(预留该字段是为了方便拓展用, 但是舍弃了该字段, 改为使用 useAppLockScreen 方法) copyrightSwitch: true, // 底部区域开关
footerSwitch: true, // 底部区域开关
contentTransition: 'scale', // 切换过渡效果 contentTransition: 'scale', // 切换过渡效果
watermarkSwitch: false, // 水印开关, watermarkSwitch: false, // 水印开关,
}) })

View File

@ -4,15 +4,12 @@ import type { Placement } from '@/types/modules/component'
export interface SettingState { export interface SettingState {
drawerPlacement: Placement drawerPlacement: Placement
primaryColorOverride: GlobalThemeOverrides primaryColorOverride: GlobalThemeOverrides
themeValue: boolean appTheme: boolean
reloadRouteSwitch: boolean
menuTagSwitch: boolean menuTagSwitch: boolean
spinSwitch: boolean
breadcrumbSwitch: boolean breadcrumbSwitch: boolean
localeLanguage: string localeLanguage: string
lockScreenSwitch: boolean lockScreenSwitch: boolean
lockScreenInputSwitch: boolean
watermarkSwitch: boolean watermarkSwitch: boolean
footerSwitch: boolean copyrightSwitch: boolean
contentTransition: string contentTransition: string
} }

View File

@ -28,7 +28,7 @@ import type {
SigningResponse, SigningResponse,
} from '@/store/modules/signing/type' } from '@/store/modules/signing/type'
export const useSigning = defineStore( export const piniaSigningStore = defineStore(
'signing', 'signing',
() => { () => {
const state = reactive({ const state = reactive({

View File

@ -43,6 +43,7 @@ const PreviewSVGIcons = defineComponent({
<div <div
class="pre-view-icons__card" class="pre-view-icons__card"
v-copy={`<RIcon name="${curr}" size="56" />`} v-copy={`<RIcon name="${curr}" size="56" />`}
key={curr}
> >
<NPopover> <NPopover>
{{ {{

View File

@ -0,0 +1,76 @@
/**
*
* @author Ray <https://github.com/XiaoDaiGua-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 (
<NSpace wrapItem={false} vertical>
<NCard title="useAppMenu 导航方法">
<h3>
navigationTo
</h3>
<br />
<NButton onClick={() => navigationTo(14)}></NButton>
</NCard>
<NCard title="useMainPage 主页面方法">
<NCard title="reload 加载函数">
<h3>
使
vue 800ms
</h3>
<br />
<NButton
onClick={() => {
reload()
}}
>
</NButton>
</NCard>
<NCard title="maximize 内容区域最大化">
<NButton
onClick={() => {
this.maximizeRef = !this.maximizeRef
maximize(this.maximizeRef)
}}
>
</NButton>
</NCard>
</NCard>
</NSpace>
)
},
})

View File

@ -1,4 +1,4 @@
.qrcode-signin { .qrcode-signing {
width: 100%; width: 100%;
height: 220px; height: 220px;
@include flexCenter; @include flexCenter;

View File

@ -22,8 +22,8 @@ import LOGO from '@/assets/images/ray.svg'
* *
*/ */
const QRCodeSignin = defineComponent({ const QRCodeSigning = defineComponent({
name: 'QRCodeSignin', name: 'QRCodeSigning',
setup() { setup() {
const qrcodeState = reactive({ const qrcodeState = reactive({
qrcodeValue: 'https://github.com/XiaoDaiGua-Ray/xiaodaigua-ray.github.io', qrcodeValue: 'https://github.com/XiaoDaiGua-Ray/xiaodaigua-ray.github.io',
@ -35,11 +35,11 @@ const QRCodeSignin = defineComponent({
}, },
render() { render() {
return ( return (
<div class="qrcode-signin"> <div class="qrcode-signing">
<RayQRcode text="ray template yes" size={200} logoImage={LOGO} /> <RayQRcode text="ray template yes" size={200} logoImage={LOGO} />
</div> </div>
) )
}, },
}) })
export default QRCodeSignin export default QRCodeSigning

View File

@ -1,5 +1,5 @@
.ray-template--light { .ray-template--light {
& .sso-signin { & .sso-signing {
color: #878787; color: #878787;
} }
} }

View File

@ -21,16 +21,16 @@ import './index.scss'
import { NSpace, NPopover } from 'naive-ui' import { NSpace, NPopover } from 'naive-ui'
import RIcon from '@/components/RIcon/index' import RIcon from '@/components/RIcon/index'
interface SSOSigninOptions { interface SSOSigningOptions {
icon: string icon: string
key: string key: string
tooltipLabel: string tooltipLabel: string
} }
const SSOSignin = defineComponent({ const SSOSigning = defineComponent({
name: 'SSOSignin', name: 'SSOSigning',
setup() { setup() {
const ssoSigninOptions = [ const ssoSigningOptions = [
{ {
icon: 'github', icon: 'github',
key: 'github', key: 'github',
@ -48,27 +48,31 @@ const SSOSignin = defineComponent({
}, },
] ]
const handleSSOSigninClick = (option: SSOSigninOptions) => { const handleSSOSigningClick = (option: SSOSigningOptions) => {
window.$message.info(`调用${option.tooltipLabel}`) window.$message.info(`调用${option.tooltipLabel}`)
} }
return { return {
ssoSigninOptions, ssoSigningOptions,
handleSSOSigninClick, handleSSOSigningClick,
} }
}, },
render() { render() {
return ( return (
<NSpace class="sso-signin" align="center" itemStyle={{ display: 'flex' }}> <NSpace
{this.ssoSigninOptions.map((curr) => ( class="sso-signing"
<NPopover> align="center"
itemStyle={{ display: 'flex' }}
>
{this.ssoSigningOptions.map((curr) => (
<NPopover key={curr.key}>
{{ {{
trigger: () => ( trigger: () => (
<RIcon <RIcon
name={curr.icon} name={curr.icon}
size="24" size="24"
cursor="pointer" cursor="pointer"
onClick={this.handleSSOSigninClick.bind(this, curr)} onClick={this.handleSSOSigningClick.bind(this, curr)}
/> />
), ),
default: () => curr.tooltipLabel, default: () => curr.tooltipLabel,
@ -80,4 +84,4 @@ const SSOSignin = defineComponent({
}, },
}) })
export default SSOSignin export default SSOSigning

View File

@ -1,23 +1,21 @@
import { NForm, NFormItem, NInput, NButton } from 'naive-ui' import { NForm, NFormItem, NInput, NButton } from 'naive-ui'
import { setStorage } from '@/utils/cache' import { setStorage } from '@/utils/cache'
import { useSigning } from '@/store'
import { useI18n } from '@/hooks/web/index' import { useI18n } from '@/hooks/web/index'
import { APP_CATCH_KEY, ROOT_ROUTE } from '@/app-config/appConfig' import { APP_CATCH_KEY, ROOT_ROUTE } from '@/app-config/appConfig'
import { useVueRouter } from '@/hooks/web/index' import { useVueRouter } from '@/hooks/web/index'
import { setVariable, getVariableToRefs } from '@/global-variable/index' import { setVariable, getVariableToRefs } from '@/global-variable/index'
import { useSigningActions, useSigningGetters } from '@/store'
import type { FormInst } from 'naive-ui' import type { FormInst } from 'naive-ui'
export default defineComponent({ export default defineComponent({
name: 'RSignin', name: 'RSigning',
setup() { setup() {
const loginFormRef = ref<FormInst>() const loginFormRef = ref<FormInst>()
const { t } = useI18n() const { t } = useI18n()
const signingStore = useSigning() const { signing } = useSigningActions()
const { signing } = signingStore
const { path } = ROOT_ROUTE const { path } = ROOT_ROUTE
const globalSpinning = getVariableToRefs('globalSpinning') const globalSpinning = getVariableToRefs('globalSpinning')

View File

@ -11,17 +11,17 @@ import {
NGrid, NGrid,
NGridItem, NGridItem,
} from 'naive-ui' } from 'naive-ui'
import Signin from './components/Signin/index' import Signing from './components/Signing/index'
import Register from './components/Register/index' import Register from './components/Register/index'
import QRCodeSignin from './components/QRCodeSignin/index' import QRCodeSigning from './components/QRCodeSigning/index'
import SSOSignin from './components/SSOSignin/index' import SSOSigning from './components/SSOSigning/index'
import RIcon from '@/components/RIcon' import RIcon from '@/components/RIcon'
import RayLink from '@/app-components/app/RayLink/index' import RayLink from '@/app-components/app/RayLink/index'
import ThemeSwitch from '@/layout/components/SiderBar/components/SettingDrawer/components/ThemeSwitch/index' import ThemeSwitch from '@/layout/components/SiderBar/components/SettingDrawer/components/ThemeSwitch/index'
import { useSetting } from '@/store'
import { LOCAL_OPTIONS } from '@/app-config/localConfig' import { LOCAL_OPTIONS } from '@/app-config/localConfig'
import { useWindowSize } from '@vueuse/core' import { useWindowSize } from '@vueuse/core'
import { useSettingActions } from '@/store'
const Login = defineComponent({ const Login = defineComponent({
name: 'RLogin', name: 'RLogin',
@ -31,12 +31,11 @@ const Login = defineComponent({
} = __APP_CFG__ } = __APP_CFG__
const state = reactive({ const state = reactive({
tabsValue: 'signin', tabsValue: 'signing',
}) })
const { height: windowHeight, width: windowWidth } = useWindowSize() const { height: windowHeight, width: windowWidth } = useWindowSize()
const settingStore = useSetting() const { updateLocale } = useSettingActions()
const { updateLocale } = settingStore
return { return {
...toRefs(state), ...toRefs(state),
@ -122,10 +121,10 @@ const Login = defineComponent({
default: () => ( default: () => (
<> <>
<NTabPane <NTabPane
tab={$t('views.login.index.Signin')} tab={$t('views.login.index.Signing')}
name="signin" name="signing"
> >
<Signin /> <Signing />
</NTabPane> </NTabPane>
<NTabPane <NTabPane
tab={$t('views.login.index.Register')} tab={$t('views.login.index.Register')}
@ -134,17 +133,17 @@ const Login = defineComponent({
<Register /> <Register />
</NTabPane> </NTabPane>
<NTabPane <NTabPane
tab={$t('views.login.index.QRCodeSignin')} tab={$t('views.login.index.QRCodeSigning')}
name="qrcodeSignin" name="qrcodeSigning"
> >
<QRCodeSignin /> <QRCodeSigning />
</NTabPane> </NTabPane>
</> </>
), ),
}} }}
</NTabs> </NTabs>
<NDivider></NDivider> <NDivider></NDivider>
<SSOSignin /> <SSOSigning />
<NDivider></NDivider> <NDivider></NDivider>
<RayLink /> <RayLink />
</NCard> </NCard>