webman迁移
This commit is contained in:
160
dafuweng-webman/web/src/layouts/frontend/components/aside.vue
Normal file
160
dafuweng-webman/web/src/layouts/frontend/components/aside.vue
Normal file
@@ -0,0 +1,160 @@
|
||||
<template>
|
||||
<el-aside class="ba-user-layouts">
|
||||
<div class="userinfo">
|
||||
<div @click="routerPush('account/profile')" class="user-avatar-box">
|
||||
<img class="user-avatar" :src="fullUrl(userInfo.avatar ? userInfo.avatar : '/static/images/avatar.png')" alt="" />
|
||||
<Icon class="user-avatar-gender" :name="userInfo.getGenderIcon()['name']" size="14" :color="userInfo.getGenderIcon()['color']" />
|
||||
</div>
|
||||
<p class="username">{{ userInfo.nickname }}</p>
|
||||
<el-button-group>
|
||||
<el-button
|
||||
@click="routerPush('account/integral')"
|
||||
v-blur
|
||||
class="userinfo-button-item"
|
||||
:title="$t('Integral') + ' ' + userInfo.score"
|
||||
size="default"
|
||||
plain
|
||||
>
|
||||
<span>{{ $t('Integral') + ' ' + userInfo.score }}</span>
|
||||
</el-button>
|
||||
<el-button
|
||||
@click="routerPush('account/balance')"
|
||||
v-blur
|
||||
class="userinfo-button-item"
|
||||
:title="$t('Balance') + ' ' + userInfo.money"
|
||||
size="default"
|
||||
plain
|
||||
>
|
||||
<span>{{ $t('Balance') + ' ' + userInfo.money }}</span>
|
||||
</el-button>
|
||||
</el-button-group>
|
||||
</div>
|
||||
|
||||
<div class="user-menus">
|
||||
<template v-for="(item, idx) in memberCenter.state.viewRoutes" :key="idx">
|
||||
<div v-if="memberCenter.state.showHeadline" class="user-menu-max-title">{{ item.meta?.title }}</div>
|
||||
<div
|
||||
v-for="(menu, index) in item.children"
|
||||
:key="index"
|
||||
@click="routerPush(menu)"
|
||||
class="user-menu-item"
|
||||
:class="route.fullPath == menu.path ? 'active' : ''"
|
||||
>
|
||||
<Icon :name="menu.meta?.icon" size="16" color="var(--el-text-color-secondary)" />
|
||||
<span>{{ menu.meta?.title }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</el-aside>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useRoute, useRouter, type RouteRecordRaw } from 'vue-router'
|
||||
import { useMemberCenter } from '/@/stores/memberCenter'
|
||||
import { useUserInfo } from '/@/stores/userInfo'
|
||||
import { fullUrl } from '/@/utils/common'
|
||||
import { onClickMenu } from '/@/utils/router'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const userInfo = useUserInfo()
|
||||
const memberCenter = useMemberCenter()
|
||||
|
||||
const routerPush = (route: string | RouteRecordRaw) => {
|
||||
if (typeof route === 'string') {
|
||||
router.push({ name: route })
|
||||
} else {
|
||||
onClickMenu(route)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.ba-user-layouts {
|
||||
width: 240px;
|
||||
background-color: var(--ba-bg-color-overlay);
|
||||
box-shadow: var(--el-box-shadow-light);
|
||||
}
|
||||
.userinfo {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 20px 0;
|
||||
}
|
||||
.username {
|
||||
display: block;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
padding: 10px 0;
|
||||
font-size: var(--el-font-size-large);
|
||||
font-weight: bold;
|
||||
}
|
||||
.user-avatar-box {
|
||||
position: relative;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.user-avatar {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.user-avatar-gender {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 10px;
|
||||
height: 22px;
|
||||
width: 22px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: var(--ba-bg-color-overlay);
|
||||
border-radius: 50%;
|
||||
box-shadow: var(--el-box-shadow);
|
||||
}
|
||||
.userinfo-button-item {
|
||||
font-size: var(--el-font-size-small);
|
||||
height: 30px;
|
||||
}
|
||||
.user-menus {
|
||||
font-size: var(--el-font-size-base);
|
||||
color: var(--el-text-color-regular);
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
.user-menu-max-title {
|
||||
font-size: 15px;
|
||||
color: var(--el-text-color-secondary);
|
||||
padding: 5px 30px;
|
||||
}
|
||||
.user-menu-item {
|
||||
padding: 10px 30px;
|
||||
cursor: pointer;
|
||||
.icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
text-align: center;
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
.user-menu-item:hover,
|
||||
.user-menu-item.active {
|
||||
border-left: 2px solid var(--el-color-primary);
|
||||
padding-left: 28px;
|
||||
color: var(--el-color-primary);
|
||||
.icon {
|
||||
color: var(--el-color-primary) !important;
|
||||
}
|
||||
background-color: var(--el-color-info-light-8);
|
||||
}
|
||||
@media screen and (max-width: 991px) {
|
||||
.ba-user-layouts {
|
||||
width: 100%;
|
||||
background-color: var(--ba-bg-color-overlay);
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,33 @@
|
||||
<template>
|
||||
<el-footer class="footer">
|
||||
<div>
|
||||
Copyright @ 2020~{{ new Date().getFullYear() }} {{ siteConfig.siteName }} {{ $t('Copyright') }}
|
||||
<a href="http://beian.miit.gov.cn/">{{ siteConfig.recordNumber }}</a>
|
||||
</div>
|
||||
</el-footer>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useSiteConfig } from '/@/stores/siteConfig'
|
||||
|
||||
const siteConfig = useSiteConfig()
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.footer {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background-color: var(--el-color-info-light-7);
|
||||
a {
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
@media screen and (max-width: 768px) {
|
||||
a {
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
127
dafuweng-webman/web/src/layouts/frontend/components/header.vue
Normal file
127
dafuweng-webman/web/src/layouts/frontend/components/header.vue
Normal file
@@ -0,0 +1,127 @@
|
||||
<template>
|
||||
<el-header class="header">
|
||||
<el-row justify="center">
|
||||
<el-col class="header-row" :xs="24" :sm="24" :md="16">
|
||||
<div @click="router.push({ name: '/' })" class="header-logo">
|
||||
<img src="~assets/logo.png" />
|
||||
<span class="site-name">{{ siteConfig.siteName }}</span>
|
||||
</div>
|
||||
<div v-if="!memberCenter.state.menuExpand" @click="memberCenter.toggleMenuExpand(true)" class="user-menus-expand hidden-md-and-up">
|
||||
<Icon name="fa fa-indent" color="var(--el-color-primary)" size="20" />
|
||||
</div>
|
||||
|
||||
<el-scrollbar ref="layoutMenuScrollbarRef" class="hidden-sm-and-down">
|
||||
<Menu class="frontend-header-menu" :ellipsis="false" mode="horizontal" />
|
||||
</el-scrollbar>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-drawer
|
||||
class="ba-aside-drawer"
|
||||
:append-to-body="true"
|
||||
v-model="memberCenter.state.menuExpand"
|
||||
:with-header="false"
|
||||
direction="ltr"
|
||||
:size="memberCenter.state.shrink ? '70%' : '40%'"
|
||||
>
|
||||
<div class="header-row">
|
||||
<div @click="router.push({ name: '/' })" class="header-logo">
|
||||
<img src="~assets/logo.png" />
|
||||
<span class="site-name">{{ siteConfig.siteName }}</span>
|
||||
</div>
|
||||
<div @click="memberCenter.toggleMenuExpand(false)" class="user-menus-expand hidden-md-and-up">
|
||||
<Icon name="fa fa-dedent" color="var(--el-color-primary)" size="20" />
|
||||
</div>
|
||||
</div>
|
||||
<Menu :show-icon="true" mode="vertical" />
|
||||
</el-drawer>
|
||||
</el-header>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onBeforeRouteUpdate, useRouter } from 'vue-router'
|
||||
import { initialize } from '/@/api/frontend/index'
|
||||
import Menu from '/@/layouts/frontend/components/menu.vue'
|
||||
import { useMemberCenter } from '/@/stores/memberCenter'
|
||||
import { layoutMenuScrollbarRef } from '/@/stores/refs'
|
||||
import { useSiteConfig } from '/@/stores/siteConfig'
|
||||
|
||||
const router = useRouter()
|
||||
const siteConfig = useSiteConfig()
|
||||
const memberCenter = useMemberCenter()
|
||||
|
||||
onBeforeRouteUpdate(() => {
|
||||
memberCenter.toggleMenuExpand(false)
|
||||
})
|
||||
|
||||
/**
|
||||
* 前端初始化请求,获取站点配置信息,动态路由信息等
|
||||
*/
|
||||
initialize()
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.header {
|
||||
background-color: var(--ba-bg-color-overlay);
|
||||
box-shadow: 0 0 8px rgba(0 0 0 / 8%);
|
||||
.frontend-header-menu {
|
||||
height: var(--el-header-height);
|
||||
}
|
||||
}
|
||||
.header-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
.header-logo {
|
||||
display: flex;
|
||||
height: var(--el-header-height);
|
||||
align-items: center;
|
||||
padding-right: 15px;
|
||||
cursor: pointer;
|
||||
img {
|
||||
height: 34px;
|
||||
width: 34px;
|
||||
}
|
||||
.site-name {
|
||||
padding-left: 4px;
|
||||
font-size: var(--el-font-size-large);
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
.user-menus-expand {
|
||||
display: flex;
|
||||
height: var(--el-header-height);
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
.ba-aside-drawer {
|
||||
.header-row {
|
||||
padding: 10px 20px;
|
||||
background-color: var(--el-color-info-light-9);
|
||||
.header-logo {
|
||||
img {
|
||||
height: 28px;
|
||||
width: 28px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@at-root html.dark {
|
||||
.header-logo .site-name {
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 768px) {
|
||||
.user-menus-expand {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 414px) {
|
||||
.frontend-header-menu :deep(.el-sub-menu .el-sub-menu__title) {
|
||||
padding: 0 20px;
|
||||
.el-icon {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
22
dafuweng-webman/web/src/layouts/frontend/components/main.vue
Normal file
22
dafuweng-webman/web/src/layouts/frontend/components/main.vue
Normal file
@@ -0,0 +1,22 @@
|
||||
<template>
|
||||
<el-main class="layout-main">
|
||||
<router-view v-slot="{ Component }">
|
||||
<transition :name="config.layout.mainAnimation" mode="out-in">
|
||||
<component :is="Component" />
|
||||
</transition>
|
||||
</router-view>
|
||||
</el-main>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useConfig } from '/@/stores/config'
|
||||
|
||||
const config = useConfig()
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.layout-main {
|
||||
padding: 0 !important;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
</style>
|
||||
256
dafuweng-webman/web/src/layouts/frontend/components/menu.vue
Normal file
256
dafuweng-webman/web/src/layouts/frontend/components/menu.vue
Normal file
@@ -0,0 +1,256 @@
|
||||
<template>
|
||||
<el-menu ref="layoutMenuRef" :default-active="state.activeMenu" @select="onSelect">
|
||||
<el-menu-item @click="router.push({ name: '/' })" v-blur index="index">
|
||||
<Icon v-if="props.showIcon" name="fa fa-home" color="var(--el-text-color-primary)" />
|
||||
<template #title>{{ $t('Home') }}</template>
|
||||
</el-menu-item>
|
||||
|
||||
<!-- 动态菜单 -->
|
||||
<MenuSub :menus="siteConfig.headNav" :show-icon="showIcon" />
|
||||
|
||||
<template v-if="memberCenter.state.open">
|
||||
<el-sub-menu v-if="userInfo.isLogin()" @click="$attrs.mode == 'vertical' ? '' : router.push({ name: 'user' })" v-blur index="user-box">
|
||||
<template #title>
|
||||
<div class="header-user-box">
|
||||
<img
|
||||
class="header-user-avatar"
|
||||
:class="$attrs.mode == 'vertical' ? 'icon-header-user-avatar' : ''"
|
||||
:src="fullUrl(userInfo.avatar ? userInfo.avatar : '/static/images/avatar.png')"
|
||||
alt=""
|
||||
/>
|
||||
{{ userInfo.nickname }}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-menu-item @click="router.push({ name: 'user' })" v-blur index="user">
|
||||
<Icon v-if="showIcon" name="fa fa-user-circle" color="var(--el-text-color-primary)" />
|
||||
{{ $t('Member Center') }}
|
||||
</el-menu-item>
|
||||
|
||||
<!-- 动态菜单 -->
|
||||
<MenuSub :menus="memberCenter.state.navUserMenus" :show-icon="showIcon" />
|
||||
|
||||
<!-- 会员中心菜单 -->
|
||||
<MenuSub :menus="memberCenter.state.viewRoutes" :show-icon="showIcon" />
|
||||
|
||||
<el-menu-item @click="userInfo.logout()" v-blur index="user-logout">
|
||||
<Icon v-if="showIcon" name="fa fa-sign-out" color="var(--el-text-color-primary)" />
|
||||
{{ $t('Logout login') }}
|
||||
</el-menu-item>
|
||||
</el-sub-menu>
|
||||
<el-menu-item v-else @click="router.push({ name: 'user' })" v-blur index="user">
|
||||
<Icon v-if="showIcon" name="fa fa-user-circle" color="var(--el-text-color-primary)" />
|
||||
{{ $t('Member Center') }}
|
||||
</el-menu-item>
|
||||
|
||||
<el-sub-menu v-blur index="language-switch" class="language-switch">
|
||||
<template #title>
|
||||
<Icon v-if="showIcon" name="local-lang" color="var(--el-text-color-primary)" />
|
||||
{{ $t('Language') }}
|
||||
</template>
|
||||
<el-menu-item
|
||||
@click="editDefaultLang(item.name)"
|
||||
v-for="item in config.lang.langArray"
|
||||
:key="item.name"
|
||||
:index="'language-switch-' + item.value"
|
||||
class="language-switch"
|
||||
>
|
||||
<Icon v-if="showIcon" name="fa fa-circle-o" color="var(--el-text-color-primary)" />
|
||||
{{ item.value }}
|
||||
</el-menu-item>
|
||||
</el-sub-menu>
|
||||
|
||||
<el-menu-item index="theme-switch" class="theme-switch" :class="$attrs.mode + '-theme-switch'">
|
||||
<DarkSwitch @click="toggleDark()" />
|
||||
</el-menu-item>
|
||||
</template>
|
||||
</el-menu>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { nextTick, reactive } from 'vue'
|
||||
import { editDefaultLang } from '/@/lang/index'
|
||||
import { useConfig } from '/@/stores/config'
|
||||
import { useUserInfo } from '/@/stores/userInfo'
|
||||
import { useSiteConfig } from '/@/stores/siteConfig'
|
||||
import { useMemberCenter } from '/@/stores/memberCenter'
|
||||
import { fullUrl } from '/@/utils/common'
|
||||
import MenuSub from '/@/layouts/frontend/components/menuSub.vue'
|
||||
import toggleDark from '/@/utils/useDark'
|
||||
import DarkSwitch from '/@/layouts/common/components/darkSwitch.vue'
|
||||
import { onBeforeRouteUpdate, useRoute, useRouter } from 'vue-router'
|
||||
import type { RouteLocationNormalizedLoaded, RouteRecordRaw } from 'vue-router'
|
||||
import { layoutMenuRef } from '/@/stores/refs'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const config = useConfig()
|
||||
const userInfo = useUserInfo()
|
||||
const siteConfig = useSiteConfig()
|
||||
const memberCenter = useMemberCenter()
|
||||
|
||||
interface Props {
|
||||
showIcon?: boolean
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
showIcon: false,
|
||||
})
|
||||
|
||||
const state = reactive({
|
||||
activeMenu: '',
|
||||
})
|
||||
|
||||
/**
|
||||
* 设置激活菜单
|
||||
*/
|
||||
const setActiveMenu = (route: RouteLocationNormalizedLoaded) => {
|
||||
if (route.path == '/') return (state.activeMenu = 'index')
|
||||
|
||||
const menuId = findMenus(route)
|
||||
if (menuId) {
|
||||
state.activeMenu = 'column-' + menuId
|
||||
} else if (route.path.startsWith('/user')) {
|
||||
state.activeMenu = 'user'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 菜单被点击时额外对无需激活的菜单处理(外链、暗黑模式开关、语言切换等)
|
||||
* 检查菜单是否需要激活,如果否,还原 state.activeMenu
|
||||
*/
|
||||
const onSelect = (index: string) => {
|
||||
if (
|
||||
noNeedActive(siteConfig.headNav, index) ||
|
||||
noNeedActive(memberCenter.state.navUserMenus, index) ||
|
||||
noNeedActive(memberCenter.state.viewRoutes, index)
|
||||
) {
|
||||
const oldActiveMenu = state.activeMenu
|
||||
state.activeMenu = ''
|
||||
nextTick(() => {
|
||||
state.activeMenu = oldActiveMenu
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查一个菜单是否需要激活态
|
||||
* @param menus
|
||||
* @param index
|
||||
*/
|
||||
const noNeedActive = (menus: RouteRecordRaw[], index: string) => {
|
||||
if (index.indexOf('language-switch') === 0 || index == 'theme-switch') {
|
||||
return true
|
||||
}
|
||||
return isExternalLink(menus, index)
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查一个菜单是否是外站链接,如果是,不要激活
|
||||
* @param menus
|
||||
* @param index
|
||||
*/
|
||||
const isExternalLink = (menus: RouteRecordRaw[], index: string): boolean => {
|
||||
for (const key in menus) {
|
||||
const columnIndex = `column-${menus[key].meta?.id}`
|
||||
if (columnIndex == index) {
|
||||
return menus[key].meta?.menu_type == 'link'
|
||||
}
|
||||
if (menus[key].children?.length) {
|
||||
return isExternalLink(menus[key].children!, index)
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归的搜索菜单 Index
|
||||
*/
|
||||
const searchMenuIndex = (menus: RouteRecordRaw[], route: RouteLocationNormalizedLoaded): number | false => {
|
||||
let find: boolean | number = false
|
||||
for (const key in menus) {
|
||||
if (menus[key].meta?.id && menus[key].path == route.fullPath) {
|
||||
return menus[key].meta.id as number
|
||||
}
|
||||
if (menus[key].children && menus[key].children?.length) {
|
||||
find = searchMenuIndex(menus[key].children, route)
|
||||
if (find !== false) return find
|
||||
}
|
||||
}
|
||||
return find
|
||||
}
|
||||
|
||||
/**
|
||||
* 从动态菜单(顶栏、会员中心下拉、会员中心菜单)中搜索一个菜单
|
||||
*/
|
||||
const findMenus = (route: RouteLocationNormalizedLoaded) => {
|
||||
// 顶栏菜单
|
||||
const headNavIndex = searchMenuIndex(siteConfig.headNav, route)
|
||||
if (headNavIndex !== false) return headNavIndex
|
||||
|
||||
// 会员中心下拉菜单
|
||||
const navUserMenuIndex = searchMenuIndex(memberCenter.state.navUserMenus, route)
|
||||
if (navUserMenuIndex !== false) return navUserMenuIndex
|
||||
|
||||
// 会员中心菜单
|
||||
return searchMenuIndex(memberCenter.state.viewRoutes, route)
|
||||
}
|
||||
|
||||
setActiveMenu(route)
|
||||
onBeforeRouteUpdate((to) => {
|
||||
setActiveMenu(to)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.header-user-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
.header-user-avatar {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-right: 4px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.icon-header-user-avatar {
|
||||
margin-left: 4px;
|
||||
margin-right: 6px;
|
||||
}
|
||||
}
|
||||
.el-sub-menu .icon,
|
||||
.el-menu-item .icon {
|
||||
vertical-align: middle;
|
||||
margin-right: 2px;
|
||||
width: 24px;
|
||||
text-align: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.is-active > .icon {
|
||||
color: var(--el-menu-active-color) !important;
|
||||
}
|
||||
.el-menu {
|
||||
border-bottom: none;
|
||||
border-right: none;
|
||||
.theme-switch.is-active,
|
||||
.language-switch.is-active {
|
||||
border-bottom: none;
|
||||
:deep(.el-sub-menu__title) {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
.theme-switch {
|
||||
--el-menu-hover-bg-color: none;
|
||||
padding-right: 0;
|
||||
}
|
||||
.vertical-theme-switch {
|
||||
.theme-toggle-content {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
.theme-toggle-content {
|
||||
padding-right: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<template v-for="(item, idx) in props.menus" :key="idx">
|
||||
<template v-if="!isEmpty(item.children)">
|
||||
<el-sub-menu @click="onClickSubMenu(item)" v-blur :index="`column-${item.meta?.id}`">
|
||||
<template #title>
|
||||
<Icon v-if="showIcon" :name="item.meta?.icon" color="var(--el-text-color-primary)" />
|
||||
{{ item.meta?.title }}
|
||||
</template>
|
||||
<MenuSub :menus="item.children!" :show-icon="showIcon" />
|
||||
</el-sub-menu>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-menu-item @click="onClickMenu(item)" v-blur :index="'column-' + item.meta?.id" :class="(item.name as string).replace(/[\/]/g, '-')">
|
||||
<Icon v-if="showIcon" :name="item.meta?.icon" color="var(--el-text-color-primary)" />
|
||||
<template #title>{{ item.meta?.title }}</template>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { isEmpty } from 'lodash-es'
|
||||
import { onClickMenu } from '/@/utils/router'
|
||||
import type { RouteRecordRaw } from 'vue-router'
|
||||
import MenuSub from '/@/layouts/frontend/components/menuSub.vue'
|
||||
|
||||
interface Props {
|
||||
menus: RouteRecordRaw[]
|
||||
showIcon?: boolean
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
menus: () => [],
|
||||
showIcon: false,
|
||||
})
|
||||
|
||||
const onClickSubMenu = (menu: RouteRecordRaw) => {
|
||||
/**
|
||||
* 1、'/'表示菜单规则的 path 为空
|
||||
* 2、会员中心菜单目录不需要跳转
|
||||
*/
|
||||
if (menu.path == '/' || menu.meta?.type == 'menu_dir') return
|
||||
onClickMenu(menu)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.el-sub-menu .icon,
|
||||
.el-menu-item .icon {
|
||||
vertical-align: middle;
|
||||
margin-right: 2px;
|
||||
width: 24px;
|
||||
text-align: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.is-active > .icon {
|
||||
color: var(--el-menu-active-color) !important;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,35 @@
|
||||
<template>
|
||||
<el-container class="is-vertical">
|
||||
<Header />
|
||||
<el-scrollbar :style="layoutMainScrollbarStyle" ref="layoutMainScrollbarRef">
|
||||
<el-row class="frontend-footer-brother" justify="center">
|
||||
<el-col class="user-layouts" :span="16" :xs="24">
|
||||
<Aside class="hidden-sm-and-down" />
|
||||
<Main />
|
||||
</el-col>
|
||||
</el-row>
|
||||
<Footer />
|
||||
</el-scrollbar>
|
||||
</el-container>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Header from '/@/layouts/frontend/components/header.vue'
|
||||
import Aside from '/@/layouts/frontend/components/aside.vue'
|
||||
import Main from '/@/layouts/frontend/components/main.vue'
|
||||
import Footer from '/@/layouts/frontend/components/footer.vue'
|
||||
import { layoutMainScrollbarRef, layoutMainScrollbarStyle } from '/@/stores/refs'
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.user-layouts {
|
||||
display: flex;
|
||||
padding-top: 15px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
@media screen and (max-width: 768px) {
|
||||
.user-layouts {
|
||||
padding-top: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,32 @@
|
||||
<template>
|
||||
<el-container class="is-vertical">
|
||||
<Header />
|
||||
<el-scrollbar :style="layoutMainScrollbarStyle" ref="layoutMainScrollbarRef">
|
||||
<el-row class="frontend-footer-brother" justify="center">
|
||||
<el-col class="user-layouts" :span="16" :xs="24">
|
||||
<el-alert :center="true" :title="$t('Member center disabled')" type="error" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
<Footer />
|
||||
</el-scrollbar>
|
||||
</el-container>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Header from '/@/layouts/frontend/components/header.vue'
|
||||
import Footer from '/@/layouts/frontend/components/footer.vue'
|
||||
import { layoutMainScrollbarRef, layoutMainScrollbarStyle } from '/@/stores/refs'
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.user-layouts {
|
||||
display: flex;
|
||||
padding-top: 15px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
@media screen and (max-width: 768px) {
|
||||
.user-layouts {
|
||||
padding-top: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
84
dafuweng-webman/web/src/layouts/frontend/user.vue
Normal file
84
dafuweng-webman/web/src/layouts/frontend/user.vue
Normal file
@@ -0,0 +1,84 @@
|
||||
<template>
|
||||
<component :is="memberCenter.state.layoutMode"></component>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted } from 'vue'
|
||||
import { useUserInfo } from '/@/stores/userInfo'
|
||||
import { useSiteConfig } from '/@/stores/siteConfig'
|
||||
import { useMemberCenter } from '/@/stores/memberCenter'
|
||||
import { initialize } from '/@/api/frontend/index'
|
||||
import { getFirstRoute, routePush } from '/@/utils/router'
|
||||
import { memberCenterBaseRoutePath } from '/@/router/static/memberCenterBase'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import Default from '/@/layouts/frontend/container/default.vue'
|
||||
import Disable from '/@/layouts/frontend/container/disable.vue'
|
||||
import { ElNotification } from 'element-plus'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import userMounted from '/@/components/mixins/userMounted'
|
||||
import { isEmpty } from 'lodash-es'
|
||||
|
||||
defineOptions({
|
||||
components: { Default, Disable },
|
||||
})
|
||||
|
||||
const { t } = useI18n()
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const userInfo = useUserInfo()
|
||||
const siteConfig = useSiteConfig()
|
||||
const memberCenter = useMemberCenter()
|
||||
|
||||
onMounted(async () => {
|
||||
const ret = await userMounted()
|
||||
if (ret.type == 'break') return
|
||||
if (ret.type == 'reload') return (window.location.href = ret.url)
|
||||
|
||||
if (!userInfo.token) return router.push({ name: 'userLogin' })
|
||||
|
||||
/**
|
||||
* 会员中心初始化请求,获取会员中心菜单信息等
|
||||
*/
|
||||
|
||||
const callback = () => {
|
||||
if (ret.type == 'jump') return router.push(ret.url)
|
||||
|
||||
// 预跳转到上次路径
|
||||
if (route.params.to) {
|
||||
const lastRoute = JSON.parse(route.params.to as string)
|
||||
if (lastRoute.path != memberCenterBaseRoutePath) {
|
||||
let query = !isEmpty(lastRoute.query) ? lastRoute.query : {}
|
||||
routePush({ path: lastRoute.path, query: query })
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 跳转到第一个菜单
|
||||
if (route.name == 'userMainLoading') {
|
||||
let firstRoute = getFirstRoute(memberCenter.state.viewRoutes)
|
||||
if (firstRoute) {
|
||||
router.push({ path: firstRoute.path })
|
||||
} else {
|
||||
ElNotification({
|
||||
type: 'error',
|
||||
message: t('No route found to jump~'),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (siteConfig.userInitialize) {
|
||||
callback()
|
||||
} else {
|
||||
initialize(callback, true)
|
||||
}
|
||||
|
||||
if (document.body.clientWidth < 1024) {
|
||||
memberCenter.setShrink(true)
|
||||
} else {
|
||||
memberCenter.setShrink(false)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
Reference in New Issue
Block a user