mirror of
https://github.com/XiaoDaiGua-Ray/ray-template.git
synced 2025-04-30 14:32:40 +08:00
16:32
This commit is contained in:
parent
c2029d0fd8
commit
daf46ebe83
BIN
src/.DS_Store
vendored
BIN
src/.DS_Store
vendored
Binary file not shown.
BIN
src/components/.DS_Store
vendored
BIN
src/components/.DS_Store
vendored
Binary file not shown.
@ -1,4 +0,0 @@
|
|||||||
<svg t="1669270375884" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="14105" width="200" height="200">
|
|
||||||
<path d="M832 160h-96v-64h-64v192h64v-64H832c17.92 0 32 14.08 32 32v96h-704V256c0-17.92 14.08-32 32-32h32v-64H192c-53.12 0-96 42.88-96 96v576c0 53.12 42.88 96 96 96h640c53.12 0 96-42.88 96-96V256c0-53.12-42.88-96-96-96z m0 704H192c-17.92 0-32-14.08-32-32V416h704V832c0 17.92-14.08 32-32 32z" fill="currentColor" p-id="14106"></path>
|
|
||||||
<path d="M352 224h256v-64h-256v-64h-64v192h64zM575.36 524.8L512 588.16l-63.36-63.36-45.44 45.44 63.36 63.36-63.36 63.36 45.44 45.44 63.36-63.36 63.36 63.36 45.44-45.44-63.36-63.36 63.36-63.36z" fill="currentColor" p-id="14107"></path>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 726 B |
@ -1,50 +0,0 @@
|
|||||||
import { NMenu, NLayoutSider } from 'naive-ui'
|
|
||||||
import { useMenu } from '@/store'
|
|
||||||
|
|
||||||
const LayoutMenu = defineComponent({
|
|
||||||
name: 'LayoutMenu',
|
|
||||||
setup() {
|
|
||||||
const menuStore = useMenu()
|
|
||||||
const { menuModelValueChange, setupAppRoutes, collapsedMenu } = menuStore
|
|
||||||
const modelMenuKey = computed({
|
|
||||||
get: () => menuStore.menuKey,
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
||||||
set: () => {},
|
|
||||||
})
|
|
||||||
const modelMenuOptions = computed(() => menuStore.options)
|
|
||||||
const modelCollapsed = computed(() => menuStore.collapsed)
|
|
||||||
|
|
||||||
setupAppRoutes()
|
|
||||||
|
|
||||||
return {
|
|
||||||
modelMenuKey,
|
|
||||||
menuModelValueChange,
|
|
||||||
modelMenuOptions,
|
|
||||||
modelCollapsed,
|
|
||||||
collapsedMenu,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<NLayoutSider
|
|
||||||
bordered
|
|
||||||
showTrigger
|
|
||||||
collapseMode="width"
|
|
||||||
collapsedWidth={64}
|
|
||||||
onUpdateCollapsed={this.collapsedMenu.bind(this)}
|
|
||||||
>
|
|
||||||
<NMenu
|
|
||||||
v-model:value={this.modelMenuKey}
|
|
||||||
options={this.modelMenuOptions as NaiveMenuOptions[]}
|
|
||||||
indent={24}
|
|
||||||
collapsed={this.modelCollapsed}
|
|
||||||
collapsedIconSize={22}
|
|
||||||
collapsedWidth={64}
|
|
||||||
onUpdateValue={this.menuModelValueChange.bind(this)}
|
|
||||||
/>
|
|
||||||
</NLayoutSider>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
export default LayoutMenu
|
|
@ -1,14 +0,0 @@
|
|||||||
$space: calc($layoutRouterViewContainer / 2);
|
|
||||||
|
|
||||||
.menu-tag {
|
|
||||||
height: $layoutMenuHeight;
|
|
||||||
|
|
||||||
& .menu-tag-sapce {
|
|
||||||
width: calc(100% - $space * 2);
|
|
||||||
padding: $space;
|
|
||||||
}
|
|
||||||
|
|
||||||
& .n-tag {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,61 +0,0 @@
|
|||||||
import './index.scss'
|
|
||||||
import { NScrollbar, NTag, NSpace } from 'naive-ui'
|
|
||||||
import { useMenu } from '@/store'
|
|
||||||
|
|
||||||
import type { MenuOption } from 'naive-ui'
|
|
||||||
|
|
||||||
const MenuTag = defineComponent({
|
|
||||||
name: 'MenuTag',
|
|
||||||
setup() {
|
|
||||||
const menuStore = useMenu()
|
|
||||||
const { menuTagOptions, menuKey } = storeToRefs(menuStore)
|
|
||||||
const { menuModelValueChange, spliceMenTagOptions } = menuStore
|
|
||||||
|
|
||||||
const handleCloseTag = (idx: number) => {
|
|
||||||
spliceMenTagOptions(idx)
|
|
||||||
|
|
||||||
if (menuKey.value !== '/dashboard') {
|
|
||||||
const options = menuTagOptions.value as MenuOption[]
|
|
||||||
const length = options.length
|
|
||||||
|
|
||||||
const tag = options[length - 1]
|
|
||||||
|
|
||||||
menuModelValueChange(tag.key as string, tag)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleTagClick = (item: MenuOption) => {
|
|
||||||
menuModelValueChange(item.key as string, item)
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
menuTagOptions,
|
|
||||||
menuModelValueChange,
|
|
||||||
handleCloseTag,
|
|
||||||
menuKey,
|
|
||||||
handleTagClick,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<NScrollbar class="menu-tag" xScrollable>
|
|
||||||
<NSpace class="menu-tag-sapce" wrap={false} align="center">
|
|
||||||
{this.menuTagOptions.map((curr: MenuOption, idx) => (
|
|
||||||
<NTag
|
|
||||||
closable={
|
|
||||||
curr.key !== '/dashboard' && this.menuTagOptions.length > 1
|
|
||||||
}
|
|
||||||
onClose={() => this.handleCloseTag(idx)}
|
|
||||||
type={curr.key === this.menuKey ? 'success' : 'default'}
|
|
||||||
onClick={this.handleTagClick.bind(this, curr)}
|
|
||||||
>
|
|
||||||
{typeof curr.label === 'function' ? curr.label() : curr.label}
|
|
||||||
</NTag>
|
|
||||||
))}
|
|
||||||
</NSpace>
|
|
||||||
</NScrollbar>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
export default MenuTag
|
|
@ -1,7 +0,0 @@
|
|||||||
export const useSwatchesColorOptions = () => [
|
|
||||||
'#FFFFFF',
|
|
||||||
'#18A058',
|
|
||||||
'#2080F0',
|
|
||||||
'#F0A020',
|
|
||||||
'rgba(208, 48, 80, 1)',
|
|
||||||
]
|
|
@ -1,8 +0,0 @@
|
|||||||
.setting-drawer__space {
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
& .n-descriptions-table-content {
|
|
||||||
display: flex !important;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,143 +0,0 @@
|
|||||||
import './index.scss'
|
|
||||||
import {
|
|
||||||
NDrawer,
|
|
||||||
NDrawerContent,
|
|
||||||
NDivider,
|
|
||||||
NSpace,
|
|
||||||
NSwitch,
|
|
||||||
NColorPicker,
|
|
||||||
NTooltip,
|
|
||||||
NDescriptions,
|
|
||||||
NDescriptionsItem,
|
|
||||||
} from 'naive-ui'
|
|
||||||
import RayIcon from '@/components/RayIcon/index'
|
|
||||||
import { useSwatchesColorOptions } from './hook'
|
|
||||||
import { useSetting } from '@/store'
|
|
||||||
|
|
||||||
import type { PropType } from 'vue'
|
|
||||||
|
|
||||||
const SettingDrawer = defineComponent({
|
|
||||||
name: 'SettingDrawer',
|
|
||||||
props: {
|
|
||||||
show: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
placement: {
|
|
||||||
type: String as PropType<NaiveDrawerPlacement>,
|
|
||||||
default: 'right',
|
|
||||||
},
|
|
||||||
width: {
|
|
||||||
type: Number,
|
|
||||||
default: 280,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
emits: ['update:show'],
|
|
||||||
setup(props, { emit }) {
|
|
||||||
const { t } = useI18n()
|
|
||||||
const settingStore = useSetting()
|
|
||||||
|
|
||||||
const { changeTheme, changePrimaryColor, changeMenuTagLog } = settingStore
|
|
||||||
const { themeValue, primaryColorOverride, menuTagLog } =
|
|
||||||
storeToRefs(settingStore)
|
|
||||||
|
|
||||||
const modelShow = computed({
|
|
||||||
get: () => props.show,
|
|
||||||
set: (bool) => {
|
|
||||||
emit('update:show', bool)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const handleRailStyle = () => ({
|
|
||||||
backgroundColor: '#000000',
|
|
||||||
})
|
|
||||||
|
|
||||||
return {
|
|
||||||
modelShow,
|
|
||||||
ray: t,
|
|
||||||
handleRailStyle,
|
|
||||||
changePrimaryColor,
|
|
||||||
changeTheme,
|
|
||||||
themeValue,
|
|
||||||
primaryColorOverride,
|
|
||||||
changeMenuTagLog,
|
|
||||||
menuTagLog,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<NDrawer
|
|
||||||
v-model:show={this.modelShow}
|
|
||||||
placement={this.placement}
|
|
||||||
width={this.width}
|
|
||||||
>
|
|
||||||
<NDrawerContent title={this.ray('LayoutHeaderSettingOptions.Title')}>
|
|
||||||
<NSpace class="setting-drawer__space" vertical>
|
|
||||||
<NDivider titlePlacement="center">
|
|
||||||
{this.ray('LayoutHeaderSettingOptions.ThemeOptions.Title')}
|
|
||||||
</NDivider>
|
|
||||||
<NSpace justify="center">
|
|
||||||
<NTooltip>
|
|
||||||
{{
|
|
||||||
trigger: () => (
|
|
||||||
<NSwitch
|
|
||||||
v-model:value={this.themeValue}
|
|
||||||
railStyle={this.handleRailStyle.bind(this)}
|
|
||||||
onUpdateValue={this.changeTheme.bind(this)}
|
|
||||||
>
|
|
||||||
{{
|
|
||||||
'checked-icon': () =>
|
|
||||||
h(
|
|
||||||
RayIcon,
|
|
||||||
{
|
|
||||||
name: 'dark',
|
|
||||||
},
|
|
||||||
{},
|
|
||||||
),
|
|
||||||
'unchecked-icon': () =>
|
|
||||||
h(
|
|
||||||
RayIcon,
|
|
||||||
{
|
|
||||||
name: 'light',
|
|
||||||
},
|
|
||||||
{},
|
|
||||||
),
|
|
||||||
}}
|
|
||||||
</NSwitch>
|
|
||||||
),
|
|
||||||
default: () =>
|
|
||||||
this.themeValue
|
|
||||||
? this.ray('LayoutHeaderSettingOptions.ThemeOptions.Dark')
|
|
||||||
: this.ray(
|
|
||||||
'LayoutHeaderSettingOptions.ThemeOptions.Light',
|
|
||||||
),
|
|
||||||
}}
|
|
||||||
</NTooltip>
|
|
||||||
</NSpace>
|
|
||||||
<NDivider titlePlacement="center">
|
|
||||||
{this.ray(
|
|
||||||
'LayoutHeaderSettingOptions.ThemeOptions.PrimaryColorConfig',
|
|
||||||
)}
|
|
||||||
</NDivider>
|
|
||||||
<NColorPicker
|
|
||||||
swatches={useSwatchesColorOptions()}
|
|
||||||
v-model:value={this.primaryColorOverride.common.primaryColor}
|
|
||||||
onUpdateValue={this.changePrimaryColor.bind(this)}
|
|
||||||
/>
|
|
||||||
<NDivider titlePlacement="center">界面显示</NDivider>
|
|
||||||
<NDescriptions labelPlacement="left" column={1}>
|
|
||||||
<NDescriptionsItem label="显示多标签">
|
|
||||||
<NSwitch
|
|
||||||
v-model:value={this.menuTagLog}
|
|
||||||
onUpdateValue={this.changeMenuTagLog.bind(this)}
|
|
||||||
/>
|
|
||||||
</NDescriptionsItem>
|
|
||||||
</NDescriptions>
|
|
||||||
</NSpace>
|
|
||||||
</NDrawerContent>
|
|
||||||
</NDrawer>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
export default SettingDrawer
|
|
@ -1,14 +0,0 @@
|
|||||||
export const useAvatarOptions = () => [
|
|
||||||
{
|
|
||||||
key: 'person',
|
|
||||||
label: '个人信息',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'divider',
|
|
||||||
key: 'd1',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'logout',
|
|
||||||
label: '退出登陆',
|
|
||||||
},
|
|
||||||
]
|
|
@ -1,16 +0,0 @@
|
|||||||
.layout-header {
|
|
||||||
height: $layoutHeaderHeight;
|
|
||||||
padding: 0 $layoutRouterViewContainer;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
> .layout-header__method {
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
& .layout-header__method--icon {
|
|
||||||
cursor: pointer;
|
|
||||||
outline: none;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,175 +0,0 @@
|
|||||||
import './index.scss'
|
|
||||||
import { NLayoutHeader, NSpace, NTooltip, NDropdown } from 'naive-ui'
|
|
||||||
import RayIcon from '@/components/RayIcon/index'
|
|
||||||
import { useSetting } from '@/store'
|
|
||||||
import { useLanguageOptions } from '@/language/index'
|
|
||||||
import SettingDrawer from './Components/SettingDrawer/index'
|
|
||||||
import { useAvatarOptions } from './hook'
|
|
||||||
import { removeCache } from '@/utils/cache'
|
|
||||||
|
|
||||||
import type { IconEventMapOptions, IconEventMap } from './type'
|
|
||||||
|
|
||||||
const SiderBar = defineComponent({
|
|
||||||
name: 'SiderBar',
|
|
||||||
setup() {
|
|
||||||
const settingStore = useSetting()
|
|
||||||
|
|
||||||
const { t } = useI18n()
|
|
||||||
const { updateLocale, changeReloadLog } = settingStore
|
|
||||||
const modelDrawerPlacement = ref(settingStore.drawerPlacement)
|
|
||||||
const showSettings = ref(false)
|
|
||||||
|
|
||||||
const leftIconOptions = [
|
|
||||||
{
|
|
||||||
name: 'reload',
|
|
||||||
size: 18,
|
|
||||||
tooltip: 'LayoutHeaderTooltipOptions.Reload',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
const rightIconOptions = [
|
|
||||||
{
|
|
||||||
name: 'language',
|
|
||||||
size: 18,
|
|
||||||
tooltip: '',
|
|
||||||
dropdown: {
|
|
||||||
methodName: 'handleSelect', // 默认为 `handleSelect`
|
|
||||||
switch: true,
|
|
||||||
options: useLanguageOptions(),
|
|
||||||
handleSelect: (key: string | number) => updateLocale(String(key)),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'github',
|
|
||||||
size: 18,
|
|
||||||
tooltip: 'LayoutHeaderTooltipOptions.Github',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'setting',
|
|
||||||
size: 18,
|
|
||||||
tooltip: 'LayoutHeaderTooltipOptions.Setting',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'ray',
|
|
||||||
size: 22,
|
|
||||||
tooltip: '',
|
|
||||||
dropdown: {
|
|
||||||
methodName: 'handleSelect', // 默认为 `handleSelect`
|
|
||||||
switch: true,
|
|
||||||
options: useAvatarOptions(),
|
|
||||||
handleSelect: (key: string | number) => {
|
|
||||||
if (key === 'logout') {
|
|
||||||
window.$dialog.warning({
|
|
||||||
title: '提示',
|
|
||||||
content: '您确定要退出登录吗',
|
|
||||||
positiveText: '确定',
|
|
||||||
negativeText: '不确定',
|
|
||||||
onPositiveClick: () => {
|
|
||||||
window.$message.info('账号退出中...')
|
|
||||||
|
|
||||||
removeCache('all-sessionStorage')
|
|
||||||
|
|
||||||
setTimeout(() => window.location.reload(), 2 * 1000)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
window.$message.info('这个人很懒, 没做这个功能~')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]
|
|
||||||
const iconEventMap: IconEventMapOptions = {
|
|
||||||
reload: () => {
|
|
||||||
changeReloadLog(false)
|
|
||||||
|
|
||||||
setTimeout(() => changeReloadLog(true))
|
|
||||||
},
|
|
||||||
setting: () => {
|
|
||||||
showSettings.value = true
|
|
||||||
},
|
|
||||||
github: () => {
|
|
||||||
window.open('https://github.com/XiaoDaiGua-Ray/ray-template')
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleIconClick = (key: IconEventMap) => {
|
|
||||||
iconEventMap[key]?.()
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
leftIconOptions,
|
|
||||||
rightIconOptions,
|
|
||||||
t,
|
|
||||||
handleIconClick,
|
|
||||||
modelDrawerPlacement,
|
|
||||||
showSettings,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<NLayoutHeader class="layout-header" bordered>
|
|
||||||
<NSpace
|
|
||||||
class="layout-header__method"
|
|
||||||
align="center"
|
|
||||||
justify="space-between"
|
|
||||||
>
|
|
||||||
<NSpace align="center">
|
|
||||||
{this.leftIconOptions.map((curr) => (
|
|
||||||
<NTooltip>
|
|
||||||
{{
|
|
||||||
trigger: () => (
|
|
||||||
<RayIcon
|
|
||||||
customClassName="layout-header__method--icon"
|
|
||||||
name={curr.name}
|
|
||||||
size={curr.size}
|
|
||||||
onClick={this.handleIconClick.bind(this, curr.name)}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
default: () => this.t(curr.tooltip),
|
|
||||||
}}
|
|
||||||
</NTooltip>
|
|
||||||
))}
|
|
||||||
</NSpace>
|
|
||||||
<NSpace align="center">
|
|
||||||
{this.rightIconOptions.map((curr) =>
|
|
||||||
curr.dropdown?.switch ? (
|
|
||||||
<NDropdown
|
|
||||||
options={curr.dropdown.options}
|
|
||||||
onSelect={
|
|
||||||
curr.dropdown[curr.dropdown.methodName ?? 'handleSelect']
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<RayIcon
|
|
||||||
customClassName="layout-header__method--icon"
|
|
||||||
name={curr.name}
|
|
||||||
size={curr.size}
|
|
||||||
/>
|
|
||||||
</NDropdown>
|
|
||||||
) : (
|
|
||||||
<NTooltip>
|
|
||||||
{{
|
|
||||||
trigger: () => (
|
|
||||||
<RayIcon
|
|
||||||
customClassName="layout-header__method--icon"
|
|
||||||
name={curr.name}
|
|
||||||
size={curr.size}
|
|
||||||
onClick={this.handleIconClick.bind(this, curr.name)}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
default: () => this.t(curr.tooltip),
|
|
||||||
}}
|
|
||||||
</NTooltip>
|
|
||||||
),
|
|
||||||
)}
|
|
||||||
</NSpace>
|
|
||||||
</NSpace>
|
|
||||||
<SettingDrawer
|
|
||||||
v-model:show={this.showSettings}
|
|
||||||
placement={this.modelDrawerPlacement}
|
|
||||||
/>
|
|
||||||
</NLayoutHeader>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
export default SiderBar
|
|
@ -1,5 +0,0 @@
|
|||||||
export interface IconEventMapOptions {
|
|
||||||
[propName: string]: (...args: unknown[]) => unknown
|
|
||||||
}
|
|
||||||
|
|
||||||
export type IconEventMap = keyof IconEventMapOptions
|
|
@ -1,13 +0,0 @@
|
|||||||
.layout {
|
|
||||||
box-sizing: border-box;
|
|
||||||
|
|
||||||
> .layout-full {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
& .layout-content__router-view {
|
|
||||||
// height: calc(100% - $layoutHeaderHeight - $layoutMenuHeight);
|
|
||||||
height: var(--layout-content-height);
|
|
||||||
padding: calc($layoutRouterViewContainer / 2);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,64 +0,0 @@
|
|||||||
import './index.scss'
|
|
||||||
import { NLayout, NLayoutContent } from 'naive-ui'
|
|
||||||
import RayTransitionComponent from '@/components/RayTransitionComponent/index.vue'
|
|
||||||
import LayoutMenu from './components/Menu/index'
|
|
||||||
import SiderBar from './components/SiderBar/index'
|
|
||||||
import MenuTag from './components/MenuTag/index'
|
|
||||||
import { useSetting } from '@/store'
|
|
||||||
|
|
||||||
const Layout = defineComponent({
|
|
||||||
name: 'Layout',
|
|
||||||
props: {},
|
|
||||||
setup() {
|
|
||||||
const menuStore = useSetting()
|
|
||||||
const { height: windowHeight } = useWindowSize()
|
|
||||||
const modelReloadRoute = computed(() => menuStore.reloadRouteLog)
|
|
||||||
const modelMenuTagLog = computed(() => menuStore.menuTagLog)
|
|
||||||
const cssVarsRef = computed(() => {
|
|
||||||
let cssVar = {}
|
|
||||||
|
|
||||||
if (menuStore.menuTagLog) {
|
|
||||||
cssVar = {
|
|
||||||
'--layout-content-height': 'calc(100% - 110px)',
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
cssVar = {
|
|
||||||
'--layout-content-height': 'calc(100% - 64px)',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return cssVar
|
|
||||||
})
|
|
||||||
|
|
||||||
return {
|
|
||||||
windowHeight,
|
|
||||||
modelReloadRoute,
|
|
||||||
modelMenuTagLog,
|
|
||||||
cssVarsRef,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
class="layout"
|
|
||||||
style={[`height: ${this.windowHeight}px`, this.cssVarsRef]}
|
|
||||||
>
|
|
||||||
<NLayout class="layout-full" hasSider>
|
|
||||||
<LayoutMenu />
|
|
||||||
<NLayout>
|
|
||||||
<SiderBar />
|
|
||||||
{this.modelMenuTagLog ? <MenuTag /> : ''}
|
|
||||||
<NLayoutContent
|
|
||||||
class="layout-content__router-view"
|
|
||||||
nativeScrollbar={false}
|
|
||||||
>
|
|
||||||
{this.modelReloadRoute ? <RayTransitionComponent /> : ''}
|
|
||||||
</NLayoutContent>
|
|
||||||
</NLayout>
|
|
||||||
</NLayout>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
export default Layout
|
|
@ -1,9 +0,0 @@
|
|||||||
export default {
|
|
||||||
path: '/error',
|
|
||||||
name: 'error',
|
|
||||||
component: () => import('@/views/error/index'),
|
|
||||||
meta: {
|
|
||||||
i18nKey: 'Error',
|
|
||||||
icon: 'error',
|
|
||||||
},
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
import dashboard from './dashboard'
|
|
||||||
import reyl from './rely'
|
|
||||||
import error from './error'
|
|
||||||
|
|
||||||
const routes = [dashboard, error, reyl]
|
|
||||||
|
|
||||||
export default routes
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* 弃用自动导入路由模块方式
|
|
||||||
* 采用手动引入子路由模块方式
|
|
||||||
*/
|
|
@ -1,14 +0,0 @@
|
|||||||
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
|
|
||||||
|
|
||||||
import type { App } from 'vue'
|
|
||||||
|
|
||||||
export { useSetting } from './modules/setting' // import { useSetting } from '@/store' 即可使用
|
|
||||||
export { useMenu } from './modules/menu'
|
|
||||||
|
|
||||||
const store = createPinia()
|
|
||||||
|
|
||||||
export const setupStore = (app: App<Element>) => {
|
|
||||||
app.use(store)
|
|
||||||
|
|
||||||
store.use(piniaPluginPersistedstate)
|
|
||||||
}
|
|
@ -1,150 +0,0 @@
|
|||||||
import { getCache, setCache } from '@/utils/cache'
|
|
||||||
import { NEllipsis } from 'naive-ui'
|
|
||||||
import RayIcon from '@/components/RayIcon/index'
|
|
||||||
|
|
||||||
import type { MenuOption } from 'naive-ui'
|
|
||||||
import type { RouteRecordRaw } from 'vue-router'
|
|
||||||
|
|
||||||
export const useMenu = defineStore('menu', () => {
|
|
||||||
const router = useRouter()
|
|
||||||
const route = useRoute()
|
|
||||||
const { t } = useI18n()
|
|
||||||
|
|
||||||
const cacheMenuKey =
|
|
||||||
getCache('menuKey') === 'no' ? '/dashboard' : getCache('menuKey')
|
|
||||||
|
|
||||||
const menuState = reactive({
|
|
||||||
menuKey: cacheMenuKey as string | null, // 当前菜单 `key`
|
|
||||||
options: [] as RouteRecordRaw[], // 菜单列表
|
|
||||||
collapsed: false, // 是否折叠菜单
|
|
||||||
menuTagOptions: [] as RouteRecordRaw[],
|
|
||||||
})
|
|
||||||
|
|
||||||
const handleMenuTagOptions = (item: RouteRecordRaw) => {
|
|
||||||
if (item.path !== menuState.menuKey) {
|
|
||||||
const tag = menuState.menuTagOptions.find(
|
|
||||||
(curr) => curr.path === item.path,
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!tag) {
|
|
||||||
menuState.menuTagOptions.push(item)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param key 菜单更新后的 `key`
|
|
||||||
* @param item 菜单当前 `item`
|
|
||||||
*
|
|
||||||
* 修改 `menu key` 后的回调函数
|
|
||||||
*/
|
|
||||||
const menuModelValueChange = (key: string, item: MenuOption) => {
|
|
||||||
handleMenuTagOptions(item as unknown as RouteRecordRaw)
|
|
||||||
|
|
||||||
menuState.menuKey = key
|
|
||||||
|
|
||||||
router.push(`${item.path}`)
|
|
||||||
setCache('menuKey', key)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param path 路由地址
|
|
||||||
*
|
|
||||||
* 监听路由地址变化更新菜单状态
|
|
||||||
*/
|
|
||||||
const updateMenuKeyWhenRouteUpdate = (path: string) => {
|
|
||||||
const matchMenuItem = (options: MenuOption[]) => {
|
|
||||||
for (const i of options) {
|
|
||||||
if (i?.children?.length) {
|
|
||||||
matchMenuItem(i.children)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (path === i.path) {
|
|
||||||
menuModelValueChange(i.path, i)
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
matchMenuItem(menuState.options)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* 获取菜单列表
|
|
||||||
* 缓存菜单
|
|
||||||
*/
|
|
||||||
const setupAppRoutes = () => {
|
|
||||||
const layout = router.getRoutes().find((route) => route.name === 'layout')
|
|
||||||
|
|
||||||
const resolveRoutes = (routes: RouteRecordRaw[], index: number) => {
|
|
||||||
return routes.map((curr) => {
|
|
||||||
if (curr.children?.length) {
|
|
||||||
curr.children = resolveRoutes(
|
|
||||||
curr.children as RouteRecordRaw[],
|
|
||||||
index++,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const route = {
|
|
||||||
...curr,
|
|
||||||
key: curr.path,
|
|
||||||
label: () =>
|
|
||||||
h(NEllipsis, null, {
|
|
||||||
default: () => t(`GlobalMenuOptions.${curr!.meta!.i18nKey}`),
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
const expandIcon = {
|
|
||||||
icon: () =>
|
|
||||||
h(
|
|
||||||
RayIcon,
|
|
||||||
{
|
|
||||||
name: curr?.meta?.icon as string,
|
|
||||||
size: 20,
|
|
||||||
},
|
|
||||||
{},
|
|
||||||
),
|
|
||||||
}
|
|
||||||
|
|
||||||
const attr = curr.meta?.icon ? Object.assign(route, expandIcon) : route
|
|
||||||
|
|
||||||
// 初始化 `menu tag`
|
|
||||||
if (curr.path === cacheMenuKey) {
|
|
||||||
menuState.menuTagOptions.push(attr)
|
|
||||||
}
|
|
||||||
|
|
||||||
return attr
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
menuState.options = resolveRoutes(layout?.children as RouteRecordRaw[], 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param collapsed 折叠菜单开关
|
|
||||||
*/
|
|
||||||
const collapsedMenu = (collapsed: boolean) =>
|
|
||||||
(menuState.collapsed = collapsed)
|
|
||||||
|
|
||||||
const spliceMenTagOptions = (idx: number) =>
|
|
||||||
menuState.menuTagOptions.splice(idx, 1)
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => route.fullPath,
|
|
||||||
(newData) => {
|
|
||||||
updateMenuKeyWhenRouteUpdate(newData)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
|
||||||
...toRefs(menuState),
|
|
||||||
menuModelValueChange,
|
|
||||||
setupAppRoutes,
|
|
||||||
collapsedMenu,
|
|
||||||
spliceMenTagOptions,
|
|
||||||
}
|
|
||||||
})
|
|
@ -1,57 +0,0 @@
|
|||||||
export const useSetting = defineStore(
|
|
||||||
'setting',
|
|
||||||
() => {
|
|
||||||
const settingState = reactive({
|
|
||||||
drawerPlacement: 'right' as NaiveDrawerPlacement,
|
|
||||||
primaryColorOverride: {
|
|
||||||
common: {
|
|
||||||
primaryColor: '#18A058', // 主题色
|
|
||||||
},
|
|
||||||
},
|
|
||||||
themeValue: false, // `true` 为黑夜主题, `false` 为白色主题
|
|
||||||
reloadRouteLog: true, // 刷新路由开关
|
|
||||||
menuTagLog: true, // 多标签页开关
|
|
||||||
})
|
|
||||||
const { locale } = useI18n()
|
|
||||||
|
|
||||||
const updateLocale = (key: string) => {
|
|
||||||
// TODO: 修改语言
|
|
||||||
locale.value = key
|
|
||||||
}
|
|
||||||
|
|
||||||
const changeTheme = (bool: boolean) => {
|
|
||||||
settingState.themeValue = bool
|
|
||||||
}
|
|
||||||
|
|
||||||
const changePrimaryColor = (value: string) => {
|
|
||||||
settingState.primaryColorOverride.common.primaryColor = value
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param bool 刷新页面开关
|
|
||||||
*/
|
|
||||||
const changeReloadLog = (bool: boolean) =>
|
|
||||||
(settingState.reloadRouteLog = bool)
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param bool 刷新页面开关
|
|
||||||
*/
|
|
||||||
const changeMenuTagLog = (bool: boolean) => (settingState.menuTagLog = bool)
|
|
||||||
|
|
||||||
return {
|
|
||||||
...toRefs(settingState),
|
|
||||||
updateLocale,
|
|
||||||
changeTheme,
|
|
||||||
changePrimaryColor,
|
|
||||||
changeReloadLog,
|
|
||||||
changeMenuTagLog,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
persist: {
|
|
||||||
key: 'piniaSettingStore',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
@ -1,3 +0,0 @@
|
|||||||
$layoutRouterViewContainer: 18px;
|
|
||||||
$layoutHeaderHeight: 64px;
|
|
||||||
$layoutMenuHeight: 46px;
|
|
@ -1,63 +0,0 @@
|
|||||||
import './index.scss'
|
|
||||||
import {
|
|
||||||
NSpace,
|
|
||||||
NCard,
|
|
||||||
NTabs,
|
|
||||||
NTabPane,
|
|
||||||
NGradientText,
|
|
||||||
NDropdown,
|
|
||||||
} from 'naive-ui'
|
|
||||||
import Signin from './components/Signin/index'
|
|
||||||
import Register from './components/Register/index'
|
|
||||||
import { useSetting } from '@/store'
|
|
||||||
import RayIcon from '@/components/RayIcon'
|
|
||||||
import { useLanguageOptions } from '@/language/index'
|
|
||||||
|
|
||||||
const Login = defineComponent({
|
|
||||||
name: 'Login',
|
|
||||||
setup() {
|
|
||||||
const state = reactive({
|
|
||||||
tabsValue: 'signin',
|
|
||||||
})
|
|
||||||
const { t } = useI18n()
|
|
||||||
const { height: windowHeight } = useWindowSize()
|
|
||||||
const settingStore = useSetting()
|
|
||||||
const { updateLocale } = settingStore
|
|
||||||
|
|
||||||
return {
|
|
||||||
...toRefs(state),
|
|
||||||
windowHeight,
|
|
||||||
updateLocale,
|
|
||||||
ray: t,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div class={['login']} style={[`height: ${this.windowHeight}px`]}>
|
|
||||||
<NSpace>
|
|
||||||
<NGradientText class="login-title" type="info">
|
|
||||||
Ray Template
|
|
||||||
</NGradientText>
|
|
||||||
<NDropdown
|
|
||||||
options={useLanguageOptions()}
|
|
||||||
onSelect={(key) => this.updateLocale(key)}
|
|
||||||
>
|
|
||||||
<RayIcon customClassName="login-icon" name="language" size="18" />
|
|
||||||
</NDropdown>
|
|
||||||
</NSpace>
|
|
||||||
<NCard>
|
|
||||||
<NTabs v-model:value={this.tabsValue}>
|
|
||||||
<NTabPane tab={this.ray('LoginModule.Signin')} name="signin">
|
|
||||||
<Signin />
|
|
||||||
</NTabPane>
|
|
||||||
<NTabPane tab={this.ray('LoginModule.Register')} name="register">
|
|
||||||
<Register />
|
|
||||||
</NTabPane>
|
|
||||||
</NTabs>
|
|
||||||
</NCard>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
export default Login
|
|
Loading…
x
Reference in New Issue
Block a user