Pre Merge pull request !768 from 熊猫大侠/dev-singlelogin

pull/768/MERGE
熊猫大侠 2025-07-25 12:30:02 +00:00 committed by Gitee
commit 9a0607a82e
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
5 changed files with 44 additions and 19 deletions

View File

@ -18,7 +18,7 @@
</el-select> </el-select>
</ElDialog> </ElDialog>
<div v-else class="custom-hover" @click.stop="showTopSearch = !showTopSearch"> <div v-else class="custom-hover" @click.stop="showTopSearch = !showTopSearch">
<Icon icon="ep:search" /> <Icon icon="ep:search" :color="color"/>
<el-select <el-select
@click.stop @click.stop
filterable filterable
@ -41,11 +41,13 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { propTypes } from '@/utils/propTypes'
defineProps({ defineProps({
isModal: { isModal: {
type: Boolean, type: Boolean,
default: true default: true
} },
color: propTypes.string.def('')
}) })
const router = useRouter() // const router = useRouter() //

View File

@ -126,19 +126,25 @@ service.interceptors.response.use(
isRefreshToken = true isRefreshToken = true
// 1. 如果获取不到刷新令牌,则只能执行登出操作 // 1. 如果获取不到刷新令牌,则只能执行登出操作
if (!getRefreshToken()) { if (!getRefreshToken()) {
return handleAuthorized() return handleAuthorized(t('sys.api.timeoutMessage'))
} }
// 2. 进行刷新访问令牌 // 2. 进行刷新访问令牌
try { try {
const refreshTokenRes = await refreshToken() const refreshTokenRes = await refreshToken()
// 2.1 刷新成功,则回放队列的请求 + 当前请求 const retData = (await refreshTokenRes).data
setToken((await refreshTokenRes).data.data) if (retData.code === 1002000499) {
config.headers!.Authorization = 'Bearer ' + getAccessToken() //登录被踢下线的处理 by panda 25.04.23
requestList.forEach((cb: any) => { return handleAuthorized(retData.msg)
cb() } else {
}) // 2.1 刷新成功,则回放队列的请求 + 当前请求
requestList = [] setToken((await refreshTokenRes).data.data)
return service(config) config.headers!.Authorization = 'Bearer ' + getAccessToken()
requestList.forEach((cb: any) => {
cb()
})
requestList = []
return service(config)
}
} catch (e) { } catch (e) {
// 为什么需要 catch 异常呢?刷新失败时,请求因为 Promise.reject 触发异常。 // 为什么需要 catch 异常呢?刷新失败时,请求因为 Promise.reject 触发异常。
// 2.2 刷新失败,只回放队列的请求 // 2.2 刷新失败,只回放队列的请求
@ -146,7 +152,7 @@ service.interceptors.response.use(
cb() cb()
}) })
// 提示是否要登出。即不回放当前请求!不然会形成递归 // 提示是否要登出。即不回放当前请求!不然会形成递归
return handleAuthorized() return handleAuthorized(t('sys.api.timeoutMessage'))
} finally { } finally {
requestList = [] requestList = []
isRefreshToken = false isRefreshToken = false
@ -181,7 +187,7 @@ service.interceptors.response.use(
if (msg === '无效的刷新令牌') { if (msg === '无效的刷新令牌') {
// hard coding忽略这个提示直接登出 // hard coding忽略这个提示直接登出
console.log(msg) console.log(msg)
return handleAuthorized() return handleAuthorized(t('sys.api.timeoutMessage'))
} else { } else {
ElNotification.error({ title: msg }) ElNotification.error({ title: msg })
} }
@ -210,7 +216,7 @@ const refreshToken = async () => {
axios.defaults.headers.common['tenant-id'] = getTenantId() axios.defaults.headers.common['tenant-id'] = getTenantId()
return await axios.post(base_url + '/system/auth/refresh-token?refreshToken=' + getRefreshToken()) return await axios.post(base_url + '/system/auth/refresh-token?refreshToken=' + getRefreshToken())
} }
const handleAuthorized = () => { const handleAuthorized = (msg: any) => {
const { t } = useI18n() const { t } = useI18n()
if (!isRelogin.show) { if (!isRelogin.show) {
// 如果已经到登录页面则不进行弹窗提示 // 如果已经到登录页面则不进行弹窗提示
@ -218,7 +224,7 @@ const handleAuthorized = () => {
return return
} }
isRelogin.show = true isRelogin.show = true
ElMessageBox.confirm(t('sys.api.timeoutMessage'), t('common.confirmTitle'), { ElMessageBox.confirm(msg, t('common.confirmTitle'), {
showCancelButton: false, showCancelButton: false,
closeOnClickModal: false, closeOnClickModal: false,
showClose: false, showClose: false,

View File

@ -2,9 +2,14 @@
import { formatDate } from '@/utils/formatTime' import { formatDate } from '@/utils/formatTime'
import * as NotifyMessageApi from '@/api/system/notify/message' import * as NotifyMessageApi from '@/api/system/notify/message'
import { useUserStoreWithOut } from '@/store/modules/user' import { useUserStoreWithOut } from '@/store/modules/user'
import { propTypes } from '@/utils/propTypes'
defineOptions({ name: 'Message' }) defineOptions({ name: 'Message' })
defineProps({
color: propTypes.string.def('')
})
const { push } = useRouter() const { push } = useRouter()
const userStore = useUserStoreWithOut() const userStore = useUserStoreWithOut()
const activeName = ref('notice') const activeName = ref('notice')
@ -54,7 +59,7 @@ onMounted(() => {
<ElPopover :width="400" placement="bottom" trigger="click"> <ElPopover :width="400" placement="bottom" trigger="click">
<template #reference> <template #reference>
<ElBadge :is-dot="unreadCount > 0" class="item"> <ElBadge :is-dot="unreadCount > 0" class="item">
<Icon :size="18" class="cursor-pointer" icon="ep:bell" @click="getList" /> <Icon :size="18" class="cursor-pointer" icon="ep:bell" :color="color" @click="getList" />
</ElBadge> </ElBadge>
</template> </template>
<ElTabs v-model="activeName"> <ElTabs v-model="activeName">

View File

@ -73,7 +73,7 @@ export default defineComponent({
{screenfull.value ? ( {screenfull.value ? (
<Screenfull class="custom-hover" color="var(--top-header-text-color)"></Screenfull> <Screenfull class="custom-hover" color="var(--top-header-text-color)"></Screenfull>
) : undefined} ) : undefined}
{search.value ? <RouterSearch isModal={false} /> : undefined} {search.value ? <RouterSearch isModal={false} color="var(--top-header-text-color)"/> : undefined}
{size.value ? ( {size.value ? (
<SizeDropdown class="custom-hover" color="var(--top-header-text-color)"></SizeDropdown> <SizeDropdown class="custom-hover" color="var(--top-header-text-color)"></SizeDropdown>
) : undefined} ) : undefined}

View File

@ -1,13 +1,25 @@
import type { App } from 'vue' import type { App } from 'vue'
import type { RouteRecordRaw } from 'vue-router' import type { RouteRecordRaw } from 'vue-router'
import { createRouter, createWebHistory } from 'vue-router' import { createRouter, createWebHistory } from 'vue-router'
import remainingRouter from './modules/remaining'
// 自动导入modules目录下的所有静态路由项目可以按模块分类增加路由文件
// by panda & inori_lover 25.03.21
const allRouters: RouteRecordRaw[] = Object.values<{ default: RouteRecordRaw[] }>(
import.meta.glob('./modules/*.ts', { eager: true })
).reduce<RouteRecordRaw[]>((acc, module) => {
// just ensure module.default is valid route define
if (Array.isArray(module?.default)) {
acc.push(...module.default)
}
return acc
}, [])
// 创建路由实例 // 创建路由实例
const router = createRouter({ const router = createRouter({
history: createWebHistory(import.meta.env.VITE_BASE_PATH), // createWebHashHistory URL带#createWebHistory URL不带# history: createWebHistory(import.meta.env.VITE_BASE_PATH), // createWebHashHistory URL带#createWebHistory URL不带#
strict: true, strict: true,
routes: remainingRouter as RouteRecordRaw[], routes: allRouters, //自动导入的所有静态路由 by panda & inori_lover 25.03.21
scrollBehavior: () => ({ left: 0, top: 0 }) scrollBehavior: () => ({ left: 0, top: 0 })
}) })