mirror of
https://github.com/XiaoDaiGua-Ray/ray-template.git
synced 2025-04-06 03:57:49 +08:00
v4.3.0
This commit is contained in:
parent
f7887989f9
commit
32183d0ab9
11
CHANGELOG.md
11
CHANGELOG.md
@ -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
|
||||||
|
|
||||||
主要更新了命名问题。并且使用单词检查器,扫描整个项目替换了拼写错误的单词。
|
主要更新了命名问题。并且使用单词检查器,扫描整个项目替换了拼写错误的单词。
|
||||||
|
@ -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(),
|
||||||
|
@ -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()
|
||||||
|
|
||||||
|
@ -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}
|
||||||
|
@ -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
|
||||||
|
@ -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}
|
||||||
>
|
>
|
||||||
|
@ -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)
|
||||||
},
|
},
|
||||||
|
@ -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
|
||||||
},
|
},
|
||||||
|
@ -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,
|
||||||
() => {
|
() => {
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -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>
|
||||||
|
@ -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
|
||||||
|
5
src/hooks/template/index.ts
Normal file
5
src/hooks/template/index.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { useAppMenu } from './useAppMenu'
|
||||||
|
import { useMainPage } from './useMainPage'
|
||||||
|
import { useMenuTag } from './useMenuTag'
|
||||||
|
|
||||||
|
export { useAppMenu, useMainPage, useMenuTag }
|
82
src/hooks/template/useAppMenu.ts
Normal file
82
src/hooks/template/useAppMenu.ts
Normal 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,
|
||||||
|
}
|
||||||
|
}
|
35
src/hooks/template/useMainPage.ts
Normal file
35
src/hooks/template/useMainPage.ts
Normal 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,
|
||||||
|
}
|
||||||
|
}
|
165
src/hooks/template/useMenuTag.ts
Normal file
165
src/hooks/template/useMenuTag.ts
Normal 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,
|
||||||
|
}
|
||||||
|
}
|
@ -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,
|
||||||
|
@ -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>
|
||||||
|
@ -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)}
|
||||||
|
@ -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>
|
||||||
|
@ -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'),
|
||||||
}}
|
}}
|
||||||
|
@ -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>
|
||||||
|
@ -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',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
@ -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>
|
||||||
)
|
)
|
||||||
|
@ -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>
|
||||||
}
|
}
|
||||||
|
@ -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>
|
||||||
|
@ -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%;
|
||||||
|
@ -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
|
||||||
|
@ -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"
|
||||||
}
|
}
|
||||||
|
@ -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",
|
||||||
|
@ -18,7 +18,8 @@
|
|||||||
"CalculatePrecision": "数字精度",
|
"CalculatePrecision": "数字精度",
|
||||||
"Directive": "指令",
|
"Directive": "指令",
|
||||||
"RouterDemo": "页面详情模式",
|
"RouterDemo": "页面详情模式",
|
||||||
"Mock": "mock 数据",
|
"Mock": "Mock 数据",
|
||||||
"QRCode": "二维码",
|
"QRCode": "二维码",
|
||||||
"SvgIcon": "SVG图标"
|
"SvgIcon": "SVG 图标",
|
||||||
|
"TemplateHooks": "模板内置 Api"
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"Register": "注册",
|
"Register": "注册",
|
||||||
"Signin": "登录",
|
"Signing": "登录",
|
||||||
"QRCodeSignin": "扫码登陆",
|
"QRCodeSigning": "扫码登陆",
|
||||||
"NamePlaceholder": "请输入用户名",
|
"NamePlaceholder": "请输入用户名",
|
||||||
"PasswordPlaceholder": "请输入密码",
|
"PasswordPlaceholder": "请输入密码",
|
||||||
"Login": "登 陆",
|
"Login": "登 陆",
|
||||||
|
@ -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
|
||||||
|
17
src/router/modules/demo/template-hooks.ts
Normal file
17
src/router/modules/demo/template-hooks.ts
Normal 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
|
35
src/store/hooks/useKeepAliveStore.ts
Normal file
35
src/store/hooks/useKeepAliveStore.ts
Normal 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,
|
||||||
|
}
|
||||||
|
}
|
97
src/store/hooks/useMenuStore.ts
Normal file
97
src/store/hooks/useMenuStore.ts
Normal 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,
|
||||||
|
}
|
||||||
|
}
|
96
src/store/hooks/useSettingStore.ts
Normal file
96
src/store/hooks/useSettingStore.ts
Normal 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,
|
||||||
|
}
|
||||||
|
}
|
35
src/store/hooks/useSigningStore.ts
Normal file
35
src/store/hooks/useSigningStore.ts
Normal 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,
|
||||||
|
}
|
||||||
|
}
|
@ -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'
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
@ -10,4 +10,5 @@ export interface MenuState {
|
|||||||
collapsed: boolean
|
collapsed: boolean
|
||||||
menuTagOptions: MenuTagOptions[]
|
menuTagOptions: MenuTagOptions[]
|
||||||
breadcrumbOptions: AppMenuOption[]
|
breadcrumbOptions: AppMenuOption[]
|
||||||
|
currentMenuOption: AppMenuOption | null
|
||||||
}
|
}
|
||||||
|
@ -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, // 水印开关,
|
||||||
})
|
})
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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({
|
||||||
|
@ -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>
|
||||||
{{
|
{{
|
||||||
|
76
src/views/demo/template-hooks/index.tsx
Normal file
76
src/views/demo/template-hooks/index.tsx
Normal 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>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
})
|
@ -1,4 +1,4 @@
|
|||||||
.qrcode-signin {
|
.qrcode-signing {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 220px;
|
height: 220px;
|
||||||
@include flexCenter;
|
@include flexCenter;
|
@ -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
|
@ -1,5 +1,5 @@
|
|||||||
.ray-template--light {
|
.ray-template--light {
|
||||||
& .sso-signin {
|
& .sso-signing {
|
||||||
color: #878787;
|
color: #878787;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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
|
@ -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')
|
||||||
|
|
@ -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>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user