v3.1.1,补充面包屑和修复一些小问题

This commit is contained in:
ray_wuhao 2023-03-03 14:46:56 +08:00
parent 13db02c6c3
commit 5676356af5
29 changed files with 647 additions and 189 deletions

13
CHANGELOG.md Normal file
View File

@ -0,0 +1,13 @@
# CHANGE LOG
## 3.1.1
### Fixes
- 修复国际化语言包模块合并处理不能正常合并问题
- 修复国际化切换时,面包屑、标签页不能正常切换
### Feats
- 新增面包屑
- 支持国际化语言包分包管理(但是,依旧是合并到一个文件中,所以需要注意 key 的管理)

View File

@ -8,6 +8,7 @@
"scrollReveal": "Scroll Reveal",
"Axios": "Axios Request",
"Table": "Table",
"MultiMenu": "MultiMenu",
"Doc": "Doc",
"DocLocal": "Doc (China)"
},

View File

@ -8,6 +8,7 @@
"scrollReveal": "Scroll Reveal",
"Axios": "Axios Request",
"Table": "Table",
"MultiMenu": "MultiMenu",
"Doc": "Doc",
"DocLocal": "Doc (China)"
},

View File

@ -8,6 +8,7 @@
"scrollReveal": "滚动动画",
"Axios": "请求",
"Table": "表格",
"MultiMenu": "多级菜单",
"Doc": "文档",
"DocLocal": "文档 (国内地址)"
},

View File

@ -8,6 +8,7 @@
"scrollReveal": "Scroll Reveal",
"Axios": "Axios Request",
"Table": "Table",
"MultiMenu": "MultiMenu",
"Doc": "Doc",
"DocLocal": "Doc (China)"
},

View File

@ -8,6 +8,7 @@
"scrollReveal": "滚动动画",
"Axios": "请求",
"Table": "表格",
"MultiMenu": "多级菜单",
"Doc": "文档",
"DocLocal": "文档 (国内地址)"
},

View File

@ -8,6 +8,7 @@
"scrollReveal": "滚动动画",
"Axios": "请求",
"Table": "表格",
"MultiMenu": "多级菜单",
"Doc": "文档",
"DocLocal": "文档 (国内地址)"
},

View File

