git commit -m feat(projects): 对接后端登录接口

This commit is contained in:
2025-11-30 11:04:30 +08:00
parent b3fb87d850
commit 65640c8b71
16 changed files with 54 additions and 44 deletions

12
.env
View File

@ -2,9 +2,9 @@
# if use a sub directory, it must be end with "/", like "/admin/" but not "/admin"
VITE_BASE_URL=/
VITE_APP_TITLE=SoybeanAdmin
VITE_APP_TITLE=Dolphin
VITE_APP_DESC=SoybeanAdmin is a fresh and elegant admin template
VITE_APP_DESC='A fresh and elegant admin management system'
# the prefix of the icon name
VITE_ICON_PREFIX=icon
@ -29,16 +29,16 @@ VITE_HTTP_PROXY=Y
VITE_ROUTER_HISTORY_MODE=history
# success code of backend service, when the code is received, the request is successful
VITE_SERVICE_SUCCESS_CODE=0000
VITE_SERVICE_SUCCESS_CODE=00000000
# logout codes of backend service, when the code is received, the user will be logged out and redirected to login page
VITE_SERVICE_LOGOUT_CODES=8888,8889
VITE_SERVICE_LOGOUT_CODES=00010001,00010002
# modal logout codes of backend service, when the code is received, the user will be logged out by displaying a modal
VITE_SERVICE_MODAL_LOGOUT_CODES=7777,7778
VITE_SERVICE_MODAL_LOGOUT_CODES=00010004
# token expired codes of backend service, when the code is received, it will refresh the token and resend the request
VITE_SERVICE_EXPIRED_TOKEN_CODES=9999,9998,3333
VITE_SERVICE_EXPIRED_TOKEN_CODES=00010003
# when the route mode is static, the defined super role
VITE_STATIC_SUPER_ROLE=R_SUPER

View File

