mirror of
				https://github.com/soybeanjs/soybean-admin.git
				synced 2025-11-04 07:43:42 +08:00 
			
		
		
		
	@@ -7,6 +7,7 @@ import { useRouteStore } from '@/store/modules/route';
 | 
			
		||||
import HorizontalMenu from '../global-menu/base-menu.vue';
 | 
			
		||||
import GlobalLogo from '../global-logo/index.vue';
 | 
			
		||||
import GlobalBreadcrumb from '../global-breadcrumb/index.vue';
 | 
			
		||||
import GlobalSearch from '../global-search/index.vue';
 | 
			
		||||
import { useMixMenuContext } from '../../hooks/use-mix-menu';
 | 
			
		||||
import ThemeButton from './components/theme-button.vue';
 | 
			
		||||
import UserAvatar from './components/user-avatar.vue';
 | 
			
		||||
@@ -54,6 +55,7 @@ const headerMenus = computed(() => {
 | 
			
		||||
      <GlobalBreadcrumb v-if="!appStore.isMobile" class="ml-12px" />
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="h-full flex-y-center justify-end">
 | 
			
		||||
      <GlobalSearch />
 | 
			
		||||
      <FullScreen v-if="!appStore.isMobile" :full="isFullscreen" @click="toggle" />
 | 
			
		||||
      <LangSwitch :lang="appStore.locale" :lang-options="appStore.localeOptions" @change-lang="appStore.changeLocale" />
 | 
			
		||||
      <ThemeSchemaSwitch
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,32 @@
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
import { $t } from '@/locales';
 | 
			
		||||
 | 
			
		||||
defineOptions({ name: 'SearchFooter' });
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="h-44px flex-y-center px-24px">
 | 
			
		||||
    <span class="mr-14px flex-y-center">
 | 
			
		||||
      <icon-mdi-keyboard-return class="icon mr-6px p-2px text-20px" />
 | 
			
		||||
      <span>{{ $t('common.confirm') }}</span>
 | 
			
		||||
    </span>
 | 
			
		||||
    <span class="mr-14px flex-y-center">
 | 
			
		||||
      <icon-mdi-arrow-up-thin class="icon mr-5px p-2px text-20px" />
 | 
			
		||||
      <icon-mdi-arrow-down-thin class="icon mr-6px p-2px text-20px" />
 | 
			
		||||
      <span>{{ $t('common.switch') }}</span>
 | 
			
		||||
    </span>
 | 
			
		||||
    <span class="flex-y-center">
 | 
			
		||||
      <icon-mdi-keyboard-esc class="icon mr-6px p-2px text-20px" />
 | 
			
		||||
      <span>{{ $t('common.close') }}</span>
 | 
			
		||||
    </span>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.icon {
 | 
			
		||||
  box-shadow:
 | 
			
		||||
    inset 0 -2px #cdcde6,
 | 
			
		||||
    inset 0 0 1px 1px #fff,
 | 
			
		||||
    0 1px 2px 1px #1e235a66;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										115
									
								
								src/layouts/modules/global-search/components/search-modal.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								src/layouts/modules/global-search/components/search-modal.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,115 @@
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
import { computed, ref, shallowRef } from 'vue';
 | 
			
		||||
import { useRouter } from 'vue-router';
 | 
			
		||||
import { onKeyStroke, useDebounceFn } from '@vueuse/core';
 | 
			
		||||
import { useRouteStore } from '@/store/modules/route';
 | 
			
		||||
import { useAppStore } from '@/store/modules/app';
 | 
			
		||||
import { $t } from '@/locales';
 | 
			
		||||
import SearchResult from './search-result.vue';
 | 
			
		||||
import SearchFooter from './search-footer.vue';
 | 
			
		||||
 | 
			
		||||
defineOptions({ name: 'SearchModal' });
 | 
			
		||||
 | 
			
		||||
const appStore = useAppStore();
 | 
			
		||||
const isMobile = computed(() => appStore.isMobile);
 | 
			
		||||
const router = useRouter();
 | 
			
		||||
const routeStore = useRouteStore();
 | 
			
		||||
 | 
			
		||||
const keyword = ref('');
 | 
			
		||||
const activePath = ref('');
 | 
			
		||||
const resultOptions = shallowRef<App.Global.Menu[]>([]);
 | 
			
		||||
 | 
			
		||||
const handleSearch = useDebounceFn(search, 300);
 | 
			
		||||
 | 
			
		||||
const modelShow = defineModel<boolean>('show', { required: true });
 | 
			
		||||
 | 
			
		||||
/** 查询 */
 | 
			
		||||
function search() {
 | 
			
		||||
  resultOptions.value = routeStore.searchMenus.filter(menu => {
 | 
			
		||||
    const trimKeyword = keyword.value.toLocaleLowerCase().trim();
 | 
			
		||||
    const title = (menu.i18nKey ? $t(menu.i18nKey) : menu.label).toLocaleLowerCase();
 | 
			
		||||
    return trimKeyword && title.includes(trimKeyword);
 | 
			
		||||
  });
 | 
			
		||||
  activePath.value = resultOptions.value[0]?.routePath ?? '';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function handleClose() {
 | 
			
		||||
  modelShow.value = false;
 | 
			
		||||
  /** 延时处理防止用户看到某些操作 */
 | 
			
		||||
  setTimeout(() => {
 | 
			
		||||
    resultOptions.value = [];
 | 
			
		||||
    keyword.value = '';
 | 
			
		||||
  }, 200);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** key up */
 | 
			
		||||
function handleUp() {
 | 
			
		||||
  const { length } = resultOptions.value;
 | 
			
		||||
  if (length === 0) return;
 | 
			
		||||
  const index = resultOptions.value.findIndex(item => item.routePath === activePath.value);
 | 
			
		||||
  if (index === 0) {
 | 
			
		||||
    activePath.value = resultOptions.value[length - 1].routePath;
 | 
			
		||||
  } else {
 | 
			
		||||
    activePath.value = resultOptions.value[index - 1].routePath;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** key down */
 | 
			
		||||
function handleDown() {
 | 
			
		||||
  const { length } = resultOptions.value;
 | 
			
		||||
  if (length === 0) return;
 | 
			
		||||
  const index = resultOptions.value.findIndex(item => item.routePath === activePath.value);
 | 
			
		||||
  if (index + 1 === length) {
 | 
			
		||||
    activePath.value = resultOptions.value[0].routePath;
 | 
			
		||||
  } else {
 | 
			
		||||
    activePath.value = resultOptions.value[index + 1].routePath;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** key enter */
 | 
			
		||||
function handleEnter(e: Event | undefined) {
 | 
			
		||||
  const { length } = resultOptions.value;
 | 
			
		||||
  if (length === 0 || activePath.value === '') return;
 | 
			
		||||
  e?.preventDefault();
 | 
			
		||||
  handleClose();
 | 
			
		||||
  router.push(activePath.value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
onKeyStroke('Escape', handleClose);
 | 
			
		||||
onKeyStroke('Enter', handleEnter);
 | 
			
		||||
onKeyStroke('ArrowUp', handleUp);
 | 
			
		||||
onKeyStroke('ArrowDown', handleDown);
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <NModal
 | 
			
		||||
    v-model:show="modelShow"
 | 
			
		||||
    :segmented="{ footer: 'soft' }"
 | 
			
		||||
    :closable="false"
 | 
			
		||||
    preset="card"
 | 
			
		||||
    auto-focus
 | 
			
		||||
    footer-style="padding: 0; margin: 0"
 | 
			
		||||
    class="fixed left-0 right-0"
 | 
			
		||||
    :class="[isMobile ? 'size-full top-0px rounded-0' : 'w-630px top-50px']"
 | 
			
		||||
    @after-leave="handleClose"
 | 
			
		||||
  >
 | 
			
		||||
    <NInputGroup>
 | 
			
		||||
      <NInput v-model:value="keyword" clearable :placeholder="$t('common.keywordSearch')" @input="handleSearch">
 | 
			
		||||
        <template #prefix>
 | 
			
		||||
          <icon-uil-search class="text-15px text-#c2c2c2" />
 | 
			
		||||
        </template>
 | 
			
		||||
      </NInput>
 | 
			
		||||
      <NButton v-if="isMobile" type="primary" ghost @click="handleClose">{{ $t('common.cancel') }}</NButton>
 | 
			
		||||
    </NInputGroup>
 | 
			
		||||
 | 
			
		||||
    <div class="mt-20px">
 | 
			
		||||
      <NEmpty v-if="resultOptions.length === 0" :description="$t('common.noData')" />
 | 
			
		||||
      <SearchResult v-else v-model:path="activePath" :options="resultOptions" @enter="handleEnter" />
 | 
			
		||||
    </div>
 | 
			
		||||
    <template #footer>
 | 
			
		||||
      <SearchFooter v-if="!isMobile" />
 | 
			
		||||
    </template>
 | 
			
		||||
  </NModal>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped></style>
 | 
			
		||||
@@ -0,0 +1,57 @@
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
import { useThemeStore } from '@/store/modules/theme';
 | 
			
		||||
import { $t } from '@/locales';
 | 
			
		||||
 | 
			
		||||
defineOptions({ name: 'SearchResult' });
 | 
			
		||||
 | 
			
		||||
interface Props {
 | 
			
		||||
  options: App.Global.Menu[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
defineProps<Props>();
 | 
			
		||||
 | 
			
		||||
interface Emits {
 | 
			
		||||
  (e: 'enter'): void;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const emit = defineEmits<Emits>();
 | 
			
		||||
 | 
			
		||||
const theme = useThemeStore();
 | 
			
		||||
 | 
			
		||||
const active = defineModel<string>('path', { required: true });
 | 
			
		||||
 | 
			
		||||
/** 鼠标移入 */
 | 
			
		||||
async function handleMouse(item: App.Global.Menu) {
 | 
			
		||||
  active.value = item.routePath;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function handleTo() {
 | 
			
		||||
  emit('enter');
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <NScrollbar>
 | 
			
		||||
    <div class="pb-12px">
 | 
			
		||||
      <template v-for="item in options" :key="item.routePath">
 | 
			
		||||
        <div
 | 
			
		||||
          class="mt-8px h-56px flex-y-center cursor-pointer justify-between rounded-4px bg-#e5e7eb px-14px dark:bg-dark"
 | 
			
		||||
          :style="{
 | 
			
		||||
            background: item.routePath === active ? theme.themeColor : '',
 | 
			
		||||
            color: item.routePath === active ? '#fff' : ''
 | 
			
		||||
          }"
 | 
			
		||||
          @click="handleTo"
 | 
			
		||||
          @mouseenter="handleMouse(item)"
 | 
			
		||||
        >
 | 
			
		||||
          <component :is="item.icon" />
 | 
			
		||||
          <span class="ml-5px flex-1">
 | 
			
		||||
            {{ (item.i18nKey && $t(item.i18nKey)) || item.label }}
 | 
			
		||||
          </span>
 | 
			
		||||
          <icon-ant-design-enter-outlined class="icon mr-3px p-2px text-20px" />
 | 
			
		||||
        </div>
 | 
			
		||||
      </template>
 | 
			
		||||
    </div>
 | 
			
		||||
  </NScrollbar>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped></style>
 | 
			
		||||
							
								
								
									
										21
									
								
								src/layouts/modules/global-search/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/layouts/modules/global-search/index.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
import { useBoolean } from '@sa/hooks';
 | 
			
		||||
import { $t } from '@/locales';
 | 
			
		||||
import SearchModal from './components/search-modal.vue';
 | 
			
		||||
 | 
			
		||||
defineOptions({ name: 'GlobalSearch' });
 | 
			
		||||
 | 
			
		||||
const { bool: show, toggle } = useBoolean();
 | 
			
		||||
function handleSearch() {
 | 
			
		||||
  toggle();
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <ButtonIcon :tooltip-content="$t('common.search')" @click="handleSearch">
 | 
			
		||||
    <icon-uil-search class="text-20px" />
 | 
			
		||||
  </ButtonIcon>
 | 
			
		||||
  <SearchModal v-model:show="show" />
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped></style>
 | 
			
		||||
@@ -9,6 +9,7 @@ const local: App.I18n.Schema = {
 | 
			
		||||
    backToHome: 'Back to home',
 | 
			
		||||
    batchDelete: 'Batch Delete',
 | 
			
		||||
    cancel: 'Cancel',
 | 
			
		||||
    close: 'Close',
 | 
			
		||||
    check: 'Check',
 | 
			
		||||
    columnSetting: 'Column Setting',
 | 
			
		||||
    confirm: 'Confirm',
 | 
			
		||||
@@ -17,16 +18,19 @@ const local: App.I18n.Schema = {
 | 
			
		||||
    confirmDelete: 'Are you sure you want to delete?',
 | 
			
		||||
    edit: 'Edit',
 | 
			
		||||
    index: 'Index',
 | 
			
		||||
    keywordSearch: 'Please enter keyword',
 | 
			
		||||
    logout: 'Logout',
 | 
			
		||||
    logoutConfirm: 'Are you sure you want to log out?',
 | 
			
		||||
    lookForward: 'Coming soon',
 | 
			
		||||
    modify: 'Modify',
 | 
			
		||||
    modifySuccess: 'Modify Success',
 | 
			
		||||
    noData: 'No Data',
 | 
			
		||||
    operate: 'Operate',
 | 
			
		||||
    pleaseCheckValue: 'Please check whether the value is valid',
 | 
			
		||||
    refresh: 'Refresh',
 | 
			
		||||
    reset: 'Reset',
 | 
			
		||||
    search: 'Search',
 | 
			
		||||
    switch: 'Switch',
 | 
			
		||||
    tip: 'Tip',
 | 
			
		||||
    update: 'Update',
 | 
			
		||||
    updateSuccess: 'Update Success',
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,7 @@ const local: App.I18n.Schema = {
 | 
			
		||||
    backToHome: '返回首页',
 | 
			
		||||
    batchDelete: '批量删除',
 | 
			
		||||
    cancel: '取消',
 | 
			
		||||
    close: '关闭',
 | 
			
		||||
    check: '勾选',
 | 
			
		||||
    columnSetting: '列设置',
 | 
			
		||||
    confirm: '确认',
 | 
			
		||||
@@ -17,16 +18,19 @@ const local: App.I18n.Schema = {
 | 
			
		||||
    confirmDelete: '确认删除吗?',
 | 
			
		||||
    edit: '编辑',
 | 
			
		||||
    index: '序号',
 | 
			
		||||
    keywordSearch: '请输入关键词搜索',
 | 
			
		||||
    logout: '退出登录',
 | 
			
		||||
    logoutConfirm: '确认退出登录吗?',
 | 
			
		||||
    lookForward: '敬请期待',
 | 
			
		||||
    modify: '修改',
 | 
			
		||||
    modifySuccess: '修改成功',
 | 
			
		||||
    noData: '无数据',
 | 
			
		||||
    operate: '操作',
 | 
			
		||||
    pleaseCheckValue: '请检查输入的值是否合法',
 | 
			
		||||
    refresh: '刷新',
 | 
			
		||||
    reset: '重置',
 | 
			
		||||
    search: '搜索',
 | 
			
		||||
    switch: '切换',
 | 
			
		||||
    tip: '提示',
 | 
			
		||||
    update: '更新',
 | 
			
		||||
    updateSuccess: '更新成功',
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,7 @@ import {
 | 
			
		||||
  getSelectedMenuKeyPathByKey,
 | 
			
		||||
  isRouteExistByRouteName,
 | 
			
		||||
  sortRoutesByOrder,
 | 
			
		||||
  transformMenuToSearchMenus,
 | 
			
		||||
  updateLocaleOfGlobalMenus
 | 
			
		||||
} from './shared';
 | 
			
		||||
 | 
			
		||||
@@ -52,6 +53,7 @@ export const useRouteStore = defineStore(SetupStoreId.Route, () => {
 | 
			
		||||
 | 
			
		||||
  /** Global menus */
 | 
			
		||||
  const menus = ref<App.Global.Menu[]>([]);
 | 
			
		||||
  const searchMenus = computed(() => transformMenuToSearchMenus(menus.value));
 | 
			
		||||
 | 
			
		||||
  /** Get global menus */
 | 
			
		||||
  function getGlobalMenus(routes: ElegantConstRoute[]) {
 | 
			
		||||
@@ -275,6 +277,7 @@ export const useRouteStore = defineStore(SetupStoreId.Route, () => {
 | 
			
		||||
    resetStore,
 | 
			
		||||
    routeHome,
 | 
			
		||||
    menus,
 | 
			
		||||
    searchMenus,
 | 
			
		||||
    updateGlobalMenusByLocale,
 | 
			
		||||
    cacheRoutes,
 | 
			
		||||
    reCacheRoutesByKey,
 | 
			
		||||
 
 | 
			
		||||
@@ -310,3 +310,22 @@ export function getBreadcrumbsByRoute(
 | 
			
		||||
 | 
			
		||||
  return [];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Transform menu to searchMenus
 | 
			
		||||
 *
 | 
			
		||||
 * @param menus - menus
 | 
			
		||||
 * @param treeMap
 | 
			
		||||
 */
 | 
			
		||||
export function transformMenuToSearchMenus(menus: App.Global.Menu[], treeMap: App.Global.Menu[] = []) {
 | 
			
		||||
  if (menus && menus.length === 0) return [];
 | 
			
		||||
  return menus.reduce((acc, cur) => {
 | 
			
		||||
    if (!cur.children) {
 | 
			
		||||
      acc.push(cur);
 | 
			
		||||
    }
 | 
			
		||||
    if (cur.children && cur.children.length > 0) {
 | 
			
		||||
      transformMenuToSearchMenus(cur.children, treeMap);
 | 
			
		||||
    }
 | 
			
		||||
    return acc;
 | 
			
		||||
  }, treeMap);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								src/typings/app.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								src/typings/app.d.ts
									
									
									
									
										vendored
									
									
								
							@@ -255,6 +255,7 @@ declare namespace App {
 | 
			
		||||
        backToHome: string;
 | 
			
		||||
        batchDelete: string;
 | 
			
		||||
        cancel: string;
 | 
			
		||||
        close: string;
 | 
			
		||||
        check: string;
 | 
			
		||||
        columnSetting: string;
 | 
			
		||||
        confirm: string;
 | 
			
		||||
@@ -263,16 +264,19 @@ declare namespace App {
 | 
			
		||||
        confirmDelete: string;
 | 
			
		||||
        edit: string;
 | 
			
		||||
        index: string;
 | 
			
		||||
        keywordSearch: string;
 | 
			
		||||
        logout: string;
 | 
			
		||||
        logoutConfirm: string;
 | 
			
		||||
        lookForward: string;
 | 
			
		||||
        modify: string;
 | 
			
		||||
        modifySuccess: string;
 | 
			
		||||
        noData: string;
 | 
			
		||||
        operate: string;
 | 
			
		||||
        pleaseCheckValue: string;
 | 
			
		||||
        refresh: string;
 | 
			
		||||
        reset: string;
 | 
			
		||||
        search: string;
 | 
			
		||||
        switch: string;
 | 
			
		||||
        tip: string;
 | 
			
		||||
        update: string;
 | 
			
		||||
        updateSuccess: string;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										9
									
								
								src/typings/components.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								src/typings/components.d.ts
									
									
									
									
										vendored
									
									
								
							@@ -14,6 +14,7 @@ declare module 'vue' {
 | 
			
		||||
    DarkModeContainer: typeof import('./../components/common/dark-mode-container.vue')['default']
 | 
			
		||||
    ExceptionBase: typeof import('./../components/common/exception-base.vue')['default']
 | 
			
		||||
    FullScreen: typeof import('./../components/common/full-screen.vue')['default']
 | 
			
		||||
    IconAntDesignEnterOutlined: typeof import('~icons/ant-design/enter-outlined')['default']
 | 
			
		||||
    IconAntDesignReloadOutlined: typeof import('~icons/ant-design/reload-outlined')['default']
 | 
			
		||||
    IconAntDesignSettingOutlined: typeof import('~icons/ant-design/setting-outlined')['default']
 | 
			
		||||
    IconGridiconsFullscreen: typeof import('~icons/gridicons/fullscreen')['default']
 | 
			
		||||
@@ -24,8 +25,13 @@ declare module 'vue' {
 | 
			
		||||
    IconIcRoundSearch: typeof import('~icons/ic/round-search')['default']
 | 
			
		||||
    IconLocalBanner: typeof import('~icons/local/banner')['default']
 | 
			
		||||
    IconLocalLogo: typeof import('~icons/local/logo')['default']
 | 
			
		||||
    IconMdiArrowDownThin: typeof import('~icons/mdi/arrow-down-thin')['default']
 | 
			
		||||
    IconMdiArrowUpThin: typeof import('~icons/mdi/arrow-up-thin')['default']
 | 
			
		||||
    IconMdiDrag: typeof import('~icons/mdi/drag')['default']
 | 
			
		||||
    IconMdiKeyboardEsc: typeof import('~icons/mdi/keyboard-esc')['default']
 | 
			
		||||
    IconMdiKeyboardReturn: typeof import('~icons/mdi/keyboard-return')['default']
 | 
			
		||||
    IconMdiRefresh: typeof import('~icons/mdi/refresh')['default']
 | 
			
		||||
    IconUilSearch: typeof import('~icons/uil/search')['default']
 | 
			
		||||
    LangSwitch: typeof import('./../components/common/lang-switch.vue')['default']
 | 
			
		||||
    LookForward: typeof import('./../components/custom/look-forward.vue')['default']
 | 
			
		||||
    MenuToggler: typeof import('./../components/common/menu-toggler.vue')['default']
 | 
			
		||||
@@ -43,6 +49,7 @@ declare module 'vue' {
 | 
			
		||||
    NDrawer: typeof import('naive-ui')['NDrawer']
 | 
			
		||||
    NDrawerContent: typeof import('naive-ui')['NDrawerContent']
 | 
			
		||||
    NDropdown: typeof import('naive-ui')['NDropdown']
 | 
			
		||||
    NEmpty: typeof import('naive-ui')['NEmpty']
 | 
			
		||||
    NForm: typeof import('naive-ui')['NForm']
 | 
			
		||||
    NFormItem: typeof import('naive-ui')['NFormItem']
 | 
			
		||||
    NFormItemGi: typeof import('naive-ui')['NFormItemGi']
 | 
			
		||||
@@ -56,11 +63,13 @@ declare module 'vue' {
 | 
			
		||||
    NLoadingBarProvider: typeof import('naive-ui')['NLoadingBarProvider']
 | 
			
		||||
    NMenu: typeof import('naive-ui')['NMenu']
 | 
			
		||||
    NMessageProvider: typeof import('naive-ui')['NMessageProvider']
 | 
			
		||||
    NModal: typeof import('naive-ui')['NModal']
 | 
			
		||||
    NNotificationProvider: typeof import('naive-ui')['NNotificationProvider']
 | 
			
		||||
    NPopconfirm: typeof import('naive-ui')['NPopconfirm']
 | 
			
		||||
    NPopover: typeof import('naive-ui')['NPopover']
 | 
			
		||||
    NRadio: typeof import('naive-ui')['NRadio']
 | 
			
		||||
    NRadioGroup: typeof import('naive-ui')['NRadioGroup']
 | 
			
		||||
    NScrollbar: typeof import('naive-ui')['NScrollbar']
 | 
			
		||||
    NSelect: typeof import('naive-ui')['NSelect']
 | 
			
		||||
    NSpace: typeof import('naive-ui')['NSpace']
 | 
			
		||||
    NStatistic: typeof import('naive-ui')['NStatistic']
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user