@ -1,7 +1,7 @@
{
"name": "ray-template",
"private": true,
"version": "3.1.0",
"version": "3.1.1",
"type": "module",
"scripts": {
"dev": "vite",

View File

@ -28,6 +28,7 @@ import { createI18n } from 'vue-i18n'
import { naiveLocales } from './language'
import { getCache } from '@use-utils/cache'
import { forIn, merge } from 'lodash-es'
export { naiveLocales, localOptions } from './language'
@ -51,10 +52,16 @@ export const getMatchLanguageModule = () => {
})
const moduleKeys = Object.keys(modules)
moduleKeys.forEach((curr) => {
const k = curr.match(reg)?.[1] as string
msg[k] = Object.assign({}, JSON.parse(modules[curr]))
moduleKeys.forEach((curr) => {
const k = curr.match(reg)?.[1] as string // 当前语言包类型(zh-CN, en-US...)
const content = JSON.parse(modules[curr]) // 当前语言包内容
msg[k] = merge({}, msg[k])
forIn(content, (value, ckey) => {
msg[k][ckey] = merge(msg[k][ckey], value)
})
})
} catch (e) {
console.error(e)

View File

@ -19,9 +19,11 @@ const MenuTag = defineComponent({
name: 'MenuTag',
setup() {
const menuStore = useMenu()
const { menuTagOptions, menuKey } = storeToRefs(menuStore)
const { menuKey } = storeToRefs(menuStore)
const { menuModelValueChange, spliceMenTagOptions } = menuStore
const modelMenuTagOptions = computed(() => menuStore.menuTagOptions)
/**
*
* @param idx
@ -32,7 +34,7 @@ const MenuTag = defineComponent({
spliceMenTagOptions(idx)
if (menuKey.value !== '/dashboard') {
const options = menuTagOptions.value as MenuOption[]
const options = modelMenuTagOptions.value
const length = options.length
const tag = options[length - 1]
@ -50,7 +52,7 @@ const MenuTag = defineComponent({
}
return {
menuTagOptions,
modelMenuTagOptions,
menuModelValueChange,
handleCloseTag,
menuKey,
@ -61,10 +63,10 @@ const MenuTag = defineComponent({
return (
<NScrollbar class="menu-tag" xScrollable>
<NSpace class="menu-tag-sapce" wrap={false} align="center">
{this.menuTagOptions.map((curr, idx) => (
{this.modelMenuTagOptions.map((curr, idx) => (
<NTag
closable={
curr.key !== '/dashboard' && this.menuTagOptions.length > 1
curr.key !== '/dashboard' && this.modelMenuTagOptions.length > 1
}
onClose={() => this.handleCloseTag(idx)}
type={curr.key === this.menuKey ? 'success' : 'info'}

View File

@ -0,0 +1,76 @@
/**
*
* @author Ray <https://github.com/XiaoDaiGua-Ray>
*
* @date 2023-03-03
*
* @workspace ray-template
*
* @remark
*/
/**
*
*
*
* ,
*
* <span> , Runtime directive used on component...
*/
import { NDropdown, NBreadcrumb, NBreadcrumbItem } from 'naive-ui'
import { useMenu } from '@/store'
import type { DropdownOption } from 'naive-ui'
const Breadcrumb = defineComponent({
name: 'Breadcrumb',
setup() {
const menuStore = useMenu()
const { menuModelValueChange } = menuStore
const modelBreadcrumbOptions = computed(() => menuStore.breadcrumbOptions)
const handleDropdownSelect = (
key: string | number,
option: DropdownOption,
) => {
menuModelValueChange(key, option)
}
return {
modelBreadcrumbOptions,
handleDropdownSelect,
}
},
render() {
return (
<NBreadcrumb>
{this.modelBreadcrumbOptions.map((curr) => (
<NBreadcrumbItem key={curr.key}>
<NDropdown
labelField="breadcrumbLabel"
options={
curr.children && curr.children?.length > 1 ? curr.children : []
}
onSelect={this.handleDropdownSelect.bind(this)}
>
{{
default: () => (
<span>
{curr.label && typeof curr.label === 'function'
? curr.label()
: curr.breadcrumbLabel}
</span>
),
}}
</NDropdown>
</NBreadcrumbItem>
))}
</NBreadcrumb>
)
},
})
export default Breadcrumb

View File

@ -38,8 +38,12 @@ const SettingDrawer = defineComponent({
const settingStore = useSetting()
const { changePrimaryColor, changeSwitcher } = settingStore
const { themeValue, primaryColorOverride, menuTagSwitch } =
storeToRefs(settingStore)
const {
themeValue,
primaryColorOverride,
menuTagSwitch,
breadcrumbSwitch,
} = storeToRefs(settingStore)
const modelShow = computed({
get: () => props.show,
@ -61,6 +65,7 @@ const SettingDrawer = defineComponent({
primaryColorOverride,
menuTagSwitch,
changeSwitcher,
breadcrumbSwitch,
}
},
render() {
@ -135,6 +140,14 @@ const SettingDrawer = defineComponent({
}
/>
</NDescriptionsItem>
<NDescriptionsItem label="显示面包屑">
<NSwitch
v-model:value={this.breadcrumbSwitch}
onUpdateValue={(bool: boolean) =>
this.changeSwitcher(bool, 'breadcrumbSwitch')
}
/>
</NDescriptionsItem>
</NDescriptions>
</NSpace>
</NDrawerContent>

View File

@ -15,6 +15,7 @@ import { NLayoutHeader, NSpace, NTooltip, NDropdown, NTag } from 'naive-ui'
import RayIcon from '@/components/RayIcon/index'
import RayTooltipIcon from '@/components/RayTooltipIcon/index'
import SettingDrawer from './components/SettingDrawer/index'
import Breadcrumb from './components/Breadcrumb/index'
import { useSetting } from '@/store'
import { localOptions } from '@/language/index'
@ -39,7 +40,7 @@ const SiderBar = defineComponent({
const { t } = useI18n()
const { updateLocale, changeSwitcher } = settingStore
const modelDrawerPlacement = ref(settingStore.drawerPlacement)
const { drawerPlacement, breadcrumbSwitch } = storeToRefs(settingStore)
const showSettings = ref(false)
const person = getCache('person')
const spaceItemStyle = {
@ -127,12 +128,13 @@ const SiderBar = defineComponent({
rightTooltipIconOptions,
t,
handleIconClick,
modelDrawerPlacement,
showSettings,
updateLocale,
handlePersonSelect,
person,
spaceItemStyle,
drawerPlacement,
breadcrumbSwitch,
}
},
render() {
@ -159,6 +161,7 @@ const SiderBar = defineComponent({
}}
</NTooltip>
))}
{this.breadcrumbSwitch ? <Breadcrumb /> : ''}
</NSpace>
<NSpace align="center" itemStyle={this.spaceItemStyle}>
{this.rightTooltipIconOptions.map((curr) => (
@ -203,7 +206,7 @@ const SiderBar = defineComponent({
</NSpace>
<SettingDrawer
v-model:show={this.showSettings}
placement={this.modelDrawerPlacement}
placement={this.drawerPlacement}
/>
</NLayoutHeader>
)

View File

@ -4,10 +4,11 @@ import { constantRoutes } from './routes'
import { permissionRouter as _permissionRouter } from './permission'
import type { App } from 'vue'
import type { RouteRecordRaw } from 'vue-router'
export const router = createRouter({
history: createWebHashHistory(),
routes: constantRoutes,
routes: constantRoutes as unknown as RouteRecordRaw[],
scrollBehavior: () => ({ left: 0, top: 0 }),
})

View File

@ -6,6 +6,7 @@ import scrollReveal from './scroll-reveal'
import axios from './axios'
import table from './table'
import doc from './doc'
import multiMenu from './multi-menu'
import docLocal from './doc-local'
const routes = [
@ -15,6 +16,7 @@ const routes = [
axios,
scrollReveal,
error,
multiMenu,
doc,
docLocal,
reyl,

View File

@ -0,0 +1,40 @@
export default {
path: '/multi-menu',
name: 'multi-menu',
component: () => import('@/views/multi-menu/index'),
meta: {
i18nKey: 'MultiMenu',
icon: 'table',
},
children: [
{
path: 'multi-menu-one',
name: 'multi-menu-one',
component: () => import('@/views/multi-menu/views/multi-menu-one/index'),
meta: {
noLocalTitle: '多级菜单-1',
},
},
{
path: 'multi-menu-two',
name: 'multi-menu-two',
component: () => import('@/views/multi-menu/views/multi-menu-two/index'),
meta: {
noLocalTitle: '多级菜单-2',
},
children: [
{
path: 'sub-menu',
name: 'sub-menu',
component: () =>
import(
'@/views/multi-menu/views/multi-menu-two/views/sub-menu/index'
),
meta: {
noLocalTitle: '多级菜单-2-1',
},
},
],
},
],
}

23
src/router/remark.md Normal file
View File

@ -0,0 +1,23 @@
- 类型
```ts
interface RouteMeta {
i18nKey: string
icon?: string
windowOpen?: string
role?: string[]
hidden?: boolean
noLocalTitle?: string | number
}
```
- 说明
```
i18nKey: i18n 国际化 key, 会优先使用该字段
icon: icon 图标, 用于 Menu 菜单(依赖 RayIcon 组件实现)
windowOpen: 超链接打开
role: 权限表
hidden: 是否显示
noLocalTitle: 不使用国际化渲染 Menu Titile
```

View File

@ -3,7 +3,7 @@ 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'
export { useMenu } from './modules/menu/index'
export { useSignin } from './modules/signin'
const store = createPinia()

View File

@ -1,165 +0,0 @@
import { NEllipsis } from 'naive-ui'
import RayIcon from '@/components/RayIcon/index'
import { getCache, setCache } from '@/utils/cache'
import { validRole } from '@/router/basic'
import type { MenuOption } from 'naive-ui'
import type { RouteMeta } 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 IMenuOptions[], // 菜单列表
collapsed: false, // 是否折叠菜单
menuTagOptions: [] as TagMenuOptions[],
})
const handleMenuTagOptions = (item: IMenuOptions) => {
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) => {
const meta = item.meta as RouteMeta
if (meta.windowOpen) {
window.open(meta.windowOpen)
} else {
handleMenuTagOptions(item as unknown as TagMenuOptions)
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 as MenuOption[])
}
/**
*
* @remark ,
* @remark ,
*/
const setupAppRoutes = () => {
const layout = router.getRoutes().find((route) => route.name === 'layout')
const resolveRoutes = (routes: IMenuOptions[], index: number) => {
return routes.map((curr) => {
if (curr.children?.length) {
curr.children = resolveRoutes(curr.children, index++)
}
const { meta } = curr
const route = {
...curr,
key: curr.path,
label: () =>
h(NEllipsis, null, {
default: () => t(`GlobalMenuOptions.${meta!.i18nKey}`),
}),
}
const expandIcon = {
icon: () =>
h(
RayIcon,
{
name: meta!.icon as string,
size: 20,
},
{},
),
}
const attr: IMenuOptions = meta?.icon
? Object.assign({}, route, expandIcon)
: route
if (curr.path === cacheMenuKey) {
menuState.menuTagOptions.push(attr)
}
attr.show = validRole(curr)
return attr
})
}
menuState.options = resolveRoutes(layout?.children as IMenuOptions[], 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)
},
{
immediate: true,
},
)
return {
...toRefs(menuState),
menuModelValueChange,
setupAppRoutes,
collapsedMenu,
spliceMenTagOptions,
}
})

View File

@ -0,0 +1,110 @@
/**
*
* @author Ray <https://github.com/XiaoDaiGua-Ray>
*
* @date 2023-03-03
*
* @workspace ray-template
*
* @remark
*/
/** 本方法感谢 <https://yunkuangao.me/> 的支持 */
/**
*
* @param node
* @param key
* @param value
*
* @remark
*/
const check = (
node: IMenuOptions,
key: string | number,
value: string | number,
) => {
return node[key] === value || node.key === value
}
/**
*
* @param options
* @param key
* @param value
*
* @remark
*/
const process = (
options: IMenuOptions,
key: string | number,
value: string | number,
) => {
const temp: IMenuOptions[] = []
// 检查当前节点是否匹配值
if (check(options, key, value)) {
temp.push(options)
return temp
}
// 遍历子节点
if (options.children && options.children.length > 0) {
for (const it of options.children) {
// 子节点递归调用
const innerTemp = process(it, key, value)
// 如果子节点匹配到了,则将当前节点加入数组
if (innerTemp.length > 0) {
temp.push(options, ...innerTemp)
}
}
}
return temp
}
/**
*
* @param options
* @param key
* @param value
*/
export const parse = (
options: IMenuOptions[],
key: string | number,
value: string | number,
) => {
const temp = []
for (const it of options) {
const innerTemp = process(it, key, value)
if (innerTemp.length > 0) {
temp.push(...innerTemp)
}
}
return temp
}
/**
*
* @param item menu options
*
* @remark
*/
export const matchMenuOption = (
item: IMenuOptions,
key: MenuKey,
menuTagOptions: TagMenuOptions[],
) => {
if (item.path !== key) {
const tag = menuTagOptions.find((curr) => curr.path === item.path)
if (!tag) {
menuTagOptions.push(item)
}
}
}

View File

@ -0,0 +1,218 @@
/**
*
* @author Ray <https://github.com/XiaoDaiGua-Ray>
*
* @date 2022-11-03
*
* @workspace ray-template
*
* @remark
*/
/**
*
* menu pinia store
*
* :
* - BreadcrumbMenuTagMenuMenu
* - BreadcrumbMenuTagMenuMenu vue-router routers,
*/
import { NEllipsis } from 'naive-ui'
import RayIcon from '@/components/RayIcon/index'
import { getCache, setCache } from '@/utils/cache'
import { validRole } from '@/router/basic'
import { parse, matchMenuOption } from './helper'
import type { MenuOption } from 'naive-ui'
import type { RouteMeta } 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 MenuKey, // 当前菜单 `key`
options: [] as IMenuOptions[], // 菜单列表
collapsed: false, // 是否折叠菜单
menuTagOptions: [] as TagMenuOptions[], // tag 标签菜单
breadcrumbOptions: [] as IMenuOptions[], // 面包屑菜单
})
/**
*
* @param key `key`
* @param item `item`
*
* `menu key`
*/
const menuModelValueChange = (key: string | number, item: MenuOption) => {
const meta = item.meta as RouteMeta
if (meta.windowOpen) {
window.open(meta.windowOpen)
} else {
// 防止重复点击做重复操作处理
if (menuState.menuKey !== key) {
matchMenuOption(
item as unknown as TagMenuOptions,
menuState.menuKey,
menuState.menuTagOptions,
)
menuState.breadcrumbOptions = parse(menuState.options, 'key', key) // 获取面包屑
if (key[0] !== '/') {
const p = menuState.breadcrumbOptions
.map((curr) => curr.key)
.join('/')
router.push(p)
} else {
router.push(item.path as string)
}
menuState.menuKey = key
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 as MenuOption[])
}
/**
*
* @remark ,
* @remark ,
*/
const setupAppRoutes = () => {
const layout = router.getRoutes().find((route) => route.name === 'layout')
const resolveRoutes = (routes: IMenuOptions[], index: number) => {
return routes.map((curr) => {
if (curr.children?.length) {
curr.children = resolveRoutes(curr.children, index++)
}
const { meta } = curr
const label = computed(() =>
meta?.i18nKey
? t(`GlobalMenuOptions.${meta!.i18nKey}`)
: meta?.noLocalTitle,
)
/** 拼装菜单项 */
const route = {
...curr,
key: curr.path,
label: () =>
h(NEllipsis, null, {
default: () => label.value,
}),
breadcrumbLabel: label.value,
} as IMenuOptions
/** 是否有 icon */
const expandIcon = {
icon: () =>
h(
RayIcon,
{
name: meta!.icon as string,
size: 20,
},
{},
),
}
const attr: IMenuOptions = meta?.icon
? Object.assign({}, route, expandIcon)
: route
if (curr.path === cacheMenuKey) {
menuState.menuTagOptions.push(attr)
}
attr.show = validRole(curr)
return attr
})
}
menuState.options = resolveRoutes(layout?.children as IMenuOptions[], 0)
/** 初始化后渲染面包屑 */
nextTick(() => {
menuState.breadcrumbOptions = parse(
menuState.options,
'key',
menuState.menuKey as string,
)
})
}
/**
*
* @param collapsed
*/
const collapsedMenu = (collapsed: boolean) =>
(menuState.collapsed = collapsed)
const spliceMenTagOptions = (idx: number) =>
menuState.menuTagOptions.splice(idx, 1)
watch(
() => route.fullPath,
(newData) => {
updateMenuKeyWhenRouteUpdate(newData)
},
{
immediate: true,
},
)
return {
...toRefs(menuState),
menuModelValueChange,
setupAppRoutes,
collapsedMenu,
spliceMenTagOptions,
}
},
{
persist: {
key: 'piniaMenuStore',
storage: window.sessionStorage,
paths: ['breadcrumbOptions', 'menuKey'],
},
},
)

View File

@ -1,4 +1,5 @@
import { naiveLocales, getDefaultNaiveLocal } from '@/language/index'
import { setCache } from '@use-utils/cache'
export const useSetting = defineStore(
'setting',
@ -15,6 +16,7 @@ export const useSetting = defineStore(
menuTagSwitch: true, // 多标签页开关
naiveLocal: getDefaultNaiveLocal(), // `naive ui` 语言包
spinSwitch: false, // 全屏加载
breadcrumbSwitch: true, // 面包屑开关
})
const { locale } = useI18n()
@ -22,6 +24,8 @@ export const useSetting = defineStore(
// TODO: 修改语言
locale.value = key
settingState.naiveLocal = naiveLocales(key)
setCache('localeLanguage', key, 'localStorage')
}
const changePrimaryColor = (value: string) => {

View File

@ -13,7 +13,11 @@ declare global {
show?: boolean
children?: IMenuOptions[]
meta?: RouteMeta
breadcrumbLabel?: string
noLocalTitle?: string | number
}
declare interface TagMenuOptions extends IMenuOptions {}
declare type MenuKey = null | string | number
}

View File

@ -7,6 +7,7 @@ import {
NLayoutHeader,
NSpace,
NInput,
NButton,
} from 'naive-ui'
import { onAxiosTest } from '@use-api/test'
@ -41,9 +42,13 @@ const Axios = defineComponent({
]
const handleInputCityValue = async (value: string) => {
const cb = await onAxiosTest(value)
try {
const cb = await onAxiosTest(value)
state.weatherData = cb.data as unknown as IUnknownObjectKey[]
state.weatherData = cb.data as unknown as IUnknownObjectKey[]
} catch (e) {
window.$message.error('请求已被取消')
}
}
onBeforeMount(async () => {
@ -62,20 +67,23 @@ const Axios = defineComponent({
<NLayout>
<NLayoutHeader bordered>
<NCard title="请求函数">
axios , , .
axios
<p>
=&gt; =&gt; 使3g网络 =&gt;
</p>
</NCard>
</NLayoutHeader>
<NLayoutHeader bordered>
<NSpace
class="axios-header__btn"
align="center"
justify="space-between"
>
<NSpace class="axios-header__btn" align="center">
<NInput
v-model:value={this.inputCityValue}
onInput={this.handleInputCityValue.bind(this)}
placeholder="请输入城市"
/>
<NButton onClick={this.handleInputCityValue.bind(this, '')}>
</NButton>
</NSpace>
</NLayoutHeader>
<NLayoutContent>

View File

@ -0,0 +1,24 @@
/**
*
* @author Ray <https://github.com/XiaoDaiGua-Ray>
*
* @date 2023-03-01
*
* @workspace ray-template
*
* @remark
*/
import { RouterView } from 'vue-router'
const MultiMenu = defineComponent({
name: 'MultiMenu',
setup() {
return {}
},
render() {
return <RouterView />
},
})
export default MultiMenu

View File

@ -0,0 +1,22 @@
/**
*
* @author Ray <https://github.com/XiaoDaiGua-Ray>
*
* @date 2023-03-01
*
* @workspace ray-template
*
* @remark
*/
const MultiMenuOne = defineComponent({
name: 'MultiMenuOne',
setup() {
return {}
},
render() {
return <div>-1</div>
},
})
export default MultiMenuOne

View File

@ -0,0 +1,24 @@
/**
*
* @author Ray <https://github.com/XiaoDaiGua-Ray>
*
* @date 2023-03-01
*
* @workspace ray-template
*
* @remark
*/
import { RouterView } from 'vue-router'
const MultiMenuTwo = defineComponent({
name: 'MultiMenuTwo',
setup() {
return {}
},
render() {
return <RouterView />
},
})
export default MultiMenuTwo

View File

@ -0,0 +1,22 @@
/**
*
* @author Ray <https://github.com/XiaoDaiGua-Ray>
*
* @date 2023-03-01
*
* @workspace ray-template
*
* @remark
*/
const SubMenu = defineComponent({
name: 'SubMenu',
setup() {
return {}
},
render() {
return <div>-2-1</div>
},
})
export default SubMenu

1
src/vite-env.d.ts vendored
View File

@ -17,6 +17,7 @@ declare module 'vue-router' {
windowOpen?: string
role?: string[]
hidden?: boolean
noLocalTitle?: string | number
}
}