移动端header用户信息部分增加向下箭头及点击下拉弹窗功能
This commit is contained in:
parent
d49d265472
commit
fe4e3a0b25
@ -26,28 +26,41 @@
|
|||||||
<AppSidebar :collapsed="sidebarCollapsed" @menu-select="handleMenuSelect" />
|
<AppSidebar :collapsed="sidebarCollapsed" @menu-select="handleMenuSelect" />
|
||||||
</n-layout-sider>
|
</n-layout-sider>
|
||||||
<n-layout class="h-full">
|
<n-layout class="h-full">
|
||||||
<!-- 移动端顶部导航栏 -->
|
<!-- 移动端顶部导航栏 -->
|
||||||
<div
|
<div
|
||||||
v-if="isMobile && !isSignupFlow && !isHideSidebar && session.user"
|
v-if="isMobile && !isSignupFlow && !isHideSidebar && session.user"
|
||||||
class="mobile-header"
|
class="mobile-header"
|
||||||
>
|
>
|
||||||
<div class="mobile-header-content">
|
<div class="mobile-header-content">
|
||||||
<JLogo class="mobile-logo" />
|
<JLogo class="mobile-logo" />
|
||||||
<div class="mobile-user-info">
|
<n-dropdown
|
||||||
{{ teamUserText }}
|
:options="mobileDropdownOptions"
|
||||||
|
:show-arrow="true"
|
||||||
|
trigger="click"
|
||||||
|
@select="handleMobileDropdownSelect"
|
||||||
|
placement="bottom-start"
|
||||||
|
>
|
||||||
|
<div class="mobile-user-info-wrapper">
|
||||||
|
<div class="mobile-user-info">
|
||||||
|
{{ teamUserText }}
|
||||||
|
</div>
|
||||||
|
<n-icon class="mobile-chevron-icon">
|
||||||
|
<ChevronDown />
|
||||||
|
</n-icon>
|
||||||
</div>
|
</div>
|
||||||
<n-button
|
</n-dropdown>
|
||||||
quaternary
|
<n-button
|
||||||
circle
|
quaternary
|
||||||
@click="sidebarCollapsed = false"
|
circle
|
||||||
class="mobile-menu-button"
|
@click="sidebarCollapsed = false"
|
||||||
>
|
class="mobile-menu-button"
|
||||||
<template #icon>
|
>
|
||||||
<n-icon><MenuIcon /></n-icon>
|
<template #icon>
|
||||||
</template>
|
<n-icon><MenuIcon /></n-icon>
|
||||||
</n-button>
|
</template>
|
||||||
</div>
|
</n-button>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div class="w-full h-full overflow-auto" id="scrollContainer">
|
<div class="w-full h-full overflow-auto" id="scrollContainer">
|
||||||
<div
|
<div
|
||||||
v-if="
|
v-if="
|
||||||
@ -68,13 +81,15 @@
|
|||||||
</n-layout>
|
</n-layout>
|
||||||
<Toaster position="top-right" />
|
<Toaster position="top-right" />
|
||||||
<component v-for="dialog in dialogs" :is="dialog" :key="dialog.id" />
|
<component v-for="dialog in dialogs" :is="dialog" :key="dialog.id" />
|
||||||
|
<!-- 切换团队对话框 -->
|
||||||
|
<SwitchTeamDialog v-model="showTeamSwitcher" />
|
||||||
</div>
|
</div>
|
||||||
</n-config-provider>
|
</n-config-provider>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { defineAsyncComponent, computed, watch, ref, provide, onMounted, onUnmounted } from 'vue';
|
import { defineAsyncComponent, computed, watch, ref, provide, onMounted, onUnmounted, h, getCurrentInstance } from 'vue';
|
||||||
import { NLayout, NLayoutSider, NConfigProvider, NButton, NIcon } from 'naive-ui';
|
import { NLayout, NLayoutSider, NConfigProvider, NButton, NIcon, NDropdown } from 'naive-ui';
|
||||||
import { Toaster } from 'vue-sonner';
|
import { Toaster } from 'vue-sonner';
|
||||||
import { dialogs } from './utils/components';
|
import { dialogs } from './utils/components';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
@ -82,13 +97,20 @@ import { getTeam } from './data/team';
|
|||||||
import { session } from './data/session.js';
|
import { session } from './data/session.js';
|
||||||
import JLogo from '@/components/icons/JLogo.vue';
|
import JLogo from '@/components/icons/JLogo.vue';
|
||||||
import MenuIcon from '~icons/lucide/menu';
|
import MenuIcon from '~icons/lucide/menu';
|
||||||
|
import ChevronDown from '~icons/lucide/chevron-down';
|
||||||
|
|
||||||
const AppSidebar = defineAsyncComponent(
|
const AppSidebar = defineAsyncComponent(
|
||||||
() => import('./components/AppSidebar.vue'),
|
() => import('./components/AppSidebar.vue'),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const SwitchTeamDialog = defineAsyncComponent(
|
||||||
|
() => import('./components/SwitchTeamDialog.vue'),
|
||||||
|
);
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const team = getTeam();
|
const team = getTeam();
|
||||||
|
const instance = getCurrentInstance();
|
||||||
|
const showTeamSwitcher = ref(false);
|
||||||
|
|
||||||
// Naive UI 主题配置 - 使用标准方式配置 tooltip 和 menu
|
// Naive UI 主题配置 - 使用标准方式配置 tooltip 和 menu
|
||||||
const themeOverrides = {
|
const themeOverrides = {
|
||||||
@ -159,6 +181,39 @@ const handleMenuSelect = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 移动端下拉菜单选项
|
||||||
|
const mobileDropdownOptions = computed(() => {
|
||||||
|
const options = [];
|
||||||
|
const teamData = team?.pg;
|
||||||
|
if (
|
||||||
|
teamData &&
|
||||||
|
(teamData.valid_teams?.length > 1 || teamData.is_desk_user)
|
||||||
|
) {
|
||||||
|
options.push({
|
||||||
|
label: '切换团队',
|
||||||
|
key: 'switch-team',
|
||||||
|
icon: () => h('i', { class: 'i-lucide-command h-4 w-4' }),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
options.push({
|
||||||
|
label: '退出登录',
|
||||||
|
key: 'logout',
|
||||||
|
icon: () => h('i', { class: 'i-lucide-log-out h-4 w-4' }),
|
||||||
|
});
|
||||||
|
return options;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 处理移动端下拉菜单选择
|
||||||
|
const handleMobileDropdownSelect = (key) => {
|
||||||
|
if (key === 'switch-team') {
|
||||||
|
showTeamSwitcher.value = true;
|
||||||
|
} else if (key === 'logout') {
|
||||||
|
if (session) {
|
||||||
|
session.logout.submit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const isHideSidebar = computed(() => {
|
const isHideSidebar = computed(() => {
|
||||||
const alwaysHideSidebarRoutes = [
|
const alwaysHideSidebarRoutes = [
|
||||||
'Site Login',
|
'Site Login',
|
||||||
@ -298,6 +353,26 @@ provide('session', session);
|
|||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mobile-user-info-wrapper {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 6px 8px;
|
||||||
|
border-radius: 6px;
|
||||||
|
transition: background-color 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-user-info-wrapper:hover {
|
||||||
|
background: rgba(0, 0, 0, 0.04);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-user-info-wrapper:active {
|
||||||
|
background: rgba(0, 0, 0, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
.mobile-user-info {
|
.mobile-user-info {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
@ -306,6 +381,18 @@ provide('session', session);
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-chevron-icon {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #8b8e95;
|
||||||
|
flex-shrink: 0;
|
||||||
|
transition: color 0.2s ease, transform 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-user-info-wrapper:hover .mobile-chevron-icon {
|
||||||
|
color: #4a5568;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mobile-menu-button {
|
.mobile-menu-button {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user