@ -1,7 +1,7 @@
# backend service base url, test environment
VITE_SERVICE_BASE_URL=https://mock.apifox.cn/m1/3109515-0-default
VITE_SERVICE_BASE_URL=http://localhost:8080
# other backend service base url, test environment
VITE_OTHER_SERVICE_BASE_URL= `{
VITE_OTHER_SERVICE_BASE_URL=`{
"demo": "http://localhost:9528"
}`

View File

@ -73,7 +73,7 @@ function handleDropdown(key: DropdownKey) {
<div>
<ButtonIcon>
<SvgIcon icon="ph:user-circle" class="text-icon-large" />
<span class="text-16px font-medium">{{ authStore.userInfo.userName }}</span>
<span class="text-16px font-medium">{{ authStore.userInfo.username }}</span>
</ButtonIcon>
</div>
</NDropdown>

View File

@ -1,6 +1,6 @@
const local: App.I18n.Schema = {
system: {
title: 'SoybeanAdmin',
title: 'Dolphin',
updateTitle: 'System Version Update Notification',
updateContent: 'A new version of the system has been detected. Do you want to refresh the page immediately?',
updateConfirm: 'Refresh immediately',

View File

@ -1,6 +1,6 @@
const local: App.I18n.Schema = {
system: {
title: 'Soybean 管理系统',
title: 'Dolphin 管理系统',
updateTitle: '系统版本更新通知',
updateContent: '检测到系统有新版本发布,是否立即刷新页面?',
updateConfirm: '立即刷新',

View File

@ -35,7 +35,7 @@ export function createRouteGuard(router: Router) {
const needLogin = !to.meta.constant;
const routeRoles = to.meta.roles || [];
const hasRole = authStore.userInfo.roles.some(role => routeRoles.includes(role));
const hasRole = authStore.userInfo.authorities.some(role => routeRoles.includes(role));
const hasAuth = authStore.isStaticSuper || !routeRoles.length || hasRole;
// if it is login route when logged in, then switch to the root page

View File

@ -3,15 +3,15 @@ import { request } from '../request';
/**
* Login
*
* @param userName User name
* @param username User name
* @param password Password
*/
export function fetchLogin(userName: string, password: string) {
export function fetchLogin(username: string, password: string) {
return request<Api.Auth.LoginToken>({
url: '/auth/login',
method: 'post',
data: {
userName,
username,
password
}
});

View File

@ -48,7 +48,7 @@ export const request = createFlatRequest(
handleLogout();
window.removeEventListener('beforeunload', handleLogout);
request.state.errMsgStack = request.state.errMsgStack.filter(msg => msg !== response.data.msg);
request.state.errMsgStack = request.state.errMsgStack.filter(msg => msg !== response.data.message);
}
// when the backend response code is in `logoutCodes`, it means the user will be logged out and redirected to login page
@ -60,15 +60,15 @@ export const request = createFlatRequest(
// when the backend response code is in `modalLogoutCodes`, it means the user will be logged out by displaying a modal
const modalLogoutCodes = import.meta.env.VITE_SERVICE_MODAL_LOGOUT_CODES?.split(',') || [];
if (modalLogoutCodes.includes(responseCode) && !request.state.errMsgStack?.includes(response.data.msg)) {
request.state.errMsgStack = [...(request.state.errMsgStack || []), response.data.msg];
if (modalLogoutCodes.includes(responseCode) && !request.state.errMsgStack?.includes(response.data.message)) {
request.state.errMsgStack = [...(request.state.errMsgStack || []), response.data.message];
// prevent the user from refreshing the page
window.addEventListener('beforeunload', handleLogout);
window.$dialog?.error({
title: $t('common.error'),
content: response.data.msg,
content: response.data.message,
positiveText: $t('common.confirm'),
maskClosable: false,
closeOnEsc: false,
@ -106,7 +106,7 @@ export const request = createFlatRequest(
// get backend error message and code
if (error.code === BACKEND_ERROR_CODE) {
message = error.response?.data?.msg || message;
message = error.response?.data?.message || message;
backendErrorCode = String(error.response?.data?.code || '');
}

View File

@ -17,7 +17,7 @@ async function handleRefreshToken() {
const rToken = localStg.get('refreshToken') || '';
const { error, data } = await fetchRefreshToken(rToken);
if (!error) {
localStg.set('token', data.token);
localStg.set('token', data?.accessToken);
localStg.set('refreshToken', data.refreshToken);
return true;
}

View File

@ -22,9 +22,9 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
const token = ref(getToken());
const userInfo: Api.Auth.UserInfo = reactive({
userId: '',
userName: '',
roles: [],
id: '',
username: '',
authorities: [],
buttons: []
});
@ -32,7 +32,7 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
const isStaticSuper = computed(() => {
const { VITE_AUTH_ROUTE_MODE, VITE_STATIC_SUPER_ROLE } = import.meta.env;
return VITE_AUTH_ROUTE_MODE === 'static' && userInfo.roles.includes(VITE_STATIC_SUPER_ROLE);
return VITE_AUTH_ROUTE_MODE === 'static' && userInfo.authorities.includes(VITE_STATIC_SUPER_ROLE);
});
/** Is login */
@ -56,12 +56,12 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
/** Record the user ID of the previous login session Used to compare with the current user ID on next login */
function recordUserId() {
if (!userInfo.userId) {
if (!userInfo.id) {
return;
}
// Store current user ID locally for next login comparison
localStg.set('lastLoginUserId', userInfo.userId);
localStg.set('lastLoginUserId', userInfo.id);
}
/**
@ -70,14 +70,14 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
* @returns {boolean} Whether to clear all tabs
*/
function checkTabClear(): boolean {
if (!userInfo.userId) {
if (!userInfo.id) {
return false;
}
const lastLoginUserId = localStg.get('lastLoginUserId');
// Clear all tabs if current user is different from previous user
if (!lastLoginUserId || lastLoginUserId !== userInfo.userId) {
if (!lastLoginUserId || lastLoginUserId !== userInfo.id) {
localStg.remove('globalTabs');
tabStore.clearTabs();
@ -117,7 +117,7 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
window.$notification?.success({
title: $t('page.login.common.loginSuccess'),
content: $t('page.login.common.welcomeBack', { userName: userInfo.userName }),
content: $t('page.login.common.welcomeBack', { userName: userInfo.username }),
duration: 4500
});
}
@ -130,14 +130,14 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
async function loginByToken(loginToken: Api.Auth.LoginToken) {
// 1. stored in the localStorage, the later requests need it in headers
localStg.set('token', loginToken.token);
localStg.set('token', loginToken.accessToken);
localStg.set('refreshToken', loginToken.refreshToken);
// 2. get user info
const pass = await getUserInfo();
if (pass) {
token.value = loginToken.token;
token.value = loginToken.accessToken;
return true;
}

View File

@ -177,7 +177,7 @@ export const useRouteStore = defineStore(SetupStoreId.Route, () => {
/** Init auth route */
async function initAuthRoute() {
// check if user info is initialized
if (!authStore.userInfo.userId) {
if (!authStore.userInfo.id) {
await authStore.initUserInfo();
}
@ -197,7 +197,7 @@ export const useRouteStore = defineStore(SetupStoreId.Route, () => {
if (authStore.isStaticSuper) {
addAuthRoutes(staticAuthRoutes);
} else {
const filteredAuthRoutes = filterAuthRoutesByRoles(staticAuthRoutes, authStore.userInfo.roles);
const filteredAuthRoutes = filterAuthRoutesByRoles(staticAuthRoutes, authStore.userInfo.authorities);
addAuthRoutes(filteredAuthRoutes);
}

View File

@ -73,8 +73,8 @@ export const useThemeStore = defineStore(SetupStoreId.Theme, () => {
const watermarkContent = computed(() => {
const { watermark } = settings.value;
if (watermark.enableUserName && authStore.userInfo.userName) {
return authStore.userInfo.userName;
if (watermark.enableUserName && authStore.userInfo.username) {
return authStore.userInfo.username;
}
if (watermark.enableTime) {

View File

@ -6,14 +6,14 @@ declare namespace Api {
*/
namespace Auth {
interface LoginToken {
token: string;
accessToken: string;
refreshToken: string;
}
interface UserInfo {
userId: string;
userName: string;
roles: string[];
id: string;
username: string;
authorities: string[];
buttons: string[];
}
}

View File

@ -628,9 +628,11 @@ declare namespace App {
/** The backend service response code */
code: string;
/** The backend service response message */
msg: string;
message: string;
/** The backend service response data */
data: T;
/** The backend service response timestamp */
timestamp: number;
};
/** The demo backend service response data */

View File

@ -1,6 +1,6 @@
<script setup lang="ts">
import { computed, reactive } from 'vue';
import { loginModuleRecord } from '@/constants/app';
// import { loginModuleRecord } from '@/constants/app';
import { useAuthStore } from '@/store/modules/auth';
import { useRouterPush } from '@/hooks/common/router';
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
@ -20,7 +20,7 @@ interface FormModel {
}
const model: FormModel = reactive({
userName: 'Soybean',
userName: 'admin',
password: '123456'
});
@ -39,8 +39,10 @@ async function handleSubmit() {
await authStore.login(model.userName, model.password);
}
/*
type AccountKey = 'super' | 'admin' | 'user';
interface Account {
key: AccountKey;
label: string;
@ -48,6 +50,7 @@ interface Account {
password: string;
}
const accounts = computed<Account[]>(() => [
{
key: 'super',
@ -68,10 +71,13 @@ const accounts = computed<Account[]>(() => [
password: '123456'
}
]);
*/
/*
async function handleAccountLogin(account: Account) {
await authStore.login(account.userName, account.password);
}
*/
</script>
<template>
@ -97,6 +103,7 @@ async function handleAccountLogin(account: Account) {
<NButton type="primary" size="large" round block :loading="authStore.loginLoading" @click="handleSubmit">
{{ $t('common.confirm') }}
</NButton>
<!--
<div class="flex-y-center justify-between gap-12px">
<NButton class="flex-1" block @click="toggleLoginModule('code-login')">
{{ $t(loginModuleRecord['code-login']) }}
@ -111,6 +118,7 @@ async function handleAccountLogin(account: Account) {
{{ item.label }}
</NButton>
</div>
-->
</NSpace>
</NForm>
</template>

View File

@ -48,7 +48,7 @@ const statisticData = computed<StatisticData[]>(() => [
</div>
<div class="pl-12px">
<h3 class="text-18px font-semibold">
{{ $t('page.home.greeting', { userName: authStore.userInfo.userName }) }}
{{ $t('page.home.greeting', { userName: authStore.userInfo.username }) }}
</h3>
<p class="text-#999 leading-30px">{{ $t('page.home.weatherDesc') }}</p>
</div>