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

@@ -1,166 +1,166 @@
-- ================================================================
-- 证书系统数据库迁移脚本
-- 创建日期: 2026-01-29
-- 功能: 添加证书模板表和用户证书表
-- ================================================================
-- 事务开始
START TRANSACTION;
-- ================================================================
-- 1. 创建证书模板表
-- ================================================================
CREATE TABLE IF NOT EXISTS certificate_templates (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL COMMENT '模板名称',
type ENUM('course', 'exam', 'achievement') NOT NULL COMMENT '证书类型: course=课程结业, exam=考试合格, achievement=成就证书',
background_url VARCHAR(500) COMMENT '证书背景图URL',
template_html TEXT COMMENT 'HTML模板内容',
template_style TEXT COMMENT 'CSS样式',
is_active BOOLEAN DEFAULT TRUE COMMENT '是否启用',
sort_order INT DEFAULT 0 COMMENT '排序顺序',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_type (type),
INDEX idx_is_active (is_active)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='证书模板表';
-- ================================================================
-- 2. 创建用户证书表
-- ================================================================
CREATE TABLE IF NOT EXISTS user_certificates (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL COMMENT '用户ID',
template_id INT NOT NULL COMMENT '模板ID',
certificate_no VARCHAR(50) UNIQUE NOT NULL COMMENT '证书编号 KPL-年份-序号',
title VARCHAR(200) NOT NULL COMMENT '证书标题',
description TEXT COMMENT '证书描述/成就说明',
issued_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '颁发时间',
valid_until DATETIME COMMENT '有效期至NULL表示永久',
-- 关联信息
course_id INT COMMENT '关联课程ID',
exam_id INT COMMENT '关联考试ID',
badge_id INT COMMENT '关联奖章ID',
-- 成绩信息
score DECIMAL(5,2) COMMENT '考试分数',
completion_rate DECIMAL(5,2) COMMENT '完成率',
-- 生成的文件
pdf_url VARCHAR(500) COMMENT 'PDF文件URL',
image_url VARCHAR(500) COMMENT '分享图片URL',
-- 元数据
meta_data JSON COMMENT '扩展元数据',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (template_id) REFERENCES certificate_templates(id),
INDEX idx_user_id (user_id),
INDEX idx_certificate_no (certificate_no),
INDEX idx_course_id (course_id),
INDEX idx_exam_id (exam_id),
INDEX idx_issued_at (issued_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户证书表';
-- ================================================================
-- 3. 插入默认证书模板
-- ================================================================
INSERT INTO certificate_templates (name, type, template_html, template_style, is_active, sort_order) VALUES
-- 课程结业证书模板
('课程结业证书', 'course',
'<div class="certificate">
<div class="header">
<div class="logo">考培练系统</div>
<h1>结业证书</h1>
</div>
<div class="body">
<p class="recipient">兹证明 <strong>{{user_name}}</strong></p>
<p class="content">已完成课程《{{course_name}}》的全部学习内容</p>
<p class="completion">完成率:{{completion_rate}}%</p>
<p class="date">颁发日期:{{issue_date}}</p>
</div>
<div class="footer">
<div class="cert-no">证书编号:{{certificate_no}}</div>
<div class="qrcode">{{qrcode}}</div>
</div>
</div>',
'.certificate { width: 800px; height: 600px; padding: 40px; background: linear-gradient(135deg, #f5f7fa 0%, #e4e9f2 100%); font-family: "Microsoft YaHei", sans-serif; }
.header { text-align: center; margin-bottom: 30px; }
.header .logo { font-size: 24px; color: #667eea; font-weight: bold; }
.header h1 { font-size: 36px; color: #333; margin: 20px 0; }
.body { text-align: center; padding: 30px 60px; }
.body .recipient { font-size: 20px; margin-bottom: 20px; }
.body .content { font-size: 18px; color: #555; margin-bottom: 15px; }
.body .completion { font-size: 16px; color: #667eea; }
.body .date { font-size: 14px; color: #888; margin-top: 30px; }
.footer { display: flex; justify-content: space-between; align-items: center; margin-top: 40px; }
.cert-no { font-size: 12px; color: #999; }
.qrcode { width: 80px; height: 80px; }',
TRUE, 1),
-- 考试合格证书模板
('考试合格证书', 'exam',
'<div class="certificate exam-cert">
<div class="header">
<div class="logo">考培练系统</div>
<h1>考试合格证书</h1>
</div>
<div class="body">
<p class="recipient">兹证明 <strong>{{user_name}}</strong></p>
<p class="content">在《{{exam_name}}》考试中成绩合格</p>
<div class="score-badge">
<span class="score">{{score}}</span>
<span class="unit">分</span>
</div>
<p class="date">考试日期:{{exam_date}}</p>
</div>
<div class="footer">
<div class="cert-no">证书编号:{{certificate_no}}</div>
<div class="qrcode">{{qrcode}}</div>
</div>
</div>',
'.certificate.exam-cert { width: 800px; height: 600px; padding: 40px; background: linear-gradient(135deg, #e8f5e9 0%, #c8e6c9 100%); font-family: "Microsoft YaHei", sans-serif; }
.exam-cert .header h1 { color: #2e7d32; }
.score-badge { display: inline-block; padding: 20px 40px; background: #fff; border-radius: 50%; box-shadow: 0 4px 20px rgba(0,0,0,0.1); margin: 20px 0; }
.score-badge .score { font-size: 48px; font-weight: bold; color: #2e7d32; }
.score-badge .unit { font-size: 18px; color: #666; }',
TRUE, 2),
-- 成就证书模板
('成就证书', 'achievement',
'<div class="certificate achievement-cert">
<div class="header">
<div class="logo">考培练系统</div>
<h1>成就证书</h1>
</div>
<div class="body">
<p class="recipient">兹证明 <strong>{{user_name}}</strong></p>
<div class="achievement-icon">{{badge_icon}}</div>
<p class="achievement-name">{{badge_name}}</p>
<p class="achievement-desc">{{badge_description}}</p>
<p class="date">获得日期:{{achieve_date}}</p>
</div>
<div class="footer">
<div class="cert-no">证书编号:{{certificate_no}}</div>
<div class="qrcode">{{qrcode}}</div>
</div>
</div>',
'.certificate.achievement-cert { width: 800px; height: 600px; padding: 40px; background: linear-gradient(135deg, #fff3e0 0%, #ffe0b2 100%); font-family: "Microsoft YaHei", sans-serif; }
.achievement-cert .header h1 { color: #e65100; }
.achievement-icon { font-size: 64px; margin: 20px 0; }
.achievement-name { font-size: 24px; font-weight: bold; color: #e65100; margin: 10px 0; }
.achievement-desc { font-size: 16px; color: #666; }',
TRUE, 3);
-- 提交事务
COMMIT;
-- ================================================================
-- 验证脚本
-- ================================================================
-- SELECT * FROM certificate_templates;
-- SELECT COUNT(*) AS template_count FROM certificate_templates;
-- ================================================================
-- 证书系统数据库迁移脚本
-- 创建日期: 2026-01-29
-- 功能: 添加证书模板表和用户证书表
-- ================================================================
-- 事务开始
START TRANSACTION;
-- ================================================================
-- 1. 创建证书模板表
-- ================================================================
CREATE TABLE IF NOT EXISTS certificate_templates (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL COMMENT '模板名称',
type ENUM('course', 'exam', 'achievement') NOT NULL COMMENT '证书类型: course=课程结业, exam=考试合格, achievement=成就证书',
background_url VARCHAR(500) COMMENT '证书背景图URL',
template_html TEXT COMMENT 'HTML模板内容',
template_style TEXT COMMENT 'CSS样式',
is_active BOOLEAN DEFAULT TRUE COMMENT '是否启用',
sort_order INT DEFAULT 0 COMMENT '排序顺序',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_type (type),
INDEX idx_is_active (is_active)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='证书模板表';
-- ================================================================
-- 2. 创建用户证书表
-- ================================================================
CREATE TABLE IF NOT EXISTS user_certificates (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL COMMENT '用户ID',
template_id INT NOT NULL COMMENT '模板ID',
certificate_no VARCHAR(50) UNIQUE NOT NULL COMMENT '证书编号 KPL-年份-序号',
title VARCHAR(200) NOT NULL COMMENT '证书标题',
description TEXT COMMENT '证书描述/成就说明',
issued_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '颁发时间',
valid_until DATETIME COMMENT '有效期至NULL表示永久',
-- 关联信息
course_id INT COMMENT '关联课程ID',
exam_id INT COMMENT '关联考试ID',
badge_id INT COMMENT '关联奖章ID',
-- 成绩信息
score DECIMAL(5,2) COMMENT '考试分数',
completion_rate DECIMAL(5,2) COMMENT '完成率',
-- 生成的文件
pdf_url VARCHAR(500) COMMENT 'PDF文件URL',
image_url VARCHAR(500) COMMENT '分享图片URL',
-- 元数据
meta_data JSON COMMENT '扩展元数据',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (template_id) REFERENCES certificate_templates(id),
INDEX idx_user_id (user_id),
INDEX idx_certificate_no (certificate_no),
INDEX idx_course_id (course_id),
INDEX idx_exam_id (exam_id),
INDEX idx_issued_at (issued_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户证书表';
-- ================================================================
-- 3. 插入默认证书模板
-- ================================================================
INSERT INTO certificate_templates (name, type, template_html, template_style, is_active, sort_order) VALUES
-- 课程结业证书模板
('课程结业证书', 'course',
'<div class="certificate">
<div class="header">
<div class="logo">考培练系统</div>
<h1>结业证书</h1>
</div>
<div class="body">
<p class="recipient">兹证明 <strong>{{user_name}}</strong></p>
<p class="content">已完成课程《{{course_name}}》的全部学习内容</p>
<p class="completion">完成率:{{completion_rate}}%</p>
<p class="date">颁发日期:{{issue_date}}</p>
</div>
<div class="footer">
<div class="cert-no">证书编号:{{certificate_no}}</div>
<div class="qrcode">{{qrcode}}</div>
</div>
</div>',
'.certificate { width: 800px; height: 600px; padding: 40px; background: linear-gradient(135deg, #f5f7fa 0%, #e4e9f2 100%); font-family: "Microsoft YaHei", sans-serif; }
.header { text-align: center; margin-bottom: 30px; }
.header .logo { font-size: 24px; color: #667eea; font-weight: bold; }
.header h1 { font-size: 36px; color: #333; margin: 20px 0; }
.body { text-align: center; padding: 30px 60px; }
.body .recipient { font-size: 20px; margin-bottom: 20px; }
.body .content { font-size: 18px; color: #555; margin-bottom: 15px; }
.body .completion { font-size: 16px; color: #667eea; }
.body .date { font-size: 14px; color: #888; margin-top: 30px; }
.footer { display: flex; justify-content: space-between; align-items: center; margin-top: 40px; }
.cert-no { font-size: 12px; color: #999; }
.qrcode { width: 80px; height: 80px; }',
TRUE, 1),
-- 考试合格证书模板
('考试合格证书', 'exam',
'<div class="certificate exam-cert">
<div class="header">
<div class="logo">考培练系统</div>
<h1>考试合格证书</h1>
</div>
<div class="body">
<p class="recipient">兹证明 <strong>{{user_name}}</strong></p>
<p class="content">在《{{exam_name}}》考试中成绩合格</p>
<div class="score-badge">
<span class="score">{{score}}</span>
<span class="unit">分</span>
</div>
<p class="date">考试日期:{{exam_date}}</p>
</div>
<div class="footer">
<div class="cert-no">证书编号:{{certificate_no}}</div>
<div class="qrcode">{{qrcode}}</div>
</div>
</div>',
'.certificate.exam-cert { width: 800px; height: 600px; padding: 40px; background: linear-gradient(135deg, #e8f5e9 0%, #c8e6c9 100%); font-family: "Microsoft YaHei", sans-serif; }
.exam-cert .header h1 { color: #2e7d32; }
.score-badge { display: inline-block; padding: 20px 40px; background: #fff; border-radius: 50%; box-shadow: 0 4px 20px rgba(0,0,0,0.1); margin: 20px 0; }
.score-badge .score { font-size: 48px; font-weight: bold; color: #2e7d32; }
.score-badge .unit { font-size: 18px; color: #666; }',
TRUE, 2),
-- 成就证书模板
('成就证书', 'achievement',
'<div class="certificate achievement-cert">
<div class="header">
<div class="logo">考培练系统</div>
<h1>成就证书</h1>
</div>
<div class="body">
<p class="recipient">兹证明 <strong>{{user_name}}</strong></p>
<div class="achievement-icon">{{badge_icon}}</div>
<p class="achievement-name">{{badge_name}}</p>
<p class="achievement-desc">{{badge_description}}</p>
<p class="date">获得日期:{{achieve_date}}</p>
</div>
<div class="footer">
<div class="cert-no">证书编号:{{certificate_no}}</div>
<div class="qrcode">{{qrcode}}</div>
</div>
</div>',
'.certificate.achievement-cert { width: 800px; height: 600px; padding: 40px; background: linear-gradient(135deg, #fff3e0 0%, #ffe0b2 100%); font-family: "Microsoft YaHei", sans-serif; }
.achievement-cert .header h1 { color: #e65100; }
.achievement-icon { font-size: 64px; margin: 20px 0; }
.achievement-name { font-size: 24px; font-weight: bold; color: #e65100; margin: 10px 0; }
.achievement-desc { font-size: 16px; color: #666; }',
TRUE, 3);
-- 提交事务
COMMIT;
-- ================================================================
-- 验证脚本
-- ================================================================
-- SELECT * FROM certificate_templates;
-- SELECT COUNT(*) AS template_count FROM certificate_templates;