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" # if use a sub directory, it must be end with "/", like "/admin/" but not "/admin"
VITE_BASE_URL=/ 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 # the prefix of the icon name
VITE_ICON_PREFIX=icon VITE_ICON_PREFIX=icon
@ -29,16 +29,16 @@ VITE_HTTP_PROXY=Y
VITE_ROUTER_HISTORY_MODE=history VITE_ROUTER_HISTORY_MODE=history
# success code of backend service, when the code is received, the request is successful # 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 # 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 # 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 # 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 # when the route mode is static, the defined super role
VITE_STATIC_SUPER_ROLE=R_SUPER VITE_STATIC_SUPER_ROLE=R_SUPER

View File

@ -1,7 +1,7 @@
# backend service base url, test environment # 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 # other backend service base url, test environment
VITE_OTHER_SERVICE_BASE_URL= `{ VITE_OTHER_SERVICE_BASE_URL=`{
"demo": "http://localhost:9528" "demo": "http://localhost:9528"
}` }`

View File

@ -73,7 +73,7 @@ function handleDropdown(key: DropdownKey) {
<div> <div>
<ButtonIcon> <ButtonIcon>
<SvgIcon icon="ph:user-circle" class="text-icon-large" /> <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> </ButtonIcon>
</div> </div>
</NDropdown> </NDropdown>

View File

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

View File

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

View File

@ -35,7 +35,7 @@ export function createRouteGuard(router: Router) {
const needLogin = !to.meta.constant; const needLogin = !to.meta.constant;
const routeRoles = to.meta.roles || []; 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; const hasAuth = authStore.isStaticSuper || !routeRoles.length || hasRole;
// if it is login route when logged in, then switch to the root page // 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 * Login
* *
* @param userName User name * @param username User name
* @param password Password * @param password Password
*/ */
export function fetchLogin(userName: string, password: string) { export function fetchLogin(username: string, password: string) {
return request<Api.Auth.LoginToken>({ return request<Api.Auth.LoginToken>({
url: '/auth/login', url: '/auth/login',
method: 'post', method: 'post',
data: { data: {
userName, username,
password password
} }
}); });

View File

@ -48,7 +48,7 @@ export const request = createFlatRequest(
handleLogout(); handleLogout();
window.removeEventListener('beforeunload', 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 // 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 // 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(',') || []; const modalLogoutCodes = import.meta.env.VITE_SERVICE_MODAL_LOGOUT_CODES?.split(',') || [];
if (modalLogoutCodes.includes(responseCode) && !request.state.errMsgStack?.includes(response.data.msg)) { if (modalLogoutCodes.includes(responseCode) && !request.state.errMsgStack?.includes(response.data.message)) {
request.state.errMsgStack = [...(request.state.errMsgStack || []), response.data.msg]; request.state.errMsgStack = [...(request.state.errMsgStack || []), response.data.message];
// prevent the user from refreshing the page // prevent the user from refreshing the page
window.addEventListener('beforeunload', handleLogout); window.addEventListener('beforeunload', handleLogout);
window.$dialog?.error({ window.$dialog?.error({
title: $t('common.error'), title: $t('common.error'),
content: response.data.msg, content: response.data.message,
positiveText: $t('common.confirm'), positiveText: $t('common.confirm'),
maskClosable: false, maskClosable: false,
closeOnEsc: false, closeOnEsc: false,
@ -106,7 +106,7 @@ export const request = createFlatRequest(
// get backend error message and code // get backend error message and code
if (error.code === BACKEND_ERROR_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 || ''); backendErrorCode = String(error.response?.data?.code || '');
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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