git commit -m feat(projects): 对接后端登录接口
This commit is contained in:
12
.env
12
.env
@ -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
|
||||||
|
|||||||
@ -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"
|
||||||
}`
|
}`
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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',
|
||||||
|
|||||||
@ -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: '立即刷新',
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -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 || '');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
8
src/typings/api/auth.d.ts
vendored
8
src/typings/api/auth.d.ts
vendored
@ -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[];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
4
src/typings/app.d.ts
vendored
4
src/typings/app.d.ts
vendored
@ -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 */
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user