统一门户所有应用页面,点击跳转对应业务系统,实现业务系统免登录
//获取所有业务系统项(获取并存储到仓库)
//用于页面展示
let appSubjectVoList = ref<any>([])
appSubjectVoList.value = userStore.getAppSubjectVoList || []
//登陆后获取ticket 存储
const ticket = userStore.getTicket || ''
//当前项目编码
const PATH_URL = import.meta.env.VITE_APP_BASE_URL
//当前路由
const webclientHost = window.location.protocol + '//' + window.location.host
//token及用户信息皆为登录时获取存储到仓库
//点击业务系统图标跳转,item就是appSubjectVoList的每一项
const jumpApp = (item) => {let data = {appCode: item.appCode,appName: item.appName,parentCode: item.parentCode,securityNetworkUrl: item.securityNetworkUrl,securityNetworkUrlConnected: appAvailability.value[item.appCode], // 使用检测结果schoolNetworkUrl: item.schoolNetworkUrl,schoolNetworkUrlConnected: true,webClientHost: webclientHost,ticket: ticket,token: userStore.getToken,account: userStore.getUserInfo?.account,appType: 0,useType: item.useType}postAndRedirect(`${PATH_URL}/uil/redirect`, data)
}//由后端重定向跳转
/*** 以POST方式提交数据并处理接口重定向* 接口重定向后会在新窗口打开目标页面* @param {string} apiUrl - 后端接口地址(会重定向的接口)* @param {object} postData - 需要传递的POST参数*/
async function postAndRedirect(apiUrl, postData) {try {const response = await fetch(apiUrl, {method: 'POST',headers: {'Content-Type': 'application/json'},body: JSON.stringify(postData),redirect: 'manual'})if (response.status === 302) {const redirectUrl = response.headers.get('Location')window.open(redirectUrl, '_blank')} else {const data = await response.json()if (data.data && data.code == 200) {window.open(data.data, '_blank')}if (data.code == 401) {userStore.logout()}}} catch (error) {console.error('Error:', error)}
}
业务系统接收处理页面
- 新建 UILLogin 页面(@/views/Login/UILLogin.vue),作为接收并处理 Ticket 的转换页面
- 根据项目 Code 获取对应的 applicationId(用于菜单获取)。
- 接收统一门户跳转时传递的参数:appCode、ticket、uilBackendUrl 和 grantId,存入 uilLogindata 对象。
- 调用业务系统提供的 Token 换取接口(uilLogin),传入 uilLogindata。若接口调用成功,则执行与常规登录相同的后续流程(如获取用户信息、权限菜单等并存储);若失败,则拦截并跳转至登录页。
- 若统一门户跳转时指定了目标模块(redirect 参数),则登录成功后跳转至该模块;否则跳转至菜单首项。
<script setup lang="ts"> import { computed, reactive, ref } from 'vue' import { useRouter, useRoute } from 'vue-router' import { uilLogin } from '@/api/login' import { useAppStore } from '@/store/modules/app' import { usePermissionStore } from '@/store/modules/permission' import { useUserStore } from '@/store/modules/user' import type { RouteRecordRaw } from 'vue-router' import { userDetail, menuAccountTree } from '@/api/login' import { processMenuData } from '@/utils/tree' import { ElMessage, ElScrollbar } from 'element-plus' import { applicationInfo } from '@/api/sys/index'const { addRoute, push } = useRouter() const appStore = useAppStore() const permissionStore = usePermissionStore() const route = useRoute() const userStore = useUserStore() const redirect = ref('') let uilLogindata = reactive({appCode: '',ticket: '',uilBackendUrl: '',grantId: '' }) if (route.query?.ticket && typeof route.query.ticket === 'string') {uilLogindata.ticket = route.query.ticket } if (route.query?.appCode && typeof route.query.appCode === 'string') {uilLogindata.appCode = route.query.appCode } if (route.query?.uilBackendUrl && typeof route.query.uilBackendUrl === 'string') {uilLogindata.uilBackendUrl = route.query.uilBackendUrl } if (route.query?.redirect && typeof route.query.redirect === 'string') {redirect.value = route.query.redirect } if (route.query?.grantId && typeof route.query.grantId === 'string') {uilLogindata.grantId = route.query.grantId } //更改为项目code~~~~~~~~~~~~~~~~~~~~~~~~~ const BASE_PATH = import.meta.env.VITE_BASE_PATH // 根据需求 获取applicationId const getapplicationId = () => {applicationInfo(BASE_PATH).then((res) => {if (res.code == 200) {appStore.setSysInfo(res.data)// ticket登录~~~~~~~~~~~~~~~~~~~~~~~~if (uilLogindata.ticket) {uilLogin(uilLogindata).then(async (res) => {if (res.code == 200) {userStore.setToken(res.data.tokenValue)userStore.setTokenKey(res.data.tokenName)if (appStore.getDynamicRouter) {getUser()} else {await permissionStore.generateRoutes('static').catch(() => {})permissionStore.getAddRouters.forEach((route) => {addRoute(route as RouteRecordRaw) // 动态添加可访问路由表})permissionStore.setIsAddRouters(true)// 有指定页面跳转指定页面~~~~~~~~~~~~~~~~~~~~~~~~if (redirect.value) {push(`/${redirect.value}`)} else {push({ path: permissionStore.addRouters[0].path })}}} else {push('/login')}}).catch(() => {push('/login')})} else {// 没有ticket回到登录页push('/login')}} else {ElMessage.error('网络异常,请返回重新跳转!')}}) } getapplicationId() const application = computed(() => appStore.getSysInfo) // 获取角色信息 const getUser = async () => {const resmenu = await menuAccountTree({ applicationId: application.value.id })resmenu.data = processMenuData(resmenu.data, true, true)const res = await userDetail()res.data.menus = resmenu.data// console.log(res, 'res')if (res) {if (!res.data.menus || !res.data.menus.length) {ElMessage({type: 'error',message: '用户没有权限'})userStore.logout()return}userStore.setUserInfo(res.data)const routers: any[] = res.data.menus || []// console.log(routers, 'routers')userStore.setRoleRouters(routers)appStore.getDynamicRouter && appStore.getServerDynamicRouter? await permissionStore.generateRoutes('server', routers).catch(() => {}): await permissionStore.generateRoutes('frontEnd', routers).catch(() => {})console.log(permissionStore.getAddRouters, 'permissionStore.getAddRouters')permissionStore.getAddRouters.forEach((route) => {addRoute(route as RouteRecordRaw) // 动态添加可访问路由表})permissionStore.setIsAddRouters(true)// 有指定页面跳转指定页面~~~~~~~~~~~~~~~~~~~~~~~~if (redirect.value) {push(`/${redirect.value}`)} else {push({ path: permissionStore.addRouters[0].path })}} } </script> <template><div><ElScrollbar class="h-full"><divclass="lt-sm:p-10px dark:bg-[var(--login-bg-color)] mx-auto h-100vh flex justify-center items-center">跳转中...</div></ElScrollbar></div> </template> <style lang="less" scoped></style>
- 在路由配置(router.ts)中添加 /uil-login 页面,确保该页面可被访问。
{path: '/uil-login',component: () => import('@/views/Login/UILLogin.vue'),name: 'uilLogin',meta: {hidden: true,title: 'UIL登录',noTagsView: true}},
- 将 /uil-login 加入免重定向白名单(NO_REDIRECT_WHITE_LIST),避免在该页面触发登录重定向逻辑。
export const NO_REDIRECT_WHITE_LIST = ['/login', '/uis-login', '/uploadPage', '/uil-login']
在 @/api/login.ts 中新增 uilLogin 后端 Token 换取接口。
// uil免登录
export const uilLogin = (data): Promise<IResponse> => {return request.post({ url: `/uil/login`, data })
}