菜单、菜单筛选、个人中心、基本信息、切换用户
Frontend CI/CD / build (web-office) (push) Failing after 11s
Details
Frontend CI/CD / build (web-office) (push) Failing after 11s
Details
This commit is contained in:
parent
3e41e8ca50
commit
154c104148
Binary file not shown.
After Width: | Height: | Size: 3.3 KiB |
|
@ -20,6 +20,9 @@ import { $t } from '#/locales';
|
||||||
import { useAuthStore } from '#/store';
|
import { useAuthStore } from '#/store';
|
||||||
import LoginForm from '#/views/_core/authentication/login.vue';
|
import LoginForm from '#/views/_core/authentication/login.vue';
|
||||||
|
|
||||||
|
import { UserInfo,UserSwitch,UserLike } from '#/layouts/user';
|
||||||
|
|
||||||
|
|
||||||
const notifications = ref<NotificationItem[]>([
|
const notifications = ref<NotificationItem[]>([
|
||||||
{
|
{
|
||||||
avatar: 'https://avatar.vercel.sh/vercel.svg?text=VB',
|
avatar: 'https://avatar.vercel.sh/vercel.svg?text=VB',
|
||||||
|
@ -61,27 +64,21 @@ const showDot = computed(() =>
|
||||||
const menus = computed(() => [
|
const menus = computed(() => [
|
||||||
{
|
{
|
||||||
handler: () => {
|
handler: () => {
|
||||||
openWindow(VBEN_DOC_URL, {
|
infoVisible.value = true
|
||||||
target: '_blank',
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
icon: BookOpenText,
|
icon: BookOpenText,
|
||||||
text: '个人信息',
|
text: '个人信息',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
handler: () => {
|
handler: () => {
|
||||||
openWindow(VBEN_GITHUB_URL, {
|
switchVisible.value = true
|
||||||
target: '_blank',
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
icon: MdiGithub,
|
icon: MdiGithub,
|
||||||
text: '切换租户',
|
text: '切换租户',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
handler: () => {
|
handler: () => {
|
||||||
openWindow(`${VBEN_GITHUB_URL}/issues`, {
|
likeVisible.value = true
|
||||||
target: '_blank',
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
icon: CircleHelp,
|
icon: CircleHelp,
|
||||||
text: '个人偏好',
|
text: '个人偏好',
|
||||||
|
@ -103,6 +100,10 @@ function handleNoticeClear() {
|
||||||
function handleMakeAll() {
|
function handleMakeAll() {
|
||||||
notifications.value.forEach((item) => (item.isRead = true));
|
notifications.value.forEach((item) => (item.isRead = true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let infoVisible = ref(false)
|
||||||
|
let switchVisible = ref(false)
|
||||||
|
let likeVisible = ref(false)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -110,7 +111,7 @@ function handleMakeAll() {
|
||||||
|
|
||||||
<template #user-dropdown>
|
<template #user-dropdown>
|
||||||
<UserDropdown :avatar :menus :text="userStore.userInfo?.realName"
|
<UserDropdown :avatar :menus :text="userStore.userInfo?.realName"
|
||||||
@logout="handleLogout" :hideLockLcreen="true" />
|
@logout="handleLogout" />
|
||||||
</template>
|
</template>
|
||||||
<template #notification>
|
<template #notification>
|
||||||
<Notification :dot="showDot" :notifications="notifications" @clear="handleNoticeClear" :icColor="'#fff'"
|
<Notification :dot="showDot" :notifications="notifications" @clear="handleNoticeClear" :icColor="'#fff'"
|
||||||
|
@ -125,4 +126,8 @@ function handleMakeAll() {
|
||||||
<LockScreen :avatar @to-login="handleLogout" />
|
<LockScreen :avatar @to-login="handleLogout" />
|
||||||
</template>
|
</template>
|
||||||
</BasicLayout>
|
</BasicLayout>
|
||||||
|
|
||||||
|
<UserInfo v-model:visible="infoVisible"></UserInfo>
|
||||||
|
<UserSwitch v-model:visible="switchVisible"></UserSwitch>
|
||||||
|
<UserLike v-model:visible="likeVisible"></UserLike>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -3,10 +3,9 @@ import { computed, useSlots } from 'vue';
|
||||||
|
|
||||||
import { preferences, usePreferences } from '@vben/preferences';
|
import { preferences, usePreferences } from '@vben/preferences';
|
||||||
import { useAccessStore } from '@vben/stores';
|
import { useAccessStore } from '@vben/stores';
|
||||||
import { VbenFullScreen } from '@vben-core/shadcn-ui';
|
import VbenFullScreen from './../../full-screen/full-screen.vue';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
GlobalSearch,
|
|
||||||
LanguageToggle,
|
LanguageToggle,
|
||||||
PreferencesButton,
|
PreferencesButton,
|
||||||
ThemeToggle,
|
ThemeToggle,
|
||||||
|
@ -121,11 +120,6 @@ function clearPreferencesAndLogout() {
|
||||||
<template v-for="slot in rightSlots" :key="slot.name">
|
<template v-for="slot in rightSlots" :key="slot.name">
|
||||||
<slot :name="slot.name">
|
<slot :name="slot.name">
|
||||||
<template v-if="slot.name === 'global-search'">
|
<template v-if="slot.name === 'global-search'">
|
||||||
<!-- <GlobalSearch
|
|
||||||
:enable-shortcut-key="globalSearchShortcutKey"
|
|
||||||
:menus="accessStore.accessMenus"
|
|
||||||
class="mr-1 sm:mr-4"
|
|
||||||
/> -->
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-else-if="slot.name === 'preferences'">
|
<template v-else-if="slot.name === 'preferences'">
|
||||||
|
|
|
@ -13,7 +13,8 @@ import {
|
||||||
import { useLockStore, useUserStore } from '@vben/stores';
|
import { useLockStore, useUserStore } from '@vben/stores';
|
||||||
import { deepToRaw, mapTree } from '@vben/utils';
|
import { deepToRaw, mapTree } from '@vben/utils';
|
||||||
import { VbenAdminLayout } from '@vben-core/layout-ui';
|
import { VbenAdminLayout } from '@vben-core/layout-ui';
|
||||||
import { Toaster, VbenBackTop, VbenLogo } from '@vben-core/shadcn-ui';
|
import { Toaster, VbenBackTop } from '@vben-core/shadcn-ui';
|
||||||
|
import { VbenLogo } from '#/layouts/logo';
|
||||||
|
|
||||||
import { Breadcrumb, CheckUpdates, Preferences } from '@vben/layouts';
|
import { Breadcrumb, CheckUpdates, Preferences } from '@vben/layouts';
|
||||||
import { LayoutContent, LayoutContentSpinner } from './content';
|
import { LayoutContent, LayoutContentSpinner } from './content';
|
||||||
|
@ -201,6 +202,7 @@ const headerSlots = computed(() => {
|
||||||
:text="'西北油田办公平台'"
|
:text="'西北油田办公平台'"
|
||||||
:theme="'!white'"
|
:theme="'!white'"
|
||||||
:textClass="'text-white text-2xl'"
|
:textClass="'text-white text-2xl'"
|
||||||
|
:logoSize="100"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<!-- 头部区域 -->
|
<!-- 头部区域 -->
|
||||||
|
|
|
@ -4,6 +4,10 @@ import type { MenuProps } from '@vben-core/menu-ui';
|
||||||
|
|
||||||
import { Menu } from '@vben-core/menu-ui';
|
import { Menu } from '@vben-core/menu-ui';
|
||||||
|
|
||||||
|
import {
|
||||||
|
GlobalSearch,
|
||||||
|
} from './../../global-search';
|
||||||
|
|
||||||
interface Props extends MenuProps {
|
interface Props extends MenuProps {
|
||||||
menus: MenuRecordRaw[];
|
menus: MenuRecordRaw[];
|
||||||
}
|
}
|
||||||
|
@ -20,9 +24,20 @@ const emit = defineEmits<{
|
||||||
function handleMenuSelect(key: string) {
|
function handleMenuSelect(key: string) {
|
||||||
emit('select', key, props.mode);
|
emit('select', key, props.mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import { usePreferences } from '@vben/preferences';
|
||||||
|
const {globalSearchShortcutKey } = usePreferences();
|
||||||
|
import { useAccessStore } from '@vben/stores';
|
||||||
|
const accessStore = useAccessStore();
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<GlobalSearch
|
||||||
|
:enable-shortcut-key="globalSearchShortcutKey"
|
||||||
|
:menus="accessStore.accessMenus"
|
||||||
|
class="mr-1 sm:mr-4 pl-3 my-3"
|
||||||
|
/>
|
||||||
<Menu
|
<Menu
|
||||||
:accordion="accordion"
|
:accordion="accordion"
|
||||||
:collapse="collapse"
|
:collapse="collapse"
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { Maximize, Minimize } from '@vben/icons';
|
||||||
|
|
||||||
|
import { useFullscreen } from '@vueuse/core';
|
||||||
|
|
||||||
|
|
||||||
|
import {
|
||||||
|
VbenIconButton,
|
||||||
|
} from '@vben-core/shadcn-ui';
|
||||||
|
|
||||||
|
defineOptions({ name: 'FullScreen' });
|
||||||
|
|
||||||
|
const { isFullscreen, toggle } = useFullscreen();
|
||||||
|
|
||||||
|
// 重新检查全屏状态
|
||||||
|
isFullscreen.value = !!(
|
||||||
|
document.fullscreenElement ||
|
||||||
|
// @ts-ignore
|
||||||
|
document.webkitFullscreenElement ||
|
||||||
|
// @ts-ignore
|
||||||
|
document.mozFullScreenElement ||
|
||||||
|
// @ts-ignore
|
||||||
|
document.msFullscreenElement
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<VbenIconButton @click="toggle" class="hover:text-[#007da3] text-white">
|
||||||
|
<Minimize v-if="isFullscreen" class="size-4 hover:text-[#007da3]" />
|
||||||
|
<Maximize v-else class="size-4 hover:text-[#007da3]" />
|
||||||
|
</VbenIconButton>
|
||||||
|
</template>
|
|
@ -0,0 +1 @@
|
||||||
|
export { default as VbenFullScreen } from './full-screen.vue';
|
|
@ -0,0 +1,144 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { MenuRecordRaw } from '@vben/types';
|
||||||
|
|
||||||
|
import { nextTick, onMounted, onUnmounted, ref, watch } from 'vue';
|
||||||
|
|
||||||
|
import {
|
||||||
|
ArrowDown,
|
||||||
|
ArrowUp,
|
||||||
|
CornerDownLeft,
|
||||||
|
MdiKeyboardEsc,
|
||||||
|
Search,
|
||||||
|
} from '@vben/icons';
|
||||||
|
import { $t } from '@vben/locales';
|
||||||
|
import { isWindowsOs } from '@vben/utils';
|
||||||
|
import { useVbenModal } from '@vben-core/popup-ui';
|
||||||
|
|
||||||
|
import { useMagicKeys, whenever } from '@vueuse/core';
|
||||||
|
|
||||||
|
import SearchPanel from './search-panel.vue';
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: 'GlobalSearch',
|
||||||
|
});
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{ enableShortcutKey?: boolean; menus: MenuRecordRaw[] }>(),
|
||||||
|
{
|
||||||
|
enableShortcutKey: true,
|
||||||
|
menus: () => [],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const [Modal, modalApi] = useVbenModal({
|
||||||
|
onCancel() {
|
||||||
|
modalApi.close();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const open = modalApi.useStore((state) => state.isOpen);
|
||||||
|
|
||||||
|
const keyword = ref('');
|
||||||
|
const searchInputRef = ref<HTMLInputElement>();
|
||||||
|
|
||||||
|
function handleClose() {
|
||||||
|
modalApi.close();
|
||||||
|
keyword.value = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const keys = useMagicKeys();
|
||||||
|
const cmd = isWindowsOs() ? keys['ctrl+k'] : keys['cmd+k'];
|
||||||
|
whenever(cmd!, () => {
|
||||||
|
if (props.enableShortcutKey) {
|
||||||
|
modalApi.open();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
whenever(open, () => {
|
||||||
|
nextTick(() => {
|
||||||
|
searchInputRef.value?.focus();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const preventDefaultBrowserSearchHotKey = (event: KeyboardEvent) => {
|
||||||
|
if (event.key?.toLowerCase() === 'k' && (event.metaKey || event.ctrlKey)) {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const toggleKeydownListener = () => {
|
||||||
|
if (props.enableShortcutKey) {
|
||||||
|
window.addEventListener('keydown', preventDefaultBrowserSearchHotKey);
|
||||||
|
} else {
|
||||||
|
window.removeEventListener('keydown', preventDefaultBrowserSearchHotKey);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const toggleOpen = () => {
|
||||||
|
open.value ? modalApi.close() : modalApi.open();
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(() => props.enableShortcutKey, toggleKeydownListener);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
toggleKeydownListener();
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
window.removeEventListener('keydown', preventDefaultBrowserSearchHotKey);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
import { usePreferences } from '@vben/preferences';
|
||||||
|
|
||||||
|
const {sidebarCollapsed } = usePreferences();
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<Modal :fullscreen-button="false" class="w-[600px]" header-class="py-2">
|
||||||
|
<template #title>
|
||||||
|
<div class="flex items-center">
|
||||||
|
<Search class="text-muted-foreground mr-2 size-4" />
|
||||||
|
<input ref="searchInputRef" v-model="keyword" :placeholder="$t('widgets.search.searchNavigate')"
|
||||||
|
class="ring-none placeholder:text-muted-foreground w-[80%] rounded-md border border-none bg-transparent p-2 pl-0 text-sm font-normal outline-none ring-0 ring-offset-transparent focus-visible:ring-transparent" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<SearchPanel :keyword="keyword" :menus="menus" @close="handleClose" />
|
||||||
|
<template #footer>
|
||||||
|
<div class="flex w-full justify-start text-xs">
|
||||||
|
<div class="mr-2 flex items-center">
|
||||||
|
<CornerDownLeft class="mr-1 size-3" />
|
||||||
|
{{ $t('widgets.search.select') }}
|
||||||
|
</div>
|
||||||
|
<div class="mr-2 flex items-center">
|
||||||
|
<ArrowUp class="mr-1 size-3" />
|
||||||
|
<ArrowDown class="mr-1 size-3" />
|
||||||
|
{{ $t('widgets.search.navigate') }}
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center">
|
||||||
|
<MdiKeyboardEsc class="mr-1 size-3" />
|
||||||
|
{{ $t('widgets.search.close') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</Modal>
|
||||||
|
<div v-if="!sidebarCollapsed"
|
||||||
|
class="md:bg-accent group flex h-8 cursor-pointer items-center gap-3 rounded-2xl border-none bg-none px-2 py-0.5 outline-none"
|
||||||
|
@click="toggleOpen()">
|
||||||
|
<Search class="text-muted-foreground group-hover:text-foreground size-4 group-hover:opacity-100" />
|
||||||
|
<span class="text-muted-foreground group-hover:text-foreground hidden text-xs duration-300 md:block">
|
||||||
|
{{ $t('widgets.search.title') }}
|
||||||
|
</span>
|
||||||
|
<span v-if="enableShortcutKey"
|
||||||
|
class="bg-background border-foreground/60 text-muted-foreground group-hover:text-foreground relative hidden rounded-sm rounded-r-xl px-1.5 py-1 text-xs leading-none group-hover:opacity-100 md:block">
|
||||||
|
{{ isWindowsOs() ? 'Ctrl' : '⌘' }}
|
||||||
|
<kbd>K</kbd>
|
||||||
|
</span>
|
||||||
|
<span v-else></span>
|
||||||
|
</div>
|
||||||
|
<div v-else class="rounded-full w100% flex justify-center">
|
||||||
|
<Search class="text-muted-foreground group-hover:text-foreground size-4 group-hover:opacity-100" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
|
@ -0,0 +1 @@
|
||||||
|
export { default as GlobalSearch } from './global-search.vue';
|
|
@ -0,0 +1,287 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { MenuRecordRaw } from '@vben/types';
|
||||||
|
|
||||||
|
import { nextTick, onMounted, ref, shallowRef, watch } from 'vue';
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
|
import { SearchX, X } from '@vben/icons';
|
||||||
|
import { $t } from '@vben/locales';
|
||||||
|
import { mapTree, traverseTreeValues, uniqueByField } from '@vben/utils';
|
||||||
|
import { VbenIcon, VbenScrollbar } from '@vben-core/shadcn-ui';
|
||||||
|
import { isHttpUrl } from '@vben-core/shared/utils';
|
||||||
|
|
||||||
|
import { onKeyStroke, useLocalStorage, useThrottleFn } from '@vueuse/core';
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: 'SearchPanel',
|
||||||
|
});
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{ keyword: string; menus: MenuRecordRaw[] }>(),
|
||||||
|
{
|
||||||
|
keyword: '',
|
||||||
|
menus: () => [],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const emit = defineEmits<{ close: [] }>();
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
const searchHistory = useLocalStorage<MenuRecordRaw[]>(
|
||||||
|
`__search-history-${location.hostname}__`,
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
const activeIndex = ref(-1);
|
||||||
|
const searchItems = shallowRef<MenuRecordRaw[]>([]);
|
||||||
|
const searchResults = ref<MenuRecordRaw[]>([]);
|
||||||
|
|
||||||
|
const handleSearch = useThrottleFn(search, 200);
|
||||||
|
|
||||||
|
// 搜索函数,用于根据搜索关键词查找匹配的菜单项
|
||||||
|
function search(searchKey: string) {
|
||||||
|
// 去除搜索关键词的前后空格
|
||||||
|
searchKey = searchKey.trim();
|
||||||
|
|
||||||
|
// 如果搜索关键词为空,清空搜索结果并返回
|
||||||
|
if (!searchKey) {
|
||||||
|
searchResults.value = [];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用搜索关键词创建正则表达式
|
||||||
|
const reg = createSearchReg(searchKey);
|
||||||
|
|
||||||
|
// 初始化结果数组
|
||||||
|
const results: MenuRecordRaw[] = [];
|
||||||
|
|
||||||
|
// 遍历搜索项
|
||||||
|
traverseTreeValues(searchItems.value, (item) => {
|
||||||
|
// 如果菜单项的名称匹配正则表达式,将其添加到结果数组中
|
||||||
|
if (reg.test(item.name?.toLowerCase())) {
|
||||||
|
results.push(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 更新搜索结果
|
||||||
|
searchResults.value = results;
|
||||||
|
|
||||||
|
// 如果有搜索结果,设置索引为 0
|
||||||
|
if (results.length > 0) {
|
||||||
|
activeIndex.value = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 赋值索引为 0
|
||||||
|
activeIndex.value = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When the keyboard up and down keys move to an invisible place
|
||||||
|
// the scroll bar needs to scroll automatically
|
||||||
|
function scrollIntoView() {
|
||||||
|
const element = document.querySelector(
|
||||||
|
`[data-search-item="${activeIndex.value}"]`,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (element) {
|
||||||
|
element.scrollIntoView({ block: 'nearest' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// enter keyboard event
|
||||||
|
async function handleEnter() {
|
||||||
|
if (searchResults.value.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const result = searchResults.value;
|
||||||
|
const index = activeIndex.value;
|
||||||
|
if (result.length === 0 || index < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const to = result[index];
|
||||||
|
if (to) {
|
||||||
|
searchHistory.value.push(to);
|
||||||
|
handleClose();
|
||||||
|
await nextTick();
|
||||||
|
if (isHttpUrl(to.path)) {
|
||||||
|
window.open(to.path, '_blank');
|
||||||
|
} else {
|
||||||
|
router.push({ path: to.path, replace: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Arrow key up
|
||||||
|
function handleUp() {
|
||||||
|
if (searchResults.value.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
activeIndex.value--;
|
||||||
|
if (activeIndex.value < 0) {
|
||||||
|
activeIndex.value = searchResults.value.length - 1;
|
||||||
|
}
|
||||||
|
scrollIntoView();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Arrow key down
|
||||||
|
function handleDown() {
|
||||||
|
if (searchResults.value.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
activeIndex.value++;
|
||||||
|
if (activeIndex.value > searchResults.value.length - 1) {
|
||||||
|
activeIndex.value = 0;
|
||||||
|
}
|
||||||
|
scrollIntoView();
|
||||||
|
}
|
||||||
|
|
||||||
|
// close search modal
|
||||||
|
function handleClose() {
|
||||||
|
searchResults.value = [];
|
||||||
|
emit('close');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Activate when the mouse moves to a certain line
|
||||||
|
function handleMouseenter(e: MouseEvent) {
|
||||||
|
const index = (e.target as HTMLElement)?.dataset.index;
|
||||||
|
activeIndex.value = Number(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeItem(index: number) {
|
||||||
|
if (props.keyword) {
|
||||||
|
searchResults.value.splice(index, 1);
|
||||||
|
} else {
|
||||||
|
searchHistory.value.splice(index, 1);
|
||||||
|
}
|
||||||
|
activeIndex.value = activeIndex.value - 1 >= 0 ? activeIndex.value - 1 : 0;
|
||||||
|
scrollIntoView();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 存储所有需要转义的特殊字符
|
||||||
|
const code = new Set([
|
||||||
|
'$',
|
||||||
|
'(',
|
||||||
|
')',
|
||||||
|
'*',
|
||||||
|
'+',
|
||||||
|
'.',
|
||||||
|
'?',
|
||||||
|
'[',
|
||||||
|
'\\',
|
||||||
|
']',
|
||||||
|
'^',
|
||||||
|
'{',
|
||||||
|
'|',
|
||||||
|
'}',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 转换函数,用于转义特殊字符
|
||||||
|
function transform(c: string) {
|
||||||
|
// 如果字符在特殊字符列表中,返回转义后的字符
|
||||||
|
// 如果不在,返回字符本身
|
||||||
|
return code.has(c) ? `\\${c}` : c;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建搜索正则表达式
|
||||||
|
function createSearchReg(key: string) {
|
||||||
|
// 将输入的字符串拆分为单个字符
|
||||||
|
// 对每个字符进行转义
|
||||||
|
// 然后用'.*'连接所有字符,创建正则表达式
|
||||||
|
const keys = [...key].map((item) => transform(item)).join('.*');
|
||||||
|
// 返回创建的正则表达式
|
||||||
|
return new RegExp(`.*${keys}.*`);
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.keyword,
|
||||||
|
(val) => {
|
||||||
|
if (val) {
|
||||||
|
handleSearch(val);
|
||||||
|
} else {
|
||||||
|
searchResults.value = [...searchHistory.value];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
searchItems.value = mapTree(props.menus, (item) => {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
name: $t(item?.name),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
if (searchHistory.value.length > 0) {
|
||||||
|
searchResults.value = searchHistory.value;
|
||||||
|
}
|
||||||
|
// enter search
|
||||||
|
onKeyStroke('Enter', handleEnter);
|
||||||
|
// Monitor keyboard arrow keys
|
||||||
|
onKeyStroke('ArrowUp', handleUp);
|
||||||
|
onKeyStroke('ArrowDown', handleDown);
|
||||||
|
// esc close
|
||||||
|
onKeyStroke('Escape', handleClose);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<VbenScrollbar>
|
||||||
|
<div class="!flex h-full justify-center px-2 sm:max-h-[450px]">
|
||||||
|
<!-- 无搜索结果 -->
|
||||||
|
<div
|
||||||
|
v-if="keyword && searchResults.length === 0"
|
||||||
|
class="text-muted-foreground text-center"
|
||||||
|
>
|
||||||
|
<SearchX class="mx-auto mt-4 size-12" />
|
||||||
|
<p class="mb-10 mt-6 text-xs">
|
||||||
|
{{ $t('widgets.search.noResults') }}
|
||||||
|
<span class="text-foreground text-sm font-medium">
|
||||||
|
"{{ keyword }}"
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<!-- 历史搜索记录 & 没有搜索结果 -->
|
||||||
|
<div
|
||||||
|
v-if="!keyword && searchResults.length === 0"
|
||||||
|
class="text-muted-foreground text-center"
|
||||||
|
>
|
||||||
|
<p class="my-10 text-xs">
|
||||||
|
{{ $t('widgets.search.noRecent') }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul v-show="searchResults.length > 0" class="w-full">
|
||||||
|
<li
|
||||||
|
v-if="searchHistory.length > 0 && !keyword"
|
||||||
|
class="text-muted-foreground mb-2 text-xs"
|
||||||
|
>
|
||||||
|
{{ $t('widgets.search.recent') }}
|
||||||
|
</li>
|
||||||
|
<li
|
||||||
|
v-for="(item, index) in uniqueByField(searchResults, 'path')"
|
||||||
|
:key="item.path"
|
||||||
|
:class="
|
||||||
|
activeIndex === index
|
||||||
|
? 'active bg-primary text-primary-foreground'
|
||||||
|
: ''
|
||||||
|
"
|
||||||
|
:data-index="index"
|
||||||
|
:data-search-item="index"
|
||||||
|
class="bg-accent flex-center group mb-3 w-full cursor-pointer rounded-lg px-4 py-4"
|
||||||
|
@click="handleEnter"
|
||||||
|
@mouseenter="handleMouseenter"
|
||||||
|
>
|
||||||
|
<VbenIcon
|
||||||
|
:icon="item.icon"
|
||||||
|
class="mr-2 size-5 flex-shrink-0"
|
||||||
|
fallback
|
||||||
|
/>
|
||||||
|
|
||||||
|
<span class="flex-1">{{ item.name }}</span>
|
||||||
|
<div
|
||||||
|
class="flex-center dark:hover:bg-accent hover:text-primary-foreground rounded-full p-1 hover:scale-110"
|
||||||
|
@click.stop="removeItem(index)"
|
||||||
|
>
|
||||||
|
<X class="size-4" />
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</VbenScrollbar>
|
||||||
|
</template>
|
|
@ -0,0 +1 @@
|
||||||
|
export { default as VbenLogo } from './logo.vue';
|
|
@ -0,0 +1,59 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
// import { VbenAvatar } from '../avatar';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
/**
|
||||||
|
* @zh_CN 是否收起文本
|
||||||
|
*/
|
||||||
|
collapsed?: boolean;
|
||||||
|
/**
|
||||||
|
* @zh_CN Logo 跳转地址
|
||||||
|
*/
|
||||||
|
href?: string;
|
||||||
|
/**
|
||||||
|
* @zh_CN Logo 图片大小
|
||||||
|
*/
|
||||||
|
logoSize?: number;
|
||||||
|
/**
|
||||||
|
* @zh_CN Logo 图标
|
||||||
|
*/
|
||||||
|
src?: string;
|
||||||
|
/**
|
||||||
|
* @zh_CN Logo 文本
|
||||||
|
*/
|
||||||
|
text: string;
|
||||||
|
/**
|
||||||
|
* @zh_CN Logo 主题
|
||||||
|
*/
|
||||||
|
theme?: string;
|
||||||
|
/**
|
||||||
|
* logo字体颜色
|
||||||
|
*/
|
||||||
|
textClass?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: 'VbenLogo',
|
||||||
|
});
|
||||||
|
|
||||||
|
withDefaults(defineProps<Props>(), {
|
||||||
|
collapsed: false,
|
||||||
|
href: 'javascript:void 0',
|
||||||
|
logoSize: 32,
|
||||||
|
src: '',
|
||||||
|
theme: 'light',
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div :class="theme" class="flex h-full items-center text-lg">
|
||||||
|
<a :class="$attrs.class" :href="href"
|
||||||
|
class="flex h-full items-center gap-2 overflow-hidden px-3 text-lg leading-normal transition-all duration-500">
|
||||||
|
<!-- <VbenAvatar v-if="src" :alt="text" :src="src" :size="logoSize" class="relative w-8 rounded-none bg-transparent" /> -->
|
||||||
|
<img v-if="src" :alt="text" :src="src" class="relative rounded-none bg-transparent w-100" >
|
||||||
|
<span v-if="!collapsed" class="text-foreground truncate text-nowrap font-semibold" :class="textClass">
|
||||||
|
{{ text }}
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</template>
|
|
@ -0,0 +1,3 @@
|
||||||
|
export { default as UserInfo } from './info.vue';
|
||||||
|
export { default as UserLike } from './like.vue';
|
||||||
|
export { default as UserSwitch } from './switch.vue';
|
|
@ -0,0 +1,110 @@
|
||||||
|
<template>
|
||||||
|
<Modal title="基本信息" :visible="visible" :cancelText="'关闭'" @cancel="close">
|
||||||
|
<Form :label-col="{ span: 5 }" :wrapper-col="{ span: 12 }">
|
||||||
|
<FormItem label="头像" class="mb-3">
|
||||||
|
<upload v-model:file-list="fileList" name="avatar" list-type="picture-card" class="avatar-uploader"
|
||||||
|
:show-upload-list="false" action="https://www.mocky.io/v2/5cc8019d300000980a055e76"
|
||||||
|
:before-upload="beforeUpload" @change="handleChange">
|
||||||
|
<img v-if="imageUrl" :src="imageUrl" alt="avatar" />
|
||||||
|
<div v-else>
|
||||||
|
<loading-outlined v-if="loading"></loading-outlined>
|
||||||
|
<plus-outlined v-else></plus-outlined>
|
||||||
|
<div class="ant-upload-text">上传头像</div>
|
||||||
|
</div>
|
||||||
|
</upload>
|
||||||
|
</FormItem>
|
||||||
|
<FormItem :label="item.label" v-for="item in userData" :key="item.label" class="mb-3">
|
||||||
|
{{ item.value }}
|
||||||
|
</FormItem>
|
||||||
|
</Form>
|
||||||
|
<a href="#" class="text-[#007da3] ml-24">基本信息请至统一身份管理系统修改</a>
|
||||||
|
</Modal>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { Modal, Form, FormItem ,Upload } from 'ant-design-vue';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { PlusOutlined, LoadingOutlined } from '@ant-design/icons-vue';
|
||||||
|
import { message } from 'ant-design-vue';
|
||||||
|
import type { UploadChangeParam, UploadProps } from 'ant-design-vue';
|
||||||
|
|
||||||
|
function getBase64(img: Blob, callback: (base64Url: string) => void) {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.addEventListener('load', () => callback(reader.result as string));
|
||||||
|
reader.readAsDataURL(img);
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileList = ref([]);
|
||||||
|
const loading = ref<boolean>(false);
|
||||||
|
const imageUrl = ref<string>('');
|
||||||
|
|
||||||
|
const handleChange = (info: UploadChangeParam) => {
|
||||||
|
if (info.file.status === 'uploading') {
|
||||||
|
loading.value = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (info.file.status === 'done') {
|
||||||
|
// Get this url from response in real world.
|
||||||
|
getBase64(info.file.originFileObj, (base64Url: string) => {
|
||||||
|
imageUrl.value = base64Url;
|
||||||
|
loading.value = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (info.file.status === 'error') {
|
||||||
|
loading.value = false;
|
||||||
|
message.error('upload error');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const beforeUpload = (file: UploadProps['fileList'][number]) => {
|
||||||
|
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
|
||||||
|
if (!isJpgOrPng) {
|
||||||
|
message.error('You can only upload JPG file!');
|
||||||
|
}
|
||||||
|
const isLt2M = file.size / 1024 / 1024 < 2;
|
||||||
|
if (!isLt2M) {
|
||||||
|
message.error('Image must smaller than 2MB!');
|
||||||
|
}
|
||||||
|
return isJpgOrPng && isLt2M;
|
||||||
|
};
|
||||||
|
|
||||||
|
const visible = defineModel<boolean>('visible');
|
||||||
|
|
||||||
|
const close = () => {
|
||||||
|
visible.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
let userData = [{
|
||||||
|
label: '姓名',
|
||||||
|
value: '薛雄'
|
||||||
|
}, {
|
||||||
|
label: '登录名',
|
||||||
|
value: 'xuex23'
|
||||||
|
}, {
|
||||||
|
label: '性别',
|
||||||
|
value: '男'
|
||||||
|
}, {
|
||||||
|
label: '员工编号',
|
||||||
|
value: '00454711'
|
||||||
|
}, {
|
||||||
|
label: '机构单位',
|
||||||
|
value: '综合管理部(党委办公室)'
|
||||||
|
}, {
|
||||||
|
label: '邮件地址',
|
||||||
|
value: '123@163.com'
|
||||||
|
}]
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
.avatar-uploader > .ant-upload {
|
||||||
|
width: 128px;
|
||||||
|
height: 128px;
|
||||||
|
}
|
||||||
|
.ant-upload-select-picture-card i {
|
||||||
|
font-size: 32px;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-upload-select-picture-card .ant-upload-text {
|
||||||
|
margin-top: 8px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,37 @@
|
||||||
|
<template>
|
||||||
|
<Modal title="个人偏好" :visible="visible" @cancel="close">
|
||||||
|
<Tabs v-model:activeKey="activeKey" centered>
|
||||||
|
<TabPane key="1" tab="自定义菜单">Content of Tab Pane 1</TabPane>
|
||||||
|
<TabPane key="2" tab="菜单区设置" force-render>Content of Tab Pane 2</TabPane>
|
||||||
|
<TabPane key="3" tab="主题设置">Content of Tab Pane 3</TabPane>
|
||||||
|
<TabPane key="4" tab="消息语音">Content of Tab Pane 4</TabPane>
|
||||||
|
</Tabs>
|
||||||
|
<template #footer>
|
||||||
|
<Button type="link" key="back" @click="close">恢复</Button>
|
||||||
|
<Button key="back" @click="close">取消</Button>
|
||||||
|
<Button key="submit" type="primary" @click="close">确定</Button>
|
||||||
|
</template>
|
||||||
|
</Modal>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { Modal, Tabs, Form, FormItem, Select, Button, TabPane } from 'ant-design-vue';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
let activeKey = ref('1');
|
||||||
|
let options1 = [
|
||||||
|
{
|
||||||
|
value: '1',
|
||||||
|
label: '西北油田(xbyt)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: '2',
|
||||||
|
label: '智能油气田(znyqt)',
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const visible = defineModel<boolean>('visible');
|
||||||
|
|
||||||
|
const close = () => {
|
||||||
|
visible.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
|
@ -0,0 +1,32 @@
|
||||||
|
<template>
|
||||||
|
<Modal title="切换租户" :visible="visible" @cancel="close">
|
||||||
|
<!-- <div class="flex justify-center mb-10">请选择您要切换到的租户</div> -->
|
||||||
|
<Form :label-col="{ span: 5 }" :wrapper-col="{ span: 12 }">
|
||||||
|
<FormItem label="请选择租户">
|
||||||
|
<Select ref="select" v-model:value="value1" :options="options1"></Select>
|
||||||
|
</FormItem>
|
||||||
|
</Form>
|
||||||
|
</Modal>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { Modal, Form, FormItem, Select } from 'ant-design-vue';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
let value1 = ref('1');
|
||||||
|
let options1 = [
|
||||||
|
{
|
||||||
|
value: '1',
|
||||||
|
label: '西北油田(xbyt)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: '2',
|
||||||
|
label: '智能油气田(znyqt)',
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const visible = defineModel<boolean>('visible');
|
||||||
|
|
||||||
|
const close = () => {
|
||||||
|
visible.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
|
@ -30,7 +30,13 @@ export const overridesPreferences = defineOverridesPreferences({
|
||||||
preferencesButtonPosition: 'auto',
|
preferencesButtonPosition: 'auto',
|
||||||
watermark: false,
|
watermark: false,
|
||||||
},
|
},
|
||||||
|
logo: {
|
||||||
|
source: '/logo1.png',
|
||||||
|
},
|
||||||
|
shortcutKeys: {
|
||||||
|
globalSearch: false,
|
||||||
|
},
|
||||||
header: {
|
header: {
|
||||||
height: 60,
|
height: 60,
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,6 +2,54 @@ import type { RouteRecordRaw } from 'vue-router';
|
||||||
|
|
||||||
import { BasicLayout } from '#/layouts';
|
import { BasicLayout } from '#/layouts';
|
||||||
|
|
||||||
|
import { firstRouter, otherRouter } from "./linkdata"
|
||||||
|
|
||||||
|
const getRouter = (list: any, type: string) => {
|
||||||
|
let obj = [];
|
||||||
|
if (type == 'first') {
|
||||||
|
for (let i = 0; i < list.children.length; i++) {
|
||||||
|
obj.push({
|
||||||
|
name: list.children[i]?.rName,
|
||||||
|
path: '',
|
||||||
|
component: () => null,
|
||||||
|
meta: {
|
||||||
|
title: list.children[i]?.name,
|
||||||
|
link: list.children[i]?.url
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (let i = 0; i < list.length; i++) {
|
||||||
|
let chunk:any = {}
|
||||||
|
chunk.component = BasicLayout;
|
||||||
|
chunk.meta = {
|
||||||
|
icon: 'lucide:layout-dashboard',
|
||||||
|
title: list[i].name,
|
||||||
|
order: i,
|
||||||
|
};
|
||||||
|
chunk.name = list[i].rName;
|
||||||
|
chunk.path = '/'+list[i].rName;
|
||||||
|
|
||||||
|
chunk.children = [];
|
||||||
|
for (let j = 0; j < list[i].children.length; j++) {
|
||||||
|
chunk.children.push({
|
||||||
|
name: list[i].children[j]?.rName,
|
||||||
|
path: '',
|
||||||
|
component: () => null,
|
||||||
|
meta: {
|
||||||
|
title: list[i].children[j]?.name,
|
||||||
|
link: list[i].children[j]?.url
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
obj.push(chunk)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const routes: RouteRecordRaw[] = [
|
const routes: RouteRecordRaw[] = [
|
||||||
{
|
{
|
||||||
component: BasicLayout,
|
component: BasicLayout,
|
||||||
|
@ -10,7 +58,7 @@ const routes: RouteRecordRaw[] = [
|
||||||
order: -1,
|
order: -1,
|
||||||
title: '总部系统',
|
title: '总部系统',
|
||||||
},
|
},
|
||||||
name: 'Dashboard',
|
name: 'zbxt',
|
||||||
path: '/home',
|
path: '/home',
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
|
@ -23,34 +71,39 @@ const routes: RouteRecordRaw[] = [
|
||||||
title: '总部系统',
|
title: '总部系统',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: 'zshxgw',
|
...getRouter(firstRouter, 'first')
|
||||||
path: '',
|
// {
|
||||||
component: () => null,
|
// name: 'zshxgw',
|
||||||
meta: {
|
// path: '',
|
||||||
title: '中石化新公文系统',
|
// component: () => null,
|
||||||
link: 'http://www.baidu.com'
|
// meta: {
|
||||||
},
|
// title: '中石化新公文系统',
|
||||||
},
|
// link: 'http://www.baidu.com'
|
||||||
{
|
// },
|
||||||
name: 'zshht',
|
// },
|
||||||
path: '',
|
// {
|
||||||
component: () => null,
|
// name: 'zshht',
|
||||||
meta: {
|
// path: '',
|
||||||
title: '中石化合同系统',
|
// component: () => null,
|
||||||
link: 'http://www.baidu.com'
|
// meta: {
|
||||||
},
|
// title: '中石化合同系统',
|
||||||
},
|
// link: 'http://www.baidu.com'
|
||||||
|
// },
|
||||||
|
// },
|
||||||
// {
|
// {
|
||||||
// name: 'Workspace',
|
// name: 'Workspace',
|
||||||
// path: '/workspace',
|
// path: '/workspace',
|
||||||
// component: () => import('#/views/dashboard/workspace/index.vue'),
|
// component: () => import('#/views/dashboard/wor kspace/index.vue'),
|
||||||
// meta: {
|
// meta: {
|
||||||
// title: $t('page.dashboard.workspace'),
|
// title: $t('page.dashboard.workspace'),
|
||||||
// },
|
// },
|
||||||
// },
|
// },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
...getRouter(otherRouter,'other')
|
||||||
];
|
];
|
||||||
|
|
||||||
|
console.log('999999',...getRouter(otherRouter,'other'));
|
||||||
|
|
||||||
export default routes;
|
export default routes;
|
||||||
|
|
|
@ -1,30 +1,30 @@
|
||||||
import type { RouteRecordRaw } from 'vue-router';
|
// import type { RouteRecordRaw } from 'vue-router';
|
||||||
|
|
||||||
import { BasicLayout } from '#/layouts';
|
// import { BasicLayout } from '#/layouts';
|
||||||
import { $t } from '#/locales';
|
// import { $t } from '#/locales';
|
||||||
|
|
||||||
const routes: RouteRecordRaw[] = [
|
// const routes: RouteRecordRaw[] = [
|
||||||
{
|
// {
|
||||||
component: BasicLayout,
|
// component: BasicLayout,
|
||||||
meta: {
|
// meta: {
|
||||||
icon: 'ic:baseline-view-in-ar',
|
// icon: 'ic:baseline-view-in-ar',
|
||||||
keepAlive: true,
|
// keepAlive: true,
|
||||||
order: 1000,
|
// order: 1000,
|
||||||
title: $t('page.demos.title'),
|
// title: $t('page.demos.title'),
|
||||||
},
|
// },
|
||||||
name: 'Demos',
|
// name: 'Demos',
|
||||||
path: '/demos',
|
// path: '/demos',
|
||||||
children: [
|
// children: [
|
||||||
{
|
// {
|
||||||
meta: {
|
// meta: {
|
||||||
title: $t('page.demos.antd'),
|
// title: $t('page.demos.antd'),
|
||||||
},
|
// },
|
||||||
name: 'AntDesignDemos',
|
// name: 'AntDesignDemos',
|
||||||
path: '/demos/ant-design',
|
// path: '/demos/ant-design',
|
||||||
component: () => import('#/views/demos/antd/index.vue'),
|
// component: () => import('#/views/demos/antd/index.vue'),
|
||||||
},
|
// },
|
||||||
],
|
// ],
|
||||||
},
|
// },
|
||||||
];
|
// ];
|
||||||
|
|
||||||
export default routes;
|
// export default routes;
|
||||||
|
|
|
@ -0,0 +1,232 @@
|
||||||
|
let firstRouter = {
|
||||||
|
"name": "总部系统",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"name": "中石化新公文系统",
|
||||||
|
"url": "https://newoa12.sinopec.com?pageCode=zbxt_new_oa",
|
||||||
|
"rName": "zbxt_new_oa"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "中石化移动应用平台",
|
||||||
|
"url": "https://console.m.sinopec.com/ACWeb/Portal/IndexPage?pageCode=zbxt_ydyypt",
|
||||||
|
"rName": "zbxt_ydyypt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "中石化合同系统",
|
||||||
|
"url": "https://cmis.sinopec.com/zen/portal/#/home?pageCode=zbxt_htxt",
|
||||||
|
"rName": "zbxt_htxt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "中石化党群管理系统",
|
||||||
|
"url": "https://dj.sinopec.com?pageCode=zbxt_dqgl",
|
||||||
|
"rName": "zbxt_dqgl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "中石化法律共享平台",
|
||||||
|
"url": "http://slsp.sinopec.com?pageCode=zbxt_flgl",
|
||||||
|
"rName": "zbxt_flgl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "中石化安全管理系统",
|
||||||
|
"url": "http://safety.sinopec.com:8000/IPWeb/Home?pageCode=zbxt_aqgl",
|
||||||
|
"rName": "zbxt_aqgl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "中石化法治合规管理",
|
||||||
|
"url": "https://lcrs.sinopec.com/?pageCode=zbxt_nkglxt",
|
||||||
|
"rName": "zbxt_nkglxt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "中石化制度管理系统",
|
||||||
|
"url": "http://10.249.201.77?pageCode=zbxt_zdgl",
|
||||||
|
"rName": "zbxt_zdgl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "中石化信息化标准系统",
|
||||||
|
"url": "http://infostd.sinopec.com/?pageCode=zbxt_xxhbz",
|
||||||
|
"rName": "zbxt_xxhbz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "中石化网络学院",
|
||||||
|
"url": "https://sia.sinopec.com/learn/index.html?pageCode=zbxt_wlxy",
|
||||||
|
"rName": "zbxt_wlxy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "中石化科技管理平台",
|
||||||
|
"url": "http://istm.sinopec.com/?pageCode=zbxt_kjglpt",
|
||||||
|
"rName": "zbxt_kjglpt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "中石化信创邮件系统",
|
||||||
|
"url": "https://webmail.sinopec.com/?pageCode=zbxt_xcyj",
|
||||||
|
"rName": "zbxt_xcyj"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
let otherRouter =
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "经营管理",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"name": "市场管理信息系统",
|
||||||
|
"url": "https://xbscgl.xbyt.sinopec.com?pageCode=jygl_scglxx",
|
||||||
|
"rName": "jygl_scglxx"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "工程造价管理",
|
||||||
|
"url": "http://10.16.0.157:8082/xbscjyweb?pageCode=jygl_gczjgl",
|
||||||
|
"rName": "jygl_gczjgl"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"rName": "jygl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "勘探开发",
|
||||||
|
"icon": "lucide:area-chart",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"name": "油气开发平台",
|
||||||
|
"url": "http://yqkfyw.xbyt.sinopec.com/webptframe/home_navtree_hn.html?pageCode=yqkfyw_kfpt",
|
||||||
|
"rName": "yqkfyw_kfpt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "地面工程GIS",
|
||||||
|
"url": "https://ssco.xbsj.sinopec.com/DMGCFZ//HomeXBYTGISFront/Index?pageCode=yqkfyw_gis",
|
||||||
|
"rName": "yqkfyw_gis"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "设备管理系统",
|
||||||
|
"url": "https://sbgl.xbyt.sinopec.com:9006/XBEM?pageCode=yqkfyw_sbxt",
|
||||||
|
"rName": "yqkfyw_sbxt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "石油工程决策系统",
|
||||||
|
"url": "https://gcjc.xbyt.sinopec.com?pageCode=yqkfyw_sygc",
|
||||||
|
"rName": "yqkfyw_sygc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "完井快报",
|
||||||
|
"url": "http://xbyt.sinopec.com/wczx/Lists/sc/SinopecAllItems.aspx?pageCode=yqkfyw_",
|
||||||
|
"rName": "yqkfyw_"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "钻井数据库系统",
|
||||||
|
"url": "http://10.16.0.74/tyrz_zjsjk/?pageCode=yqkfyw_zjsjk",
|
||||||
|
"rName": "yqkfyw_zjsjk"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "完井测试日报",
|
||||||
|
"url": "http://xbyt.sinopec.com/wczx/Lists/kt/SinopecAllItems.aspx?pageCode=yqkfyw_wjcs",
|
||||||
|
"rName": "yqkfyw_wjcs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "IPPE",
|
||||||
|
"url": "http://ippe.sinopec.com/?pageCode=yqkfyw_ippe",
|
||||||
|
"rName": "yqkfyw_ippe"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"rName": "yqkfyw"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "安全生产",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"name": "生产重点",
|
||||||
|
"url": "http://10.16.128.237:9528/yxrb/zdbb/scxxyxrb?pageCode=scyx_zdjxx",
|
||||||
|
"rName": "scyx_zdjxx"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "集输防腐数据平台",
|
||||||
|
"url": "https://dmgcysbgl.xbyt.sinopec.com:8080/xbyqjs//xbjqmh_1.0.0/mh/loginSuccess.action?pageCode=scyx_jsffsj",
|
||||||
|
"rName": "scyx_jsffsj"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "土地信息管理系统",
|
||||||
|
"url": "http://10.16.0.73:8888/xbtd?pageCode=scyx_tdxxgl",
|
||||||
|
"rName": "scyx_tdxxgl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "HSSE管理系统",
|
||||||
|
"url": "http://10.16.128.247:8088/?pageCode=scyx_hseglxx",
|
||||||
|
"rName": "scyx_hseglxx"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "生产运行(应急)指挥中心协同平台",
|
||||||
|
"url": "http://10.16.66.120:8088/home?pageCode=scyx_yjzhxt",
|
||||||
|
"rName": "scyx_yjzhxt"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"rName": "scyx"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "综合行政",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"name": "领导请销假",
|
||||||
|
"url": "https://10.16.0.128/xjOA/main/login/leave.jsp?pageCode=gcgl_ldqxj",
|
||||||
|
"rName": "gcgl_ldqxj"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "督办管理",
|
||||||
|
"url": "https://10.16.0.128/xjOA/main/login/urge.jsp?pageCode=gcgl_db",
|
||||||
|
"rName": "gcgl_db"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "员工诉求",
|
||||||
|
"url": "https://10.16.0.128/xjOA/main/login/appeal.jsp?pageCode=gcgl_ygsq",
|
||||||
|
"rName": "gcgl_ygsq"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "会议管理系统",
|
||||||
|
"url": "http://10.16.0.128:8089/HYXT/?pageCode=gcgl_hyxt",
|
||||||
|
"rName": "gcgl_hyxt"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"rName": "gcgl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "数据管理",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"name": "GIS数据服务",
|
||||||
|
"url": "http://10.16.0.210:8017?pageCode=sjgl_gissjfw",
|
||||||
|
"rName": "sjgl_gissjfw"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "EPBP",
|
||||||
|
"url": "http://10.16.128.130/blankSSO.action?pageCode=sjgl_EPBP_ktkfsjcj",
|
||||||
|
"rName": "sjgl_EPBP_ktkfsjcj"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "单井数据服务",
|
||||||
|
"url": "https://ssco.xbsj.sinopec.com/djsjfw/goto.html?pageCode=sjgl_djsjfw",
|
||||||
|
"rName": "sjgl_djsjfw"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "数据管理平台",
|
||||||
|
"url": "http://10.16.3.30:10008/?pageCode=sjgl_sjgl",
|
||||||
|
"rName": "sjgl_sjgl"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "文档资料共享环境",
|
||||||
|
"url": "https://10.16.67.140/xbsjzlgx/sso?pageCode=sjgl_wdzlgx",
|
||||||
|
"rName": "sjgl_wdzlgx"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "视频共享平台",
|
||||||
|
"url": "http://10.16.128.81:8020/?pageCode=sjgl_spgxpt",
|
||||||
|
"rName": "sjgl_spgxpt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "smartbi报表工具",
|
||||||
|
"url": "http://10.16.67.135:18080/smartbi/vision/index.jsp?pageCode=sjgl_smartbi",
|
||||||
|
"rName": "sjgl_smartbi"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"rName": "sjgl"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
export { firstRouter, otherRouter };
|
|
@ -1,81 +1,81 @@
|
||||||
import type { RouteRecordRaw } from 'vue-router';
|
// import type { RouteRecordRaw } from 'vue-router';
|
||||||
|
|
||||||
import {
|
// import {
|
||||||
VBEN_DOC_URL,
|
// VBEN_DOC_URL,
|
||||||
VBEN_ELE_PREVIEW_URL,
|
// VBEN_ELE_PREVIEW_URL,
|
||||||
VBEN_GITHUB_URL,
|
// VBEN_GITHUB_URL,
|
||||||
VBEN_LOGO_URL,
|
// VBEN_LOGO_URL,
|
||||||
VBEN_NAIVE_PREVIEW_URL,
|
// VBEN_NAIVE_PREVIEW_URL,
|
||||||
} from '@vben/constants';
|
// } from '@vben/constants';
|
||||||
|
|
||||||
import { BasicLayout, IFrameView } from '#/layouts';
|
// import { BasicLayout, IFrameView } from '#/layouts';
|
||||||
import { $t } from '#/locales';
|
// import { $t } from '#/locales';
|
||||||
|
|
||||||
const routes: RouteRecordRaw[] = [
|
// const routes: RouteRecordRaw[] = [
|
||||||
{
|
// {
|
||||||
component: BasicLayout,
|
// component: BasicLayout,
|
||||||
meta: {
|
// meta: {
|
||||||
badgeType: 'dot',
|
// badgeType: 'dot',
|
||||||
icon: VBEN_LOGO_URL,
|
// icon: VBEN_LOGO_URL,
|
||||||
order: 9999,
|
// order: 9999,
|
||||||
title: $t('page.vben.title'),
|
// title: $t('page.vben.title'),
|
||||||
},
|
// },
|
||||||
name: 'VbenProject',
|
// name: 'VbenProject',
|
||||||
path: '/vben-admin',
|
// path: '/vben-admin',
|
||||||
children: [
|
// children: [
|
||||||
{
|
// {
|
||||||
name: 'VbenAbout',
|
// name: 'VbenAbout',
|
||||||
path: '/vben-admin/about',
|
// path: '/vben-admin/about',
|
||||||
component: () => import('#/views/_core/about/index.vue'),
|
// component: () => import('#/views/_core/about/index.vue'),
|
||||||
meta: {
|
// meta: {
|
||||||
icon: 'lucide:copyright',
|
// icon: 'lucide:copyright',
|
||||||
title: $t('page.vben.about'),
|
// title: $t('page.vben.about'),
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
name: 'VbenDocument',
|
// name: 'VbenDocument',
|
||||||
path: '/vben-admin/document',
|
// path: '/vben-admin/document',
|
||||||
component: IFrameView,
|
// component: IFrameView,
|
||||||
meta: {
|
// meta: {
|
||||||
icon: 'lucide:book-open-text',
|
// icon: 'lucide:book-open-text',
|
||||||
link: VBEN_DOC_URL,
|
// link: VBEN_DOC_URL,
|
||||||
title: $t('page.vben.document'),
|
// title: $t('page.vben.document'),
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
name: 'VbenGithub',
|
// name: 'VbenGithub',
|
||||||
path: '/vben-admin/github',
|
// path: '/vben-admin/github',
|
||||||
component: IFrameView,
|
// component: IFrameView,
|
||||||
meta: {
|
// meta: {
|
||||||
icon: 'mdi:github',
|
// icon: 'mdi:github',
|
||||||
link: VBEN_GITHUB_URL,
|
// link: VBEN_GITHUB_URL,
|
||||||
title: 'Github',
|
// title: 'Github',
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
name: 'VbenNaive',
|
// name: 'VbenNaive',
|
||||||
path: '/vben-admin/naive',
|
// path: '/vben-admin/naive',
|
||||||
component: IFrameView,
|
// component: IFrameView,
|
||||||
meta: {
|
// meta: {
|
||||||
badgeType: 'dot',
|
// badgeType: 'dot',
|
||||||
icon: 'logos:naiveui',
|
// icon: 'logos:naiveui',
|
||||||
link: VBEN_NAIVE_PREVIEW_URL,
|
// link: VBEN_NAIVE_PREVIEW_URL,
|
||||||
title: $t('page.vben.naive-ui'),
|
// title: $t('page.vben.naive-ui'),
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
name: 'VbenElementPlus',
|
// name: 'VbenElementPlus',
|
||||||
path: '/vben-admin/ele',
|
// path: '/vben-admin/ele',
|
||||||
component: IFrameView,
|
// component: IFrameView,
|
||||||
meta: {
|
// meta: {
|
||||||
badgeType: 'dot',
|
// badgeType: 'dot',
|
||||||
icon: 'logos:element',
|
// icon: 'logos:element',
|
||||||
link: VBEN_ELE_PREVIEW_URL,
|
// link: VBEN_ELE_PREVIEW_URL,
|
||||||
title: $t('page.vben.element-plus'),
|
// title: $t('page.vben.element-plus'),
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
],
|
// ],
|
||||||
},
|
// },
|
||||||
];
|
// ];
|
||||||
|
|
||||||
export default routes;
|
// export default routes;
|
||||||
|
|
|
@ -107,7 +107,7 @@ onBeforeUnmount(() => {
|
||||||
</template>
|
</template>
|
||||||
<slot name="title"></slot>
|
<slot name="title"></slot>
|
||||||
</VbenTooltip>
|
</VbenTooltip>
|
||||||
<div v-show="!showTooltip" :class="[e('content')]">
|
<div v-show="!showTooltip" :class="[e('content')]" class="text-wrap">
|
||||||
<VbenMenuBadge
|
<VbenMenuBadge
|
||||||
v-if="rootMenu.props.mode !== 'horizontal'"
|
v-if="rootMenu.props.mode !== 'horizontal'"
|
||||||
class="right-2"
|
class="right-2"
|
||||||
|
|
Loading…
Reference in New Issue