Login and Welcome Page β
Overview
This chapter details the login page architecture, login process flow, Token management mechanism, and welcome page configuration after successful login in MineAdmin 3.0. It includes component structure analysis, data flow process, route guard mechanism, and custom configuration methods.
Important Note: All code examples in this document are from the actual code of the MineAdmin open-source project. The source code is located in the GitHub repository.
Login Page Architecture β
Page Component Structure β
The main login page file is located at src/modules/base/views/login/index.vue, adopting a component-based design that splits login functionality into multiple independent sub-components to improve code maintainability and reusability.
Source Code Location:
- GitHub Address: mineadmin/web/src/modules/base/views/login/index.vue
- Local Path:
src/modules/base/views/login/index.vue
Responsive Layout Design β
The login page adopts responsive design to adapt to desktop and mobile devices:
<template>
<div class="h-full min-w-[380px] w-full flex items-center justify-center overflow-hidden border-1 bg-blue-950 lg:justify-between lg:bg-white">
<!-- Desktop left decoration area -->
<div class="relative hidden h-full w-10/12 md:hidden lg:flex">
<div class="gradient-rainbow" />
<Dashed />
<Light />
<Slogan />
<OneWord />
</div>
<!-- Login form area -->
<div class="login-form-container">
<Logo />
<LoginForm />
<CopyRight />
</div>
<!-- Mobile background effects -->
<div class="min-[380px] relative left-0 top-0 z-4 h-full max-w-[1024px] w-full flex lg:hidden">
<Dashed />
<Light />
</div>
</div>
</template>2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Component Library Notes β
Component Library Considerations
The form components on the login page are not built using the Element Plus component library but are based on MineAdmin's own foundational component library. These components are specifically designed for the system with the following characteristics:
- Lightweight Design: Contains only essential login functionality, reducing dependencies
- Unified Style: Consistent with the system's overall design language
- High Customizability: Flexible adjustments based on business needs
Customization Recommendations:
- Avoid directly modifying source code to prevent issues with future version upgrades
- Recommended to replace login components via the Plugin System
- Default
loginroute components can be overridden through route configuration
Login Process and Data Handling β
Login Process Overview β
The login process adopts a modern frontend-backend separation architecture, using JWT Token for identity authentication, supporting automatic Token refresh and permission verification.
Core Data Flow β
Development Tip
If you only need to modify the login page UI without involving login logic, you can skip the detailed process description in this section and proceed directly to the Welcome Page Configuration section.
1. User Authentication β
File Location: src/store/modules/useUserStore.ts
The login() method handles the user authentication process:
// Core logic of login method
async login(loginParams: LoginParams) {
try {
// Send login request
const response = await http.post('/admin/passport/login', loginParams)
// Save authentication info to local storage
const { access_token, refresh_token, expire_at } = response.data
// Store in Pinia Store
this.token = access_token
this.refreshToken = refresh_token
this.expireAt = expire_at
// Store in browser cache
cache.set('token', access_token)
cache.set('refresh_token', refresh_token)
cache.set('expire', useDayjs().unix() + expire_at, { exp: expire_at })
return Promise.resolve(response)
} catch (error) {
return Promise.reject(error)
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2. Route Guard Interception β
After successful login, page redirection triggers the route guard, automatically fetching user information:
// Simplified route guard logic
router.beforeEach(async (to, from, next) => {
const userStore = useUserStore()
if (to.path !== '/login' && !userStore.isLogin) {
// Not logged in, redirect to login page
next('/login')
} else if (userStore.isLogin && !userStore.userInfo) {
// Logged in but user info not fetched
try {
await userStore.requestUserInfo()
next()
} catch (error) {
// Failed to fetch user info, clear login status
await userStore.logout()
next('/login')
}
} else {
next()
}
})2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
3. User Information Fetching β
File Location: src/store/modules/useUserStore.ts
The requestUserInfo() method fetches user basic data and permission information:
async requestUserInfo() {
try {
// Parallel requests for user data, menu permissions, role info
const [userInfo, menuList, roleList] = await Promise.all([
http.get('/admin/user/info'), // User basic info
http.get('/admin/menu/index'), // Menu permission data
http.get('/admin/role/index') // Role permission data
])
// Update Store state
this.userInfo = userInfo.data
this.menuList = menuList.data
this.roleList = roleList.data
// Initialize route system
const routeStore = useRouteStore()
await routeStore.initRoutes()
return Promise.resolve(userInfo)
} catch (error) {
return Promise.reject(error)
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
4. Dynamic Route Initialization β
File Location: src/store/modules/useRouteStore.ts
The initRoutes() method dynamically generates routes based on user permissions:
async initRoutes() {
const userStore = useUserStore()
const { menuList } = userStore
// Generate route configuration based on menu data
const routes = this.generateRoutes(menuList)
// Dynamically add routes
routes.forEach(route => {
router.addRoute(route)
})
// Update route state
this.isRoutesInitialized = true
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
Token Management Mechanism β
The system adopts a dual Token mechanism to ensure security and user experience:
- Access Token: Short-term validity (default 1 hour), used for API request authentication
- Refresh Token: Long-term validity (default 2 hours), used to refresh Access Token
For detailed Token refresh mechanism, refer to Request and Interceptor documentation.
Welcome Page Configuration and Route Management β
Post-Login Redirection Logic β
MineAdmin supports multiple post-login redirection strategies to ensure user experience continuity:
Redirection Rules Explanation β
Login with Redirect Parameter
/#/login?redirect=/admin/user/index1After successful login, automatically redirects to the page specified by the
redirectparameter. This typically occurs in:- User accesses a permission-required page without login
- Token expires and automatically redirects to login page
Default Login Redirection
/#/login1Without the
redirectparameter, after successful login, redirects to the system-configured default welcome page.
Welcome Page Configuration Details β
Default Configuration Structure β
Configuration File Location: src/provider/settings/index.ts
MineAdmin's actual default welcome page configuration:
// MineAdmin default welcome page configuration
welcomePage: {
name: 'welcome', // Route name
path: '/welcome', // Route path
title: 'Welcome Page', // Page title
icon: 'icon-park-outline:jewelry', // Menu icon
},2
3
4
5
6
7
Note: In MineAdmin, the welcome page component path is automatically resolved through the route system, located at src/modules/base/views/welcome/index.vue.
Configuration Item Details β
| Item | Type | Required | Default | Description |
|---|---|---|---|---|
name | string | β | 'welcome' | Route name, must be globally unique |
path | string | β | '/welcome' | Access path, supports dynamic routes |
title | string | β | 'Welcome Page' | Page title, displayed in browser tab and breadcrumb |
icon | string | β | 'icon-park-outline:jewelry' | Icon identifier for menu display |
component | Function | β | Dynamic import component | Page component, supports async loading |
Custom Welcome Page Configuration β
Best Practice
To ensure configurations are not overwritten during system upgrades, strongly recommend custom configurations in settings.config.ts rather than directly modifying the index.ts file.
Configuration Method β
Step 1: Edit src/provider/settings/settings.config.ts
Note: This file already exists in the MineAdmin project, no need to create.
import type { SystemSettings } from '#/global'
const globalConfigSettings: SystemSettings.all = {
// Custom welcome page configuration
welcomePage: {
name: 'dashboard', // Change to dashboard
path: '/dashboard', // Path changed to dashboard path
title: 'Data Overview', // Custom title
icon: 'mdi:view-dashboard-outline', // Use dashboard icon
},
// Other system configurations...
app: {
// App-related configurations
}
}
export default globalConfigSettings2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Step 2: System automatically merges configurations
During system startup, configurations in settings.config.ts are automatically deeply merged with default configurations:
// MineAdmin actual configuration merge logic
import { defaultsDeep } from 'lodash-es'
import globalConfigSettings from '@/provider/settings/settings.config.ts'
// Merge default config with user config
const systemSetting = defaultsDeep(globalConfigSettings, defaultGlobalConfigSettings)2
3
4
5
6
Advanced Configuration Examples β
1. Conditional Welcome Page β
Set different welcome pages based on user roles or permissions:
const globalConfigSettings: SystemSettings.all = {
welcomePage: {
name: 'adaptive-welcome',
path: '/adaptive-welcome',
title: 'Personalized Welcome Page',
icon: 'mdi:account-star',
// Use custom component for conditional logic
component: () => import('@/views/custom/AdaptiveWelcome.vue')
}
}2
3
4
5
6
7
8
9
10
2. Multi-language Support β
Configure multi-language welcome pages with internationalization:
const globalConfigSettings: SystemSettings.all = {
welcomePage: {
name: 'welcome',
path: '/welcome',
// Use internationalization keys
title: 'menu.welcome',
icon: 'icon-park-outline:jewelry',
}
}2
3
4
5
6
7
8
9
3. External Link Redirection β
Configure post-login redirection to external systems:
const globalConfigSettings: SystemSettings.all = {
welcomePage: {
name: 'external-system',
path: 'https://external-dashboard.com', // External link
title: 'External System',
icon: 'mdi:open-in-new',
// Set as external link type
meta: {
isExternal: true,
target: '_blank'
}
}
}2
3
4
5
6
7
8
9
10
11
12
13
Welcome Page Component Development β
Basic Component Structure β
<!-- src/views/custom/CustomWelcome.vue -->
<template>
<div class="welcome-container">
<div class="welcome-header">
<h1>{{ $t('welcome.title') }}</h1>
<p>{{ $t('welcome.subtitle') }}</p>
</div>
<div class="welcome-content">
<!-- User info card -->
<UserInfoCard :user="userInfo" />
<!-- Quick actions -->
<QuickActions :actions="quickActions" />
<!-- Data statistics -->
<DataStatistics :stats="systemStats" />
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useUserStore } from '@/store/modules/useUserStore'
import UserInfoCard from '@/components/UserInfoCard.vue'
import QuickActions from '@/components/QuickActions.vue'
import DataStatistics from '@/components/DataStatistics.vue'
const userStore = useUserStore()
const userInfo = ref(userStore.userInfo)
const systemStats = ref({})
const quickActions = ref([
{ name: 'User Management', icon: 'mdi:account-group', path: '/admin/user' },
{ name: 'Role Permissions', icon: 'mdi:shield-account', path: '/admin/role' },
{ name: 'System Settings', icon: 'mdi:cog', path: '/admin/system' },
])
// MineAdmin welcome page doesn't require dynamic data loading
// All data is static, defined directly in the component
// MineAdmin welcome page uses static data, no API calls needed
// If dynamic data is required, add corresponding API calls
// Example: useHttp().get('/admin/user/info') for actual existing APIs
</script>
<style scoped>
.welcome-container {
padding: 24px;
max-width: 1200px;
margin: 0 auto;
}
.welcome-header {
text-align: center;
margin-bottom: 32px;
}
.welcome-content {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 24px;
}
</style>2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
Security Considerations and Best Practices β
Authentication Security β
Token Secure Storage
- Access Token stored in memory to prevent XSS attacks
- Refresh Token stored in HttpOnly Cookie
- Sensitive information not stored in localStorage
Route Permission Verification
typescript// Permission check in route guard router.beforeEach(async (to, from, next) => { const userStore = useUserStore() // Check if route requires authentication if (to.meta.requiresAuth && !userStore.isLogin) { next(`/login?redirect=${to.fullPath}`) return } // Check user permissions if (to.meta.permissions && !userStore.hasPermissions(to.meta.permissions)) { next('/403') // Insufficient permissions page return } next() })1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Performance Optimization β
Component Lazy Loading
MineAdmin uses modular route loading, components are automatically lazy-loaded:
typescript// Dynamic component loading in MineAdmin const moduleViews = import.meta.glob('../../modules/**/views/**/**.{vue,jsx,tsx}') const pluginViews = import.meta.glob('../../plugins/*/**/views/**/**.{vue,jsx,tsx}') // Automatically resolve component paths if (moduleViews[`../../modules/${item.component}${suffix}`]) { component = moduleViews[`../../modules/${item.component}${suffix}`] }1
2
3
4
5
6
7
8Data Preloading
MineAdmin handles user info loading in route guard:
typescript// MineAdmin data preloading mechanism router.beforeEach(async (to, from, next) => { if (userStore.isLogin) { if (userStore.getUserInfo() === null) { // Preload user info, menu, and permission data await userStore.requestUserInfo() next({ path: to.fullPath, query: to.query }) } else { next() } } })1
2
3
4
5
6
7
8
9
10
11
12
13
Common Issues and Solutions β
Q: Page doesn't redirect after successful login? β
**Possible