feat: 完善文档中心与报销申请交互及侧边栏重构
后端优化编排器报销查询和本体检测精度,增强报销单草稿保 存和附件回填逻辑,前端重构侧边栏组件支持折叠和图标导 航,完善文档中心状态筛选和详情提示,报销创建和审批详情 页优化会话管理和费用明细交互,新增助手应用服务和预设动 作工具函数,补充单元测试覆盖。
This commit is contained in:
@@ -14,8 +14,8 @@
|
||||
</div>
|
||||
|
||||
<div class="assistant-copy">
|
||||
<h3>嗨,{{ assistantGreetingName }},描述费用或上传票据,AI 直接帮你判断怎么报</h3>
|
||||
<p>自动识别报销类别、核对附件完整性,并生成可继续提交的报销草稿。</p>
|
||||
<h3>嗨,{{ assistantGreetingName }},描述您想做的事,AI 会直接帮您处理</h3>
|
||||
<p>我会自动识别您的意图,协助完成费用申请、报销、查询和制度问答等业务工作,耐心把事情推进到可执行的下一步。</p>
|
||||
|
||||
<div class="assistant-input">
|
||||
<input
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<aside class="rail" aria-label="主导航">
|
||||
<aside class="rail" :class="{ 'rail-collapsed': collapsed }" aria-label="主导航">
|
||||
<div class="rail-brand">
|
||||
<div class="brand-mark" aria-hidden="true">
|
||||
<img v-if="companyLogo" :src="companyLogo" alt="System Logo" class="custom-logo" />
|
||||
@@ -9,6 +9,16 @@
|
||||
</svg>
|
||||
</div>
|
||||
<strong class="brand-name">{{ displayCompanyName }}</strong>
|
||||
<button
|
||||
class="rail-collapse-btn"
|
||||
type="button"
|
||||
:aria-label="collapsed ? '展开侧边栏' : '折叠侧边栏'"
|
||||
:title="collapsed ? '展开侧边栏' : '折叠侧边栏'"
|
||||
:aria-expanded="!collapsed"
|
||||
@click="emit('toggle-collapse')"
|
||||
>
|
||||
<i :class="collapsed ? 'mdi mdi-chevron-right' : 'mdi mdi-chevron-left'"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<nav class="rail-nav" aria-label="功能导航">
|
||||
@@ -18,6 +28,7 @@
|
||||
class="nav-btn"
|
||||
:class="{ active: activeView === item.id }"
|
||||
type="button"
|
||||
:title="collapsed ? item.displayLabel : undefined"
|
||||
@click="emit('navigate', item.id)"
|
||||
>
|
||||
<span class="nav-icon" v-html="item.icon"></span>
|
||||
@@ -26,15 +37,38 @@
|
||||
</button>
|
||||
</nav>
|
||||
|
||||
<div class="rail-user">
|
||||
<div class="user-menu" role="menu" aria-label="用户菜单">
|
||||
<div
|
||||
class="rail-user"
|
||||
@mouseenter="openCollapsedUserMenu"
|
||||
@mouseleave="closeCollapsedUserMenu"
|
||||
@focusin="openCollapsedUserMenu"
|
||||
@focusout="handleUserFocusOut"
|
||||
>
|
||||
<div v-if="!collapsed" class="user-menu" role="menu" aria-label="用户菜单">
|
||||
<button class="user-menu-item" type="button" @click="emit('logout')">
|
||||
<i class="mdi mdi-logout-variant"></i>
|
||||
<span>退出系统</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="user-summary" tabindex="0" aria-label="用户信息">
|
||||
<Teleport to="body">
|
||||
<div
|
||||
v-if="collapsed && userMenuOpen"
|
||||
class="rail-user-menu-floating"
|
||||
:style="userMenuStyle"
|
||||
role="menu"
|
||||
aria-label="用户菜单"
|
||||
@mouseenter="clearUserMenuCloseTimer"
|
||||
@mouseleave="closeCollapsedUserMenu"
|
||||
>
|
||||
<button class="user-menu-item" type="button" @click="handleLogout">
|
||||
<i class="mdi mdi-logout-variant"></i>
|
||||
<span>退出系统</span>
|
||||
</button>
|
||||
</div>
|
||||
</Teleport>
|
||||
|
||||
<div class="user-summary" tabindex="0" aria-label="用户信息" :title="collapsed ? displayUser.name : undefined">
|
||||
<span class="user-avatar">{{ displayUser.avatar }}</span>
|
||||
<span class="user-copy">
|
||||
<strong>{{ displayUser.name }}</strong>
|
||||
@@ -47,7 +81,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, onBeforeUnmount, onMounted } from 'vue'
|
||||
import { computed, onBeforeUnmount, onMounted, reactive, ref, watch } from 'vue'
|
||||
|
||||
import { useApprovalInbox } from '../../composables/useApprovalInbox.js'
|
||||
|
||||
@@ -69,10 +103,14 @@ const props = defineProps({
|
||||
role: '管理员',
|
||||
avatar: '管'
|
||||
})
|
||||
},
|
||||
collapsed: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['navigate', 'openChat', 'logout'])
|
||||
const emit = defineEmits(['navigate', 'openChat', 'logout', 'toggle-collapse'])
|
||||
|
||||
const {
|
||||
badgeLabel: approvalBadgeLabel,
|
||||
@@ -108,9 +146,6 @@ onMounted(() => {
|
||||
startApprovalInboxPolling()
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
stopApprovalInboxPolling()
|
||||
})
|
||||
|
||||
const displayUser = computed(() => ({
|
||||
name: props.currentUser?.name || '系统管理员',
|
||||
@@ -119,33 +154,133 @@ const displayUser = computed(() => ({
|
||||
}))
|
||||
|
||||
const displayCompanyName = computed(() => props.companyName || 'X-Financial')
|
||||
|
||||
const userMenuOpen = ref(false)
|
||||
let userMenuCloseTimer = null
|
||||
const userMenuPosition = reactive({
|
||||
top: 0,
|
||||
left: 0
|
||||
})
|
||||
|
||||
const userMenuStyle = computed(() => ({
|
||||
top: `${userMenuPosition.top}px`,
|
||||
left: `${userMenuPosition.left}px`
|
||||
}))
|
||||
|
||||
function resolveUserMenuAnchor(element) {
|
||||
return element?.querySelector?.('.user-summary') || element
|
||||
}
|
||||
|
||||
function clearUserMenuCloseTimer() {
|
||||
if (userMenuCloseTimer) {
|
||||
clearTimeout(userMenuCloseTimer)
|
||||
userMenuCloseTimer = null
|
||||
}
|
||||
}
|
||||
|
||||
function openCollapsedUserMenu(event) {
|
||||
if (!props.collapsed) {
|
||||
return
|
||||
}
|
||||
|
||||
clearUserMenuCloseTimer()
|
||||
|
||||
const anchor = resolveUserMenuAnchor(event?.currentTarget)
|
||||
if (!anchor?.getBoundingClientRect) {
|
||||
return
|
||||
}
|
||||
|
||||
const rect = anchor.getBoundingClientRect()
|
||||
userMenuPosition.top = rect.top + rect.height / 2
|
||||
userMenuPosition.left = rect.right + 12
|
||||
userMenuOpen.value = true
|
||||
}
|
||||
|
||||
function closeCollapsedUserMenu() {
|
||||
clearUserMenuCloseTimer()
|
||||
userMenuCloseTimer = setTimeout(() => {
|
||||
userMenuOpen.value = false
|
||||
userMenuCloseTimer = null
|
||||
}, 120)
|
||||
}
|
||||
|
||||
function closeCollapsedUserMenuNow() {
|
||||
clearUserMenuCloseTimer()
|
||||
userMenuOpen.value = false
|
||||
}
|
||||
|
||||
function handleUserFocusOut(event) {
|
||||
if (!props.collapsed) {
|
||||
return
|
||||
}
|
||||
|
||||
const container = event.currentTarget
|
||||
const nextTarget = event.relatedTarget
|
||||
if (nextTarget && container?.contains(nextTarget)) {
|
||||
return
|
||||
}
|
||||
|
||||
closeCollapsedUserMenuNow()
|
||||
}
|
||||
|
||||
function handleLogout() {
|
||||
closeCollapsedUserMenuNow()
|
||||
emit('logout')
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.collapsed,
|
||||
(isCollapsed) => {
|
||||
if (!isCollapsed) {
|
||||
closeCollapsedUserMenuNow()
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
stopApprovalInboxPolling()
|
||||
closeCollapsedUserMenuNow()
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
.rail {
|
||||
--rail-motion-duration: 320ms;
|
||||
--rail-motion-ease: cubic-bezier(0.22, 1, 0.36, 1);
|
||||
--rail-fade-duration: 160ms;
|
||||
|
||||
position: sticky;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: var(--desktop-stage-height, 100dvh);
|
||||
display: grid;
|
||||
grid-template-rows: auto 1fr auto;
|
||||
background:
|
||||
linear-gradient(180deg, rgba(255, 255, 255, 0.98), rgba(248, 251, 250, 0.96)),
|
||||
#fff;
|
||||
min-height: var(--desktop-stage-height, 100dvh);
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
background: linear-gradient(180deg, rgba(255, 255, 255, 0.98), rgba(248, 251, 250, 0.96)), #fff;
|
||||
border-right: 1px solid #dbe4ee;
|
||||
box-shadow: 1px 0 0 rgba(15, 23, 42, 0.02);
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.rail-brand {
|
||||
min-height: 86px;
|
||||
position: relative;
|
||||
min-height: 92px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
justify-content: flex-start;
|
||||
gap: 12px;
|
||||
padding: 22px 20px 18px;
|
||||
padding: 22px 16px 18px;
|
||||
overflow: hidden;
|
||||
transition:
|
||||
padding var(--rail-motion-duration) var(--rail-motion-ease),
|
||||
gap var(--rail-motion-duration) var(--rail-motion-ease);
|
||||
}
|
||||
|
||||
.brand-mark {
|
||||
flex: 0 0 auto;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
display: grid;
|
||||
@@ -153,6 +288,10 @@ const displayCompanyName = computed(() => props.companyName || 'X-Financial')
|
||||
color: #07936f;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
transition:
|
||||
width var(--rail-motion-duration) var(--rail-motion-ease),
|
||||
height var(--rail-motion-duration) var(--rail-motion-ease),
|
||||
margin var(--rail-motion-duration) var(--rail-motion-ease);
|
||||
}
|
||||
|
||||
.custom-logo {
|
||||
@@ -168,26 +307,74 @@ const displayCompanyName = computed(() => props.companyName || 'X-Financial')
|
||||
}
|
||||
|
||||
.brand-name {
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
max-width: 124px;
|
||||
color: #0f172a;
|
||||
font-size: 16px;
|
||||
font-weight: 800;
|
||||
letter-spacing: 0;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
transition:
|
||||
max-width var(--rail-motion-duration) var(--rail-motion-ease),
|
||||
opacity var(--rail-fade-duration) var(--rail-motion-ease),
|
||||
transform var(--rail-fade-duration) var(--rail-motion-ease);
|
||||
}
|
||||
|
||||
.rail-collapse-btn {
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
top: 31px;
|
||||
z-index: 2;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
display: inline-grid;
|
||||
place-items: center;
|
||||
cursor: pointer;
|
||||
border: 1px solid rgba(148, 163, 184, 0.22);
|
||||
border-radius: 9px;
|
||||
background: rgba(255, 255, 255, 0.86);
|
||||
color: #64748b;
|
||||
box-shadow: 0 6px 14px rgba(15, 23, 42, 0.06);
|
||||
transition:
|
||||
top var(--rail-motion-duration) var(--rail-motion-ease),
|
||||
right var(--rail-motion-duration) var(--rail-motion-ease),
|
||||
transform var(--rail-motion-duration) var(--rail-motion-ease),
|
||||
background 180ms var(--ease),
|
||||
border-color 180ms var(--ease),
|
||||
color 180ms var(--ease),
|
||||
box-shadow 180ms var(--ease);
|
||||
}
|
||||
|
||||
.rail-collapse-btn:hover {
|
||||
border-color: rgba(16, 185, 129, 0.28);
|
||||
background: #ecfdf5;
|
||||
color: #059669;
|
||||
}
|
||||
|
||||
.rail-collapse-btn .mdi {
|
||||
font-size: 18px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.rail-nav {
|
||||
display: grid;
|
||||
align-content: start;
|
||||
gap: 14px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
padding: 16px 20px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
flex: 1;
|
||||
transition:
|
||||
padding var(--rail-motion-duration) var(--rail-motion-ease),
|
||||
gap var(--rail-motion-duration) var(--rail-motion-ease);
|
||||
}
|
||||
|
||||
.nav-btn {
|
||||
width: 100%;
|
||||
min-height: 48px;
|
||||
display: grid;
|
||||
grid-template-columns: 28px minmax(0, 1fr) auto;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 0 12px;
|
||||
@@ -196,11 +383,13 @@ const displayCompanyName = computed(() => props.companyName || 'X-Financial')
|
||||
background: transparent;
|
||||
color: #64748b;
|
||||
text-align: left;
|
||||
overflow: hidden;
|
||||
transition:
|
||||
padding var(--rail-motion-duration) var(--rail-motion-ease),
|
||||
gap var(--rail-motion-duration) var(--rail-motion-ease),
|
||||
background 180ms var(--ease),
|
||||
border-color 180ms var(--ease),
|
||||
color 180ms var(--ease),
|
||||
box-shadow 180ms var(--ease);
|
||||
color 180ms var(--ease);
|
||||
}
|
||||
|
||||
.nav-btn:hover {
|
||||
@@ -215,12 +404,17 @@ const displayCompanyName = computed(() => props.companyName || 'X-Financial')
|
||||
}
|
||||
|
||||
.nav-icon {
|
||||
flex: 0 0 28px;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
border-radius: 7px;
|
||||
color: currentColor;
|
||||
transition:
|
||||
flex-basis var(--rail-motion-duration) var(--rail-motion-ease),
|
||||
width var(--rail-motion-duration) var(--rail-motion-ease),
|
||||
height var(--rail-motion-duration) var(--rail-motion-ease);
|
||||
}
|
||||
|
||||
.nav-btn :deep(svg) {
|
||||
@@ -234,17 +428,23 @@ const displayCompanyName = computed(() => props.companyName || 'X-Financial')
|
||||
}
|
||||
|
||||
.nav-label {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
max-width: 128px;
|
||||
color: currentColor;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
line-height: 1.2;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
opacity: 1;
|
||||
transition:
|
||||
max-width var(--rail-motion-duration) var(--rail-motion-ease),
|
||||
opacity var(--rail-fade-duration) var(--rail-motion-ease),
|
||||
transform var(--rail-fade-duration) var(--rail-motion-ease);
|
||||
}
|
||||
|
||||
.nav-badge {
|
||||
flex: 0 0 auto;
|
||||
min-width: 34px;
|
||||
height: 22px;
|
||||
display: inline-flex;
|
||||
@@ -256,7 +456,11 @@ const displayCompanyName = computed(() => props.companyName || 'X-Financial')
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
line-height: 1;
|
||||
transition:
|
||||
min-width var(--rail-motion-duration) var(--rail-motion-ease),
|
||||
max-width var(--rail-motion-duration) var(--rail-motion-ease),
|
||||
padding var(--rail-motion-duration) var(--rail-motion-ease),
|
||||
opacity var(--rail-fade-duration) var(--rail-motion-ease);
|
||||
}
|
||||
|
||||
.rail-user {
|
||||
@@ -266,28 +470,32 @@ const displayCompanyName = computed(() => props.companyName || 'X-Financial')
|
||||
margin: 0;
|
||||
padding: 16px 20px 18px;
|
||||
border-top: 1px solid #edf2f7;
|
||||
transition: padding var(--rail-motion-duration) var(--rail-motion-ease);
|
||||
}
|
||||
|
||||
.user-summary {
|
||||
position: relative;
|
||||
min-width: 0;
|
||||
min-height: 42px;
|
||||
display: grid;
|
||||
grid-template-columns: 38px minmax(0, 1fr) 18px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 4px 0 0;
|
||||
padding: 4px;
|
||||
color: #64748b;
|
||||
border-radius: 12px;
|
||||
outline: none;
|
||||
transition: background 180ms var(--ease);
|
||||
cursor: pointer;
|
||||
transition:
|
||||
gap var(--rail-motion-duration) var(--rail-motion-ease),
|
||||
padding var(--rail-motion-duration) var(--rail-motion-ease),
|
||||
background 180ms var(--ease);
|
||||
}
|
||||
|
||||
.rail-user:hover .user-summary,
|
||||
.rail-user:focus-within .user-summary {
|
||||
.rail-user:hover .user-summary {
|
||||
background: rgba(255, 255, 255, 0.72);
|
||||
}
|
||||
|
||||
.user-avatar {
|
||||
flex: 0 0 36px;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
display: grid;
|
||||
@@ -299,19 +507,30 @@ const displayCompanyName = computed(() => props.companyName || 'X-Financial')
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
font-weight: 800;
|
||||
transition:
|
||||
flex-basis var(--rail-motion-duration) var(--rail-motion-ease),
|
||||
width var(--rail-motion-duration) var(--rail-motion-ease),
|
||||
height var(--rail-motion-duration) var(--rail-motion-ease);
|
||||
}
|
||||
|
||||
.user-copy {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: grid;
|
||||
max-width: 116px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
opacity: 1;
|
||||
transition:
|
||||
max-width var(--rail-motion-duration) var(--rail-motion-ease),
|
||||
opacity var(--rail-fade-duration) var(--rail-motion-ease),
|
||||
transform var(--rail-fade-duration) var(--rail-motion-ease);
|
||||
}
|
||||
|
||||
.user-copy strong {
|
||||
color: #334155;
|
||||
font-size: 14px;
|
||||
font-weight: 750;
|
||||
line-height: 1.2;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
@@ -320,24 +539,17 @@ const displayCompanyName = computed(() => props.companyName || 'X-Financial')
|
||||
.user-copy span {
|
||||
color: #64748b;
|
||||
font-size: 12px;
|
||||
line-height: 1.2;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.user-summary .mdi {
|
||||
justify-self: end;
|
||||
color: #94a3b8;
|
||||
font-size: 13px;
|
||||
line-height: 1;
|
||||
transition: transform 180ms var(--ease), color 180ms var(--ease);
|
||||
}
|
||||
|
||||
.rail-user:hover .user-summary .mdi,
|
||||
.rail-user:focus-within .user-summary .mdi {
|
||||
color: #0f9f78;
|
||||
transform: translateY(-1px);
|
||||
flex: 0 0 18px;
|
||||
font-size: 18px;
|
||||
transition:
|
||||
max-width var(--rail-motion-duration) var(--rail-motion-ease),
|
||||
opacity var(--rail-fade-duration) var(--rail-motion-ease);
|
||||
}
|
||||
|
||||
.user-menu {
|
||||
@@ -349,34 +561,15 @@ const displayCompanyName = computed(() => props.companyName || 'X-Financial')
|
||||
border: 1px solid rgba(226, 232, 240, 0.96);
|
||||
border-radius: 12px;
|
||||
background: rgba(255, 255, 255, 0.98);
|
||||
box-shadow:
|
||||
0 16px 32px rgba(15, 23, 42, 0.1),
|
||||
0 2px 8px rgba(15, 23, 42, 0.04);
|
||||
box-shadow: 0 16px 32px rgba(15, 23, 42, 0.1);
|
||||
opacity: 0;
|
||||
transform: translateY(8px);
|
||||
pointer-events: none;
|
||||
transition:
|
||||
opacity 180ms var(--ease),
|
||||
transform 180ms var(--ease),
|
||||
box-shadow 180ms var(--ease);
|
||||
transition: all 180ms var(--ease);
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
.user-menu::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
right: 18px;
|
||||
bottom: -6px;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-right: 1px solid rgba(226, 232, 240, 0.96);
|
||||
border-bottom: 1px solid rgba(226, 232, 240, 0.96);
|
||||
background: rgba(255, 255, 255, 0.98);
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.rail-user:hover .user-menu,
|
||||
.rail-user:focus-within .user-menu {
|
||||
.rail-user:hover .user-menu {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
pointer-events: auto;
|
||||
@@ -385,9 +578,8 @@ const displayCompanyName = computed(() => props.companyName || 'X-Financial')
|
||||
.user-menu-item {
|
||||
width: 100%;
|
||||
height: 38px;
|
||||
display: inline-flex;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
gap: 8px;
|
||||
padding: 0 12px;
|
||||
border: 0;
|
||||
@@ -396,18 +588,138 @@ const displayCompanyName = computed(() => props.companyName || 'X-Financial')
|
||||
color: #dc2626;
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
text-align: left;
|
||||
transition: background 180ms var(--ease), color 180ms var(--ease);
|
||||
transition: all 180ms var(--ease);
|
||||
}
|
||||
|
||||
.user-menu-item:hover {
|
||||
background: #fff5f5;
|
||||
color: #b91c1c;
|
||||
/* ========================================= */
|
||||
/* COLLAPSED STATE */
|
||||
/* ========================================= */
|
||||
|
||||
.rail-collapsed .rail-brand {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
gap: 8px;
|
||||
min-height: 0;
|
||||
padding: 24px 8px 14px;
|
||||
}
|
||||
|
||||
.user-menu-item .mdi {
|
||||
font-size: 15px;
|
||||
line-height: 1;
|
||||
.rail-collapsed .brand-mark {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.rail-collapsed .brand-mark svg {
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
}
|
||||
|
||||
.rail-collapsed .brand-name {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
max-width: 0;
|
||||
margin: 0;
|
||||
opacity: 0;
|
||||
overflow: hidden;
|
||||
clip: rect(0 0 0 0);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.rail-collapsed .rail-collapse-btn {
|
||||
position: static;
|
||||
top: auto;
|
||||
right: auto;
|
||||
align-self: center;
|
||||
width: 36px;
|
||||
height: 32px;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.rail-collapsed .rail-nav {
|
||||
gap: 10px;
|
||||
padding: 12px 8px;
|
||||
}
|
||||
|
||||
.rail-collapsed .nav-btn {
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.rail-collapsed .nav-icon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
flex: 0 0 32px;
|
||||
}
|
||||
|
||||
.rail-collapsed .nav-label {
|
||||
max-width: 0;
|
||||
opacity: 0;
|
||||
transform: translateX(-6px);
|
||||
}
|
||||
|
||||
.rail-collapsed .nav-badge {
|
||||
max-width: 0;
|
||||
min-width: 0;
|
||||
padding: 0;
|
||||
opacity: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.rail-collapsed {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.rail-collapsed .rail-user {
|
||||
position: relative;
|
||||
z-index: 6;
|
||||
padding: 14px 8px;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.rail-collapsed .user-summary {
|
||||
justify-content: center;
|
||||
padding: 4px;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.rail-user-menu-floating {
|
||||
position: fixed;
|
||||
z-index: 12000;
|
||||
min-width: 132px;
|
||||
padding: 8px;
|
||||
border: 1px solid rgba(226, 232, 240, 0.96);
|
||||
border-radius: 12px;
|
||||
background: rgba(255, 255, 255, 0.98);
|
||||
box-shadow: 0 16px 32px rgba(15, 23, 42, 0.14);
|
||||
transform: translateY(-50%);
|
||||
animation: railUserMenuIn 180ms var(--rail-motion-ease) both;
|
||||
}
|
||||
|
||||
.rail-user-menu-floating .user-menu-item {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@keyframes railUserMenuIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-50%) translateX(-6px);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(-50%) translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
.rail-collapsed .user-copy,
|
||||
.rail-collapsed .user-summary .mdi {
|
||||
max-width: 0;
|
||||
opacity: 0;
|
||||
overflow: hidden;
|
||||
transform: translateX(-6px);
|
||||
}
|
||||
|
||||
@media (max-width: 980px) {
|
||||
@@ -417,30 +729,11 @@ const displayCompanyName = computed(() => props.companyName || 'X-Financial')
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 760px) {
|
||||
.rail {
|
||||
border-right: 0;
|
||||
border-bottom: 1px solid #dbe4ee;
|
||||
}
|
||||
|
||||
.rail-brand {
|
||||
min-height: 68px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.rail-nav {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
padding: 8px 16px 16px;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.nav-btn {
|
||||
min-width: 148px;
|
||||
}
|
||||
|
||||
.rail-user {
|
||||
display: none;
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.rail *,
|
||||
.rail *::before,
|
||||
.rail *::after {
|
||||
transition: none !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user