|
|
@ -1,104 +1,130 @@ |
|
|
|
<template> |
|
|
|
<header class="header fixed w-full bg-[#3f3e3c] opacity-90 border-b border-gray-200 dark:border-gray-800 -mb-px top-0 z-50 lg:mb-0 lg:border-0"> |
|
|
|
<div class="xl:w-screen-xl xl:p-0 px-4 flex items-center between w-full m-auto bg-[#3f3e3c]"> |
|
|
|
<div class="header___left flex items-center"> |
|
|
|
<div class="logo mt-1 sm:w-[250px] h-7 w-auto py-2 flex items-center"> |
|
|
|
<nuxt-link v-if="config?.siteLogo" to="/"> |
|
|
|
<div class="flex flex-col text-center xl:p-0"> |
|
|
|
<el-image |
|
|
|
:src="config.siteLogo" |
|
|
|
shape="square" |
|
|
|
fit="fill" |
|
|
|
class="w-[190px]" |
|
|
|
:alt="config.siteName" |
|
|
|
:title="config.siteName" |
|
|
|
/> |
|
|
|
</div> |
|
|
|
<header |
|
|
|
class="header fixed w-full bg-[#3f3e3c] opacity-90 border-b border-gray-200 dark:border-gray-800 -mb-px top-0 z-50 lg:mb-0 lg:border-0"> |
|
|
|
<div class="xl:w-screen-xl xl:p-0 px-4 flex items-center between w-full m-auto bg-[#3f3e3c]"> |
|
|
|
<div class="header___left flex items-center"> |
|
|
|
<div class="logo mt-1 sm:w-[250px] h-7 w-auto py-2 flex items-center"> |
|
|
|
<nuxt-link v-if="config?.siteLogo" to="/"> |
|
|
|
<div class="flex flex-col text-center xl:p-0"> |
|
|
|
<el-image |
|
|
|
:src="config.siteLogo" |
|
|
|
shape="square" |
|
|
|
fit="fill" |
|
|
|
class="w-[190px]" |
|
|
|
:alt="config.siteName" |
|
|
|
:title="config.siteName" |
|
|
|
/> |
|
|
|
</div> |
|
|
|
|
|
|
|
</nuxt-link> |
|
|
|
<nuxt-link v-else to="/"> |
|
|
|
<text>{{ config?.siteName }}</text> |
|
|
|
</nuxt-link> |
|
|
|
</div> |
|
|
|
<div class="hidden sm:flex"> |
|
|
|
<el-menu |
|
|
|
:default-active="currentIndex" |
|
|
|
mode="horizontal" |
|
|
|
background-color="transparent" |
|
|
|
:collapse="true" |
|
|
|
:ellipsis="false" |
|
|
|
style="border: none" |
|
|
|
> |
|
|
|
<template v-for="(item, index) in navigations"> |
|
|
|
<el-sub-menu v-if="item?.children && item.children.length > 0" :index="`${item.path}`"> |
|
|
|
<template #title><h3 class="text-white">{{ item.title }}</h3></template> |
|
|
|
<el-menu-item v-for="(sub,subIndex) in item.children" :index="`${sub.path}`"> |
|
|
|
<el-space @click="openSpmUrl(`${item.path}`,sub,sub.navigationId)"> |
|
|
|
<el-avatar v-if="sub.icon" :src="sub.icon" shape="square" size="small"></el-avatar> |
|
|
|
<span class="font-bold">{{ sub.title }}</span> |
|
|
|
</el-space> |
|
|
|
</el-menu-item> |
|
|
|
</el-sub-menu> |
|
|
|
<el-menu-item v-else :index="`${item.path}`"><h3 @click="openSpmUrl(`${item.path}`,item,item.navigationId)" class="text-white">{{ item.title }}</h3></el-menu-item> |
|
|
|
</template> |
|
|
|
</el-menu> |
|
|
|
</div> |
|
|
|
</nuxt-link> |
|
|
|
<nuxt-link v-else to="/"> |
|
|
|
<text>{{ config?.siteName }}</text> |
|
|
|
</nuxt-link> |
|
|
|
</div> |
|
|
|
<div class="header__right items-center pr-4 xl:pr-0 md:flex hidden"> |
|
|
|
<el-space class="sm:flex hidden" size="large" v-if="config.showSearchTools"> |
|
|
|
<el-button v-if="token" @click="loginAdminByToken">控制台</el-button> |
|
|
|
<ClientOnly> |
|
|
|
<template v-if="token"> |
|
|
|
<el-dropdown @command="handleCommand"> |
|
|
|
<el-space class="flex items-center cursor-pointer"> |
|
|
|
<el-avatar class="cursor-pointer" :src="user?.logo" :size="30" /> |
|
|
|
<span>{{ user?.tenantName }}</span> |
|
|
|
</el-space> |
|
|
|
<template #dropdown> |
|
|
|
<el-dropdown-menu> |
|
|
|
<el-dropdown-item command="user" @click="openSpmUrl(`/user`)">账户中心</el-dropdown-item> |
|
|
|
<el-dropdown-item command="password" @click="openSpmUrl(`/user/password`)">修改密码</el-dropdown-item> |
|
|
|
<el-dropdown-item command="auth" @click="openSpmUrl(`/user/auth`)">实名认证</el-dropdown-item> |
|
|
|
<el-dropdown-item command="order" @click="openSpmUrl(`/user/order`)">我的订单</el-dropdown-item> |
|
|
|
<el-dropdown-item divided command="logOut" @click="openSpmUrl('/user/logout')">退出登录 |
|
|
|
</el-dropdown-item> |
|
|
|
</el-dropdown-menu> |
|
|
|
</template> |
|
|
|
</el-dropdown> |
|
|
|
</template> |
|
|
|
<template v-else> |
|
|
|
<el-button type="primary" v-if="!token" @click="navigateTo(`/passport/login`)">登录/注册</el-button> |
|
|
|
<!-- <el-button v-if="config.showLoginButton" circle :icon="ElIconUserFilled" @click="goLogin"></el-button>--> |
|
|
|
</template> |
|
|
|
</ClientOnly> |
|
|
|
</el-space> |
|
|
|
<div class="hidden sm:flex"> |
|
|
|
<el-menu |
|
|
|
:default-active="currentIndex" |
|
|
|
mode="horizontal" |
|
|
|
background-color="transparent" |
|
|
|
:collapse="true" |
|
|
|
:ellipsis="false" |
|
|
|
style="border: none" |
|
|
|
> |
|
|
|
<template v-for="(item, index) in navigations"> |
|
|
|
<!-- <el-sub-menu v-if="item?.children && item.children.length > 0" :index="`${item.path}`">--> |
|
|
|
<!-- <template #title><h3 class="text-white">{{ item.title }}</h3></template>--> |
|
|
|
<!-- <el-menu-item v-for="(sub,subIndex) in item.children" :index="`${sub.path}`">--> |
|
|
|
<!-- <el-space @click="openSpmUrl(`${item.path}`,sub,sub.navigationId)">--> |
|
|
|
<!-- <el-avatar v-if="sub.icon" :src="sub.icon" shape="square" size="small"></el-avatar>--> |
|
|
|
<!-- <span class="font-bold">{{ sub.title }}</span>--> |
|
|
|
<!-- </el-space>--> |
|
|
|
<!-- </el-menu-item>--> |
|
|
|
<!-- </el-sub-menu>--> |
|
|
|
<div v-if="item?.children && item.children.length > 0"> |
|
|
|
<div class="px-[20px] relative h-[60px] w-[80px] flex justify-center items-center"> |
|
|
|
<h3 class="text-white cursor-pointer" @mouseenter="mouseenter(index)" @mouseleave="mouseleave(index)"> |
|
|
|
{{ |
|
|
|
item.title |
|
|
|
}}</h3> |
|
|
|
<div v-if="item.showChild" |
|
|
|
class="absolute top-[60px] bg-white p-2 shadow border-t-2 border-[#409eff] left-0 overflow-hidden" |
|
|
|
:style="{height: `${item.childHeight}px`}"> |
|
|
|
<div v-for="(sub,subIndex) in item.children" :key="index" class="w-[200px] p-1 cursor-pointer hover:text-[#409eff]"> |
|
|
|
<el-space |
|
|
|
@click="openSpmUrl(`${item.path}`,sub,sub.navigationId)"> |
|
|
|
<el-avatar v-if="sub.icon" :src="sub.icon" shape="square" |
|
|
|
size="small"></el-avatar> |
|
|
|
<span class="font-bold">{{ sub.title }}</span> |
|
|
|
</el-space> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<el-menu-item v-else :index="`${item.path}`"><h3 |
|
|
|
@mouseenter="mouseenter(index)" |
|
|
|
@mouseleave="mouseleave(index)" |
|
|
|
@click="openSpmUrl(`${item.path}`,item,item.navigationId)" class="text-white">{{ item.title }}</h3> |
|
|
|
</el-menu-item> |
|
|
|
</template> |
|
|
|
</el-menu> |
|
|
|
</div> |
|
|
|
<!-- 移动端菜单 --> |
|
|
|
<div class="sm:hidden flex xl:p-0 px-8"> |
|
|
|
<el-dropdown> |
|
|
|
<el-space class="el-dropdown-link flex items-center"> |
|
|
|
<el-avatar v-if="token" class="cursor-pointer" :src="user?.avatar" :size="30"/> |
|
|
|
<el-button v-else :icon="ElIconMenu"></el-button> |
|
|
|
</el-space> |
|
|
|
<template #dropdown> |
|
|
|
<el-dropdown-menu> |
|
|
|
<template v-for="(item, index) in navigations"> |
|
|
|
<el-dropdown-item> |
|
|
|
<span @click="openSpmUrl(`${item.path}`,item,item.navigationId)">{{ item.title }}</span> |
|
|
|
</el-dropdown-item> |
|
|
|
</template> |
|
|
|
<template v-if="token"> |
|
|
|
<el-dropdown-item divided @click="loginDeveloperCenterByToken">会员中心</el-dropdown-item> |
|
|
|
<el-dropdown-item divided command="logOut" @click="navigateTo('/user/logout')">退出</el-dropdown-item> |
|
|
|
</div> |
|
|
|
<div class="header__right items-center pr-4 xl:pr-0 md:flex hidden"> |
|
|
|
<el-space class="sm:flex hidden" size="large" v-if="config.showSearchTools"> |
|
|
|
<el-button v-if="token" @click="loginAdminByToken">控制台</el-button> |
|
|
|
<ClientOnly> |
|
|
|
<template v-if="token"> |
|
|
|
<el-dropdown @command="handleCommand"> |
|
|
|
<el-space class="flex items-center cursor-pointer"> |
|
|
|
<el-avatar class="cursor-pointer" :src="user?.logo" :size="30"/> |
|
|
|
<span>{{ user?.tenantName }}</span> |
|
|
|
</el-space> |
|
|
|
<template #dropdown> |
|
|
|
<el-dropdown-menu> |
|
|
|
<el-dropdown-item command="user" @click="openSpmUrl(`/user`)">账户中心</el-dropdown-item> |
|
|
|
<el-dropdown-item command="password" @click="openSpmUrl(`/user/password`)">修改密码 |
|
|
|
</el-dropdown-item> |
|
|
|
<el-dropdown-item command="auth" @click="openSpmUrl(`/user/auth`)">实名认证</el-dropdown-item> |
|
|
|
<el-dropdown-item command="order" @click="openSpmUrl(`/user/order`)">我的订单</el-dropdown-item> |
|
|
|
<el-dropdown-item divided command="logOut" @click="openSpmUrl('/user/logout')">退出登录 |
|
|
|
</el-dropdown-item> |
|
|
|
</el-dropdown-menu> |
|
|
|
</template> |
|
|
|
<el-dropdown-item v-if="!token" divided @click="navigateTo(`/passport/login`)">登录</el-dropdown-item> |
|
|
|
</el-dropdown-menu> |
|
|
|
</el-dropdown> |
|
|
|
</template> |
|
|
|
</el-dropdown> |
|
|
|
</div> |
|
|
|
<template v-else> |
|
|
|
<el-button type="primary" v-if="!token" @click="navigateTo(`/passport/login`)">登录/注册</el-button> |
|
|
|
<!-- <el-button v-if="config.showLoginButton" circle :icon="ElIconUserFilled" @click="goLogin"></el-button>--> |
|
|
|
</template> |
|
|
|
</ClientOnly> |
|
|
|
</el-space> |
|
|
|
</div> |
|
|
|
<!-- 移动端菜单 --> |
|
|
|
<div class="sm:hidden flex xl:p-0 px-8"> |
|
|
|
<el-dropdown> |
|
|
|
<el-space class="el-dropdown-link flex items-center"> |
|
|
|
<el-avatar v-if="token" class="cursor-pointer" :src="user?.avatar" :size="30"/> |
|
|
|
<el-button v-else :icon="ElIconMenu"></el-button> |
|
|
|
</el-space> |
|
|
|
<template #dropdown> |
|
|
|
<el-dropdown-menu> |
|
|
|
<template v-for="(item, index) in navigations"> |
|
|
|
<el-dropdown-item> |
|
|
|
<span @click="openSpmUrl(`${item.path}`,item,item.navigationId)">{{ item.title }}</span> |
|
|
|
</el-dropdown-item> |
|
|
|
</template> |
|
|
|
<template v-if="token"> |
|
|
|
<el-dropdown-item divided @click="loginDeveloperCenterByToken">会员中心</el-dropdown-item> |
|
|
|
<el-dropdown-item divided command="logOut" @click="navigateTo('/user/logout')">退出</el-dropdown-item> |
|
|
|
</template> |
|
|
|
<el-dropdown-item v-if="!token" divided @click="navigateTo(`/passport/login`)">登录</el-dropdown-item> |
|
|
|
</el-dropdown-menu> |
|
|
|
</template> |
|
|
|
</el-dropdown> |
|
|
|
</div> |
|
|
|
<Passport :visible="showPassport" @done="reload"/> |
|
|
|
</header> |
|
|
|
</div> |
|
|
|
<Passport :visible="showPassport" @done="reload"/> |
|
|
|
</header> |
|
|
|
</template> |
|
|
|
|
|
|
|
<script setup lang="ts"> |
|
|
@ -131,6 +157,70 @@ const config = useConfigInfo(); |
|
|
|
const affix = useProductAffix(); |
|
|
|
const sysDomain = useSysDomain(); |
|
|
|
|
|
|
|
const setNav = () => { |
|
|
|
navigations.value = navigations.value.map(item => { |
|
|
|
item.showChild = false |
|
|
|
item.childHeight = 0; |
|
|
|
return item |
|
|
|
}) |
|
|
|
} |
|
|
|
setNav() |
|
|
|
|
|
|
|
const time = 10 |
|
|
|
let interval: NodeJS.Timeout |
|
|
|
const mouseenter = async (index: number) => { |
|
|
|
let showIndex = -1; |
|
|
|
for (let i = 0; i < navigations.value.length; i++) { |
|
|
|
console.log(navigations.value[i].showChild) |
|
|
|
if (navigations.value[i].showChild) { |
|
|
|
showIndex = i |
|
|
|
break |
|
|
|
} |
|
|
|
} |
|
|
|
if (showIndex === index) return |
|
|
|
const item = navigations.value[index]; |
|
|
|
const childHeight = item.children ? parseInt((item.children?.length * 31).toString()) : 0; |
|
|
|
await hideAll() |
|
|
|
item.showChild = true |
|
|
|
if (item.childHeight === undefined) item.childHeight = 0 |
|
|
|
interval = setInterval(() => { |
|
|
|
if (item.childHeight !== undefined && item.childHeight >= childHeight && interval) clearInterval(interval) |
|
|
|
if (item.childHeight !== undefined && item.children !== undefined && (item.childHeight < childHeight)) { |
|
|
|
item.childHeight += parseInt(((childHeight / item.children?.length) / 5).toString()) |
|
|
|
} else { |
|
|
|
// item.childHeight = childHeight |
|
|
|
if (interval) clearInterval(interval) |
|
|
|
} |
|
|
|
console.log(item.childHeight, childHeight) |
|
|
|
// console.log(item.childHeight) |
|
|
|
}, time) |
|
|
|
} |
|
|
|
|
|
|
|
const mouseleave = () => { |
|
|
|
if (interval) clearInterval(interval) |
|
|
|
} |
|
|
|
|
|
|
|
const hideAll = () => { |
|
|
|
return new Promise(resolve => { |
|
|
|
navigations.value = navigations.value.map(item => { |
|
|
|
if (item.childHeight === undefined) item.childHeight = 0 |
|
|
|
if (item.showChild) { |
|
|
|
const childHeight = item.children ? parseInt((item.children?.length * 31).toString()) : 0; |
|
|
|
const interval = setInterval(() => { |
|
|
|
if (item.childHeight !== undefined && item.children !== undefined && (item.childHeight > 0)) { |
|
|
|
item.childHeight -= parseInt(((childHeight / item.children?.length) / 5).toString()) |
|
|
|
} else { |
|
|
|
item.showChild = false |
|
|
|
clearInterval(interval) |
|
|
|
} |
|
|
|
}, time) |
|
|
|
} |
|
|
|
return item |
|
|
|
}) |
|
|
|
resolve(true) |
|
|
|
}) |
|
|
|
} |
|
|
|
|
|
|
|
// 顶部栏初始数 |
|
|
|
const visibleNumber = ref<number>(6); |
|
|
|
config.value.elMenuMaxNumber = 8; |
|
|
@ -171,7 +261,7 @@ const reload = async () => { |
|
|
|
const token = localStorage.getItem('token'); |
|
|
|
// const domain = localStorage.getItem('SysDomain'); |
|
|
|
// if (domain) { |
|
|
|
// sysDomain.value = domain; |
|
|
|
// sysDomain.value = domain; |
|
|
|
// } |
|
|
|
// 获取用户信息 |
|
|
|
if (token && token != '') { |
|
|
@ -181,7 +271,7 @@ const reload = async () => { |
|
|
|
} |
|
|
|
// 获取企业信息 |
|
|
|
const {data: companyInfo} = await useServerRequest<ApiResult<Company>>('/system/company/profile', {baseURL: runtimeConfig.public.apiServer}) |
|
|
|
if(companyInfo.value?.data){ |
|
|
|
if (companyInfo.value?.data) { |
|
|
|
company.value = companyInfo.value?.data; |
|
|
|
// sysDomain.value = company.value?.domain || undefined; |
|
|
|
// user.value.tenantName = company.value?.tenantName; |
|
|
|