243 lines
5.2 KiB
Vue
243 lines
5.2 KiB
Vue
<script setup lang="ts">
|
||
import { onMounted, computed, ref } from 'vue'
|
||
import { RouterView, useRoute } from 'vue-router'
|
||
import { useUserStore } from '@/stores/user'
|
||
import AppLayout from '@/components/layout/AppLayout.vue'
|
||
import { NConfigProvider, NMessageProvider, NDialogProvider, zhCN, dateZhCN, enUS, dateEnUS } from 'naive-ui'
|
||
import type { GlobalThemeOverrides } from 'naive-ui';
|
||
import { useI18n } from 'vue-i18n'
|
||
const { locale } = useI18n()
|
||
|
||
// 响应式获取naive-ui语言包
|
||
const naiveLocale = computed(() => locale.value === 'en' ? enUS : zhCN)
|
||
const naiveDateLocale = computed(() => locale.value === 'en' ? dateEnUS : dateZhCN)
|
||
|
||
|
||
// 自定义naive-ui主题颜色
|
||
const themeOverrides: GlobalThemeOverrides = {
|
||
common: {
|
||
primaryColor: '#0288D1',
|
||
primaryColorHover: '#0277BD', // A slightly darker shade for hover
|
||
primaryColorPressed: '#01579B', // A darker shade for pressed
|
||
errorColor: '#FF4D4F',
|
||
errorColorHover: '#E54547',
|
||
errorColorPressed: '#C0383A',
|
||
},
|
||
Button: {
|
||
// For ghost primary buttons
|
||
textColorGhostPrimary: '#0288D1',
|
||
borderPrimary: '1px solid #0288D1',
|
||
// For ghost error buttons
|
||
textColorGhostError: '#FF4D4F',
|
||
borderError: '1px solid #FF4D4F',
|
||
},
|
||
Tag: {
|
||
colorPrimary: '#0288D1',
|
||
colorPrimaryHover: '#0277BD',
|
||
colorPrimaryPressed: '#01579B',
|
||
textColorPrimary: '#ffffff',
|
||
},
|
||
Card: {
|
||
borderColor: '#E6E6E6',
|
||
},
|
||
Input: {
|
||
borderHover: '#0288D1',
|
||
borderFocus: '#0288D1',
|
||
boxShadowFocus: '0 0 0 1px rgba(2, 136, 209, 0.5)',
|
||
},
|
||
InputNumber: {
|
||
borderHover: '#0288D1',
|
||
borderFocus: '#0288D1',
|
||
boxShadowFocus: '0 0 0 1px rgba(2, 136, 209, 0.5)',
|
||
},
|
||
Select: {
|
||
borderHover: '#0288D1',
|
||
borderFocus: '#0288D1',
|
||
boxShadowFocus: '0 0 0 1px rgba(2, 136, 209, 0.5)',
|
||
},
|
||
Modal: {
|
||
borderRadius: '8px',
|
||
},
|
||
Dialog: {
|
||
borderRadius: '8px',
|
||
}
|
||
};
|
||
|
||
const userStore = useUserStore()
|
||
const route = useRoute()
|
||
const isInitializing = ref(true)
|
||
|
||
// 检查是否为登录页面
|
||
const isLoginPage = computed(() => route.name === 'Login')
|
||
|
||
onMounted(async () => {
|
||
try {
|
||
// 初始化用户认证状态
|
||
await userStore.initializeAuth()
|
||
} finally {
|
||
// 无论初始化成功与否,都显示页面
|
||
isInitializing.value = false
|
||
}
|
||
})
|
||
</script>
|
||
|
||
<template>
|
||
<div id="app">
|
||
<!-- 加载状态 -->
|
||
<div v-if="isInitializing" class="loading-container">
|
||
<div class="loading-spinner"></div>
|
||
<p>正在加载...</p>
|
||
</div>
|
||
|
||
<!-- 主要内容 -->
|
||
<n-config-provider v-else :theme-overrides="themeOverrides" :locale="naiveLocale" :date-locale="naiveDateLocale">
|
||
<n-dialog-provider>
|
||
<!-- 登录页面不使用 AppLayout,但需要 message provider -->
|
||
<template v-if="isLoginPage">
|
||
<n-message-provider>
|
||
<RouterView />
|
||
</n-message-provider>
|
||
</template>
|
||
<!-- 其他页面使用 AppLayout -->
|
||
<template v-else>
|
||
<AppLayout>
|
||
<RouterView />
|
||
</AppLayout>
|
||
</template>
|
||
</n-dialog-provider>
|
||
</n-config-provider>
|
||
</div>
|
||
</template>
|
||
|
||
<style>
|
||
* {
|
||
margin: 0;
|
||
padding: 0;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
/* 确保在所有缩放级别下都能正常显示 */
|
||
html {
|
||
-webkit-text-size-adjust: 100%;
|
||
-ms-text-size-adjust: 100%;
|
||
text-size-adjust: 100%;
|
||
zoom: 1;
|
||
}
|
||
|
||
/* 移除全屏相关样式,使用正常布局 */
|
||
|
||
html,
|
||
body {
|
||
height: 100vh;
|
||
width: 100vw;
|
||
margin: 0;
|
||
padding: 0;
|
||
overflow-x: hidden;
|
||
}
|
||
|
||
body {
|
||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||
line-height: 1.6;
|
||
color: #333;
|
||
background-color: #f5f5f5;
|
||
}
|
||
|
||
#app {
|
||
min-height: 100vh;
|
||
width: 100vw;
|
||
display: block;
|
||
position: relative;
|
||
}
|
||
|
||
/* 确保导航栏和横幅可见 */
|
||
.header {
|
||
display: flex !important;
|
||
visibility: visible !important;
|
||
opacity: 1 !important;
|
||
position: relative !important;
|
||
z-index: 1000 !important;
|
||
}
|
||
|
||
.hero-banner {
|
||
display: flex !important;
|
||
visibility: visible !important;
|
||
opacity: 1 !important;
|
||
position: relative !important;
|
||
z-index: 1 !important;
|
||
}
|
||
|
||
/* 响应式容器 */
|
||
.container {
|
||
width: 100%;
|
||
margin: 0 auto;
|
||
}
|
||
|
||
|
||
/* 工具类 */
|
||
.text-center {
|
||
text-align: center;
|
||
}
|
||
|
||
.mb-4 {
|
||
margin-bottom: 1rem;
|
||
}
|
||
|
||
.mt-4 {
|
||
margin-top: 1rem;
|
||
}
|
||
|
||
.p-4 {
|
||
padding: 1rem;
|
||
}
|
||
|
||
/* 响应式显示工具类 */
|
||
.d-none {
|
||
display: none !important;
|
||
}
|
||
|
||
.d-block {
|
||
display: block !important;
|
||
}
|
||
|
||
/* 加载状态样式 */
|
||
.loading-container {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100vw;
|
||
height: 100vh;
|
||
background: #f5f5f5;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
z-index: 9999;
|
||
}
|
||
|
||
.loading-spinner {
|
||
width: 40px;
|
||
height: 40px;
|
||
border: 4px solid #e3e3e3;
|
||
border-top: 4px solid #0288D1;
|
||
border-radius: 50%;
|
||
animation: spin 1s linear infinite;
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
@keyframes spin {
|
||
0% {
|
||
transform: rotate(0deg);
|
||
}
|
||
|
||
100% {
|
||
transform: rotate(360deg);
|
||
}
|
||
}
|
||
|
||
.loading-container p {
|
||
color: #666;
|
||
font-size: 14px;
|
||
margin: 0;
|
||
}
|
||
</style>
|