JMI-OPENATOMJMI-OPENATOM
首页
快速开始
  • 架构概览
  • 项目结构
  • 认证与权限
  • 数据库迁移
  • 配置说明
  • 开发规范
  • 架构概览
  • 项目结构
  • 路由与权限
  • API 请求
  • 组件库
  • UniApp 小程序
  • Docker 部署
  • CI/CD
  • Nginx 反向代理
  • 环境变量
  • QQ 机器人
  • 实验室管理系统
  • API 权限清单
  • 数据库表结构
  • 常见问题
首页
快速开始
  • 架构概览
  • 项目结构
  • 认证与权限
  • 数据库迁移
  • 配置说明
  • 开发规范
  • 架构概览
  • 项目结构
  • 路由与权限
  • API 请求
  • 组件库
  • UniApp 小程序
  • Docker 部署
  • CI/CD
  • Nginx 反向代理
  • 环境变量
  • QQ 机器人
  • 实验室管理系统
  • API 权限清单
  • 数据库表结构
  • 常见问题
  • 前端开发

    • 前端架构概览
    • 前端项目结构
    • 路由与权限
    • API 请求层
    • 组件库
    • UniApp 微信小程序

路由与权限

路由架构

前端使用 Vue Router 4,采用 createWebHistory 模式,路由按前台展示和管理后台两大区域组织。

路由守卫

路由守卫实现了多层次的访问控制:

// router/index.ts
router.beforeEach(async (to: RouteLocationNormalized, from: RouteLocationNormalized) => {
    startNavigation()

    // 1. 检查是否需要登录
    if (to.meta.requiresAuth !== false) {
        const token = getToken()
        if (!token) {
            // 未登录 → OIDC 重定向或跳转登录页
            if (shouldUseFullPageAuthRedirect()) {
                window.location.href = buildOidcAuthorizeUrl(to.fullPath)
                return false
            }
            return appendTokenQuery({ path: '/login', query: { redirect: to.fullPath } })
        }
    }

    // 2. 检查管理后台权限
    if (to.path.startsWith('/admin')) {
        if (!hasAdminAccess()) {
            return { path: '/', query: { msg: 'no_permission' } }
        }
    }

    // 3. 检查页面级权限
    if (to.meta.permissions) {
        if (!hasAnyPermission(to.meta.permissions)) {
            return { path: '/admin/dashboard', query: { msg: 'no_permission' } }
        }
    }

    finishNavigation()
})

前台路由

路径页面说明
/Home.vue首页
/clubsClubs.vue社团展示
/recruitmentRecruitment.vue招新信息
/application/formApplicationForm.vue报名表单
/application/:idAppDetail.vue申请详情
/application/progress/:idApplicationProgress.vue审批进度
/activitiesActivities.vue活动列表
/activities/:idActivityDetail.vue活动详情
/blogBlog.vue博客列表
/blog/:idBlogDetail.vue博客详情
/my-blogMyBlog.vue我的博客
/profileProfile.vue个人中心
/notificationsNotifications.vue通知列表
/leavesLeaves.vue请假申请
/pointsPoints.vue积分商城
/votesVotes.vue投票参与
/lottery/:idLotteryScreen.vue抽奖大屏
/check-in/scanCheckInScan.vue扫码签到
/qr/:idQrScreen.vue二维码展示
/school-calendarSchoolCalendar.vue校历查看
/regulationsRegulations.vue规章制度
/evening-studyEveningStudy.vue晚自习签到
/imagesImageHosting.vue图床服务
/open-platformOpenPlatform.vue数据开放
/site-form/:idSiteForm.vue表单填写
/alumniAlumniManagers.vue校友展示

管理后台路由

路径页面说明权限
/admin/dashboardDashboard.vue仪表盘登录
/admin/usersUsers.vue用户管理user:list
/admin/clubsClubs.vue社团管理club:list
/admin/positionsPositions.vue岗位管理position:list
/admin/membershipsMemberships.vue成员管理membership:list
/admin/recruitment-campaignsRecruitmentCampaigns.vue招新计划recruitment-campaign:list
/admin/applicationsApplications.vue入会申请application:list
/admin/interviewsInterviews.vue面试管理interview:list
/admin/activitiesActivities.vue活动管理activity:list
/admin/check-insCheckIns.vue签到管理check-in:list
/admin/leavesLeaves.vue请假管理leave-application:list
/admin/awardsAwards.vue获奖管理award:list
/admin/notificationsNotifications.vue通知管理notification:list
/admin/office-documentsOfficeDocuments.vue文书管理document:list
/admin/school-calendarSchoolCalendar.vue校历管理school-calendar:manage
/admin/regulationsRegulations.vue规章管理regulation:list
/admin/rolesRoles.vue角色管理role:list
/admin/site-formsSiteForms.vue表单管理site-form:list
/admin/form-submissionsFormSubmissions.vue表单提交site-form:list
/admin/lotteriesLotteries.vue抽奖管理lottery:list
/admin/votesVotes.vue投票管理vote:list
/admin/pointsPoints.vue积分管理point:account:list
/admin/blogsBlogs.vue博客管理blog:list
/admin/imagesImages.vue图床管理image:list
/admin/showcase-appsShowcaseApps.vue应用展示showcase-app:list
/admin/data-openDataOpen.vue数据开放data-open:list
/admin/oauth-clientsOauthClients.vueOAuth 管理oauth-client:list
/admin/bot-groupsBotGroups.vueQQ 群管理bot-management:list
/admin/alumni-groupsAlumniGroups.vue校友分组-
/admin/alumni-managersAlumniManagers.vue往届管理-
/admin/ai-activity-automationAiActivityAutomation.vueAI 活动-
/admin/logsLogs.vue日志查看log:operation:list
/admin/qr-centerQrCenter.vue二维码登录

路由懒加载

所有页面组件使用动态导入(懒加载),并实现了重试机制:

function resilientView(loader: () => Promise<any>) {
    return async () => {
        let lastError: unknown
        for (let attempt = 0; attempt <= ROUTE_LOAD_RETRIES; attempt++) {
            try {
                return await loader()
            } catch (error) {
                lastError = error
                if (!isRecoverableRouteLoadError(error) || attempt === ROUTE_LOAD_RETRIES) break
                await waitForOnline()
                await sleep(450 * 2 ** attempt)
            }
        }
        throw lastError
    }
}

// 使用示例
{ path: '/admin/users', component: resilientView(() => import('@/views/admin/Users.vue')) }

当动态导入失败(网络问题或部署路径变化)时,自动重试 2 次,并等待网络恢复。

权限工具函数

hasAdminAccess()

检查当前用户是否有管理后台访问权限(拥有任意 admin 权限或超管角色)。

hasAnyPermission(permissions)

检查当前用户是否拥有指定权限列表中的任意一个。

getToken()

获取当前存储的认证 Token。

clearSession()

清除登录会话(Token、用户信息等)。

OIDC 认证流程

用户访问受保护页面
        │
        ▼
  检查 Token ──── 无 Token ──── 重定向到 OIDC 授权页
        │                              │
     有 Token                          │
        │                              ▼
        ▼                    OAuth 授权 → 回调 AuthCallback.vue
  验证权限                                │
        │                                  │
        ▼                                  ▼
  允许访问 ← ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ 存储 Token

AuthCallback.vue 页面处理 OIDC 回调,解析授权码并交换 Token。

Prev
前端项目结构
Next
API 请求层