feat: 实现 KPL 系统功能改进计划
Some checks failed
continuous-integration/drone/push Build is failing

1. 课程学习进度追踪
   - 新增 UserCourseProgress 和 UserMaterialProgress 模型
   - 新增 /api/v1/progress/* 进度追踪 API
   - 更新 admin.py 使用真实课程完成率数据

2. 路由权限检查完善
   - 新增前端 permissionChecker.ts 权限检查工具
   - 更新 router/guard.ts 实现团队和课程权限验证
   - 新增后端 permission_service.py

3. AI 陪练音频转文本
   - 新增 speech_recognition.py 语音识别服务
   - 新增 /api/v1/speech/* API
   - 更新 ai-practice-coze.vue 支持语音输入

4. 双人对练报告生成
   - 更新 practice_room_service.py 添加报告生成功能
   - 新增 /rooms/{room_code}/report API
   - 更新 duo-practice-report.vue 调用真实 API

5. 学习提醒推送
   - 新增 notification_service.py 通知服务
   - 新增 scheduler_service.py 定时任务服务
   - 支持钉钉、企微、站内消息推送

6. 智能学习推荐
   - 新增 recommendation_service.py 推荐服务
   - 新增 /api/v1/recommendations/* API
   - 支持错题、能力、进度、热门多维度推荐

7. 安全问题修复
   - DEBUG 默认值改为 False
   - 添加 SECRET_KEY 安全警告
   - 新增 check_security_settings() 检查函数

8. 证书 PDF 生成
   - 更新 certificate_service.py 添加 PDF 生成
   - 添加 weasyprint、Pillow、qrcode 依赖
   - 更新下载 API 支持 PDF 和 PNG 格式
This commit is contained in:
yuliang_guo
2026-01-30 14:22:35 +08:00
parent 9793013a56
commit 64f5d567fa
66 changed files with 18067 additions and 14330 deletions

View File

@@ -7,6 +7,7 @@ import { Router, RouteLocationNormalized, NavigationGuardNext } from 'vue-router
import { ElMessage } from 'element-plus'
import { authManager } from '@/utils/auth'
import { loadingManager } from '@/utils/loadingManager'
import { checkTeamMembership, checkCourseAccess, clearPermissionCache } from '@/utils/permissionChecker'
// 白名单路由(不需要登录)
const WHITE_LIST = ['/login', '/register', '/404']
@@ -109,13 +110,21 @@ async function handleRouteGuard(
return
}
// 检查特殊路由规则
// 检查特殊路由规则(先进行同步检查)
if (!checkSpecialRouteRules(to)) {
ElMessage.error('访问被拒绝')
next(authManager.getDefaultRoute())
return
}
// 异步权限检查(团队和课程权限)
const hasSpecialAccess = await checkSpecialRouteRulesAsync(to)
if (!hasSpecialAccess) {
ElMessage.error('您没有访问此资源的权限')
next(authManager.getDefaultRoute())
return
}
next()
}
@@ -142,9 +151,9 @@ function checkRoutePermission(path: string): boolean {
}
/**
* 检查特殊路由规则
* 检查特殊路由规则(异步版本)
*/
function checkSpecialRouteRules(to: RouteLocationNormalized): boolean {
async function checkSpecialRouteRulesAsync(to: RouteLocationNormalized): Promise<boolean> {
const { path, params } = to
// 检查用户ID参数权限只能访问自己的数据管理员除外
@@ -157,14 +166,41 @@ function checkSpecialRouteRules(to: RouteLocationNormalized): boolean {
// 检查团队ID参数权限
if (params.teamId && !authManager.isAdmin()) {
// 这里可以添加团队权限检查逻辑
// 暂时允许通过,实际项目中需要检查用户是否属于该团队
const teamId = Number(params.teamId)
if (!isNaN(teamId)) {
const isMember = await checkTeamMembership(teamId)
if (!isMember) {
return false
}
}
}
// 检查课程访问权限
if (path.includes('/course/') && params.courseId) {
// 这里可以添加课程访问权限检查
// 例如检查课程是否分配给用户的岗位
const courseId = Number(params.courseId)
if (!isNaN(courseId)) {
const hasAccess = await checkCourseAccess(courseId)
if (!hasAccess) {
return false
}
}
}
return true
}
/**
* 检查特殊路由规则(同步版本,用于简单检查)
*/
function checkSpecialRouteRules(to: RouteLocationNormalized): boolean {
const { params } = to
// 检查用户ID参数权限只能访问自己的数据管理员除外
if (params.userId && !authManager.isAdmin()) {
const currentUser = authManager.getCurrentUser()
if (currentUser && String(params.userId) !== String(currentUser.id)) {
return false
}
}
return true