weizong song 3 months ago
parent d42da8724f
commit a99b3ede0f

1
.gitignore vendored

@ -13,3 +13,4 @@ npm-debug.log
yarn-error.log
/.idea
/.vscode
/.snapshots

@ -0,0 +1,58 @@
<?php
namespace App\Console\Commands;
use App\Services\TestData\CourseContentEvaluationTestDataGenerator;
use Illuminate\Console\Command;
class SeedCourseContentEvaluations extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'seed:course-evaluations
{--evaluations=20 : 生成评价问卷数量}
{--users=50 : 最少用户数量}';
/**
* The console command description.
*
* @var string
*/
protected $description = '生成课程内容评价模块的测试数据,包括问卷、问题字段和用户提交数据';
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$evaluationCount = (int) $this->option('evaluations');
$minUsers = (int) $this->option('users');
$this->info("开始生成课程内容评价测试数据...");
$this->info("计划生成 {$evaluationCount} 个评价问卷,确保至少 {$minUsers} 个用户");
$generator = new CourseContentEvaluationTestDataGenerator();
$startTime = microtime(true);
try {
$generator->generate($evaluationCount, $minUsers, function (string $message) {
$this->line(" → {$message}");
});
$duration = round(microtime(true) - $startTime, 2);
$this->info("✅ 数据生成完成!耗时 {$duration} 秒");
return Command::SUCCESS;
} catch (\Exception $e) {
$this->error("❌ 数据生成失败:" . $e->getMessage());
return Command::FAILURE;
}
}
}

@ -94,6 +94,11 @@ class Course extends SoftDeletesModel
return $this->hasOne(Upload::class, 'id', 'qun_image_id');
}
public function courseContents()
{
return $this->hasMany(CourseContent::class, 'course_id', 'id');
}
/**
* 更新课程报名状态
*/

@ -0,0 +1,405 @@
<?php
namespace App\Services\TestData;
use App\Models\Course;
use App\Models\CourseContent;
use App\Models\CourseContentEvaluation;
use App\Models\CourseContentEvaluationAsk;
use App\Models\CourseContentEvaluationForm;
use App\Models\User;
use Faker\Factory as FakerFactory;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
/**
* 课程内容评价模块测试数据生成器
*/
class CourseContentEvaluationTestDataGenerator
{
/**
* 生成课程内容评价相关的全量测试数据
*
* @param int $evaluationCount 生成评价问卷数量
* @param int $minUsers 最少用户数量,不足会自动补充
* @param callable|null $logger 可选日志输出函数 function(string $message): void
*/
public function generate(int $evaluationCount = 20, int $minUsers = 50, ?callable $logger = null): void
{
$log = $logger ?? static function (string $message): void {
// no-op
};
$faker = FakerFactory::create('zh_CN');
DB::transaction(function () use ($evaluationCount, $minUsers, $faker, $log) {
// 1) 确保用户数量
$currentUserCount = User::count();
if ($currentUserCount < $minUsers) {
$need = $minUsers - $currentUserCount;
$log("创建用户: {$need} 个");
User::factory($need)->create();
}
$allUsers = User::all();
if ($allUsers->count() < 5) {
throw new \RuntimeException('生成评价数据至少需要5个用户');
}
// 2) 确保课程和课程内容存在
$courses = Course::with('courseContents')->get();
if ($courses->isEmpty()) {
$log("创建示例课程数据");
$this->createSampleCoursesAndContents($faker);
$courses = Course::with('courseContents')->get();
}
$allCourseContents = CourseContent::all();
if ($allCourseContents->isEmpty()) {
throw new \RuntimeException('无课程内容数据,无法生成评价');
}
// 3) 生成评价问卷主数据
for ($i = 0; $i < $evaluationCount; $i++) {
$courseContent = $allCourseContents->random();
$course = $courses->where('id', $courseContent->course_id)->first();
if (!$course) {
// 如果找不到课程,跳过这个课程内容
continue;
}
$evaluation = $this->createEvaluation($courseContent, $course, $faker);
// 4) 为每个问卷生成问题字段
$askCount = $faker->numberBetween(5, 15);
$asks = $this->createEvaluationAsks($evaluation, $courseContent, $course, $askCount, $faker);
// 5) 生成用户提交的表单数据
$formCount = $faker->numberBetween(10, min(40, $allUsers->count()));
$submittedUsers = $allUsers->random($formCount);
foreach ($submittedUsers as $user) {
$this->createEvaluationForm($evaluation, $user, $asks, $faker);
}
$log(sprintf('评价问卷#%d "%s" 已生成:%d个问题字段%d份用户提交',
$evaluation->id,
$evaluation->title,
$askCount,
$formCount
));
}
});
}
/**
* 创建评价问卷主数据
*/
private function createEvaluation(CourseContent $courseContent, Course $course, $faker): CourseContentEvaluation
{
$evaluation = new CourseContentEvaluation();
$evaluation->course_id = $course->id;
$evaluation->course_content_id = $courseContent->id;
$evaluation->title = $this->generateEvaluationTitle($course, $courseContent, $faker);
$evaluation->desc = $this->generateEvaluationDesc($faker);
$evaluation->type_id = $faker->numberBetween(1, 5); // 问卷类型ID
// 时间设置:开始时间在课程内容时间前后,截止时间在开始时间之后
$startTime = $faker->dateTimeBetween('-30 days', '+7 days');
$endTime = $faker->dateTimeBetween($startTime, $startTime->format('Y-m-d H:i:s') . ' +30 days');
$evaluation->start_time = $startTime->format('Y-m-d H:i:s');
$evaluation->end_time = $endTime->format('Y-m-d H:i:s');
$evaluation->status = $faker->randomElement([0, 1]); // 0未发布, 1已发布
$evaluation->save();
return $evaluation;
}
/**
* 创建评价问题字段
*/
private function createEvaluationAsks(CourseContentEvaluation $evaluation, CourseContent $courseContent, Course $course, int $count, $faker): array
{
$asks = [];
$fieldTemplates = $this->getEvaluationFieldTemplates();
for ($i = 0; $i < $count; $i++) {
$template = $faker->randomElement($fieldTemplates);
$ask = new CourseContentEvaluationAsk();
$ask->admin_id = $faker->numberBetween(1, 10);
$ask->department_id = $faker->numberBetween(1, 5);
$ask->course_id = $course->id;
$ask->course_content_id = $courseContent->id;
$ask->course_content_evaluation_id = $evaluation->id;
$ask->name = $template['name'];
$ask->field = $template['field'] . '_' . ($i + 1);
$ask->edit_input = $template['edit_input'];
$ask->rule = $template['rule'];
$ask->sort = $i + 1;
$ask->help = $template['help'];
$ask->select_item = $template['select_item'];
$ask->need_fill = $template['need_fill'];
$ask->belong_user = $template['belong_user'];
$ask->allow_input = $template['allow_input'];
$ask->save();
$asks[] = $ask;
}
return $asks;
}
/**
* 创建用户提交的评价表单
*/
private function createEvaluationForm(CourseContentEvaluation $evaluation, User $user, array $asks, $faker): void
{
$formData = [];
foreach ($asks as $ask) {
$formData[$ask->field] = $this->generateFieldValue($ask, $faker);
}
$form = new CourseContentEvaluationForm();
$form->course_content_evaluation_id = $evaluation->id;
$form->user_id = $user->id;
$form->time_total = $faker->numberBetween(180, 1800); // 3分钟到30分钟
$form->data = $formData;
$form->created_at = $faker->dateTimeBetween($evaluation->start_time, $evaluation->end_time ?: 'now');
$form->save();
}
/**
* 生成评价标题
*/
private function generateEvaluationTitle(Course $course, CourseContent $courseContent, $faker): string
{
$templates = [
'《%s》课程满意度调查',
'%s 教学效果评价',
'%s 学习体验反馈',
'关于 %s 的教学质量评估',
'%s 课程内容评价问卷',
'%s 授课情况调研',
'%s 学员反馈调查'
];
$courseName = $course->title ?? '课程';
return sprintf($faker->randomElement($templates), $courseName);
}
/**
* 生成评价描述
*/
private function generateEvaluationDesc($faker): string
{
$descriptions = [
'为了提升教学质量,改进课程内容,请您根据实际学习体验,客观填写本次评价问卷。您的宝贵意见将帮助我们持续优化课程设计。',
'此次评价旨在了解您对本课程的学习感受和建议。问卷采用匿名形式,请放心填写真实想法,感谢您的配合!',
'请根据您的实际学习情况,对本次课程的各个方面进行客观评价。您的反馈对我们改进教学方法具有重要意义。',
'为持续提升课程品质,特设立本次学员满意度调查。请您花费几分钟时间,帮助我们了解课程的优点与不足。',
'感谢您参与本次课程学习!为了给后续学员提供更好的学习体验,恳请您如实填写这份评价问卷。'
];
return $faker->randomElement($descriptions);
}
/**
* 获取评价字段模板
*/
private function getEvaluationFieldTemplates(): array
{
return [
[
'name' => '课程内容满意度',
'field' => 'content_satisfaction',
'edit_input' => 'radio',
'rule' => 'required',
'help' => '请选择您对课程内容的满意程度',
'select_item' => ['非常满意', '满意', '一般', '不满意', '非常不满意'],
'need_fill' => true,
'belong_user' => false,
'allow_input' => false
],
[
'name' => '授课方式评价',
'field' => 'teaching_method',
'edit_input' => 'radio',
'rule' => 'required',
'help' => '请评价老师的授课方式',
'select_item' => ['很好', '好', '一般', '较差', '很差'],
'need_fill' => true,
'belong_user' => false,
'allow_input' => false
],
[
'name' => '课程难度评价',
'field' => 'difficulty_level',
'edit_input' => 'radio',
'rule' => 'required',
'help' => '您认为课程难度如何',
'select_item' => ['太简单', '偏简单', '适中', '偏难', '太难'],
'need_fill' => true,
'belong_user' => false,
'allow_input' => false
],
[
'name' => '学习收获评价',
'field' => 'learning_gain',
'edit_input' => 'checkbox',
'rule' => '',
'help' => '您在本次学习中获得了哪些收获(可多选)',
'select_item' => ['理论知识', '实践技能', '思维方法', '行业认知', '人际交往', '其他'],
'need_fill' => false,
'belong_user' => false,
'allow_input' => true
],
[
'name' => '课程推荐度',
'field' => 'recommendation',
'edit_input' => 'radio',
'rule' => 'required',
'help' => '您是否愿意向他人推荐此课程',
'select_item' => ['非常愿意', '愿意', '无所谓', '不愿意', '绝对不会'],
'need_fill' => true,
'belong_user' => false,
'allow_input' => false
],
[
'name' => '整体评分',
'field' => 'overall_rating',
'edit_input' => 'select',
'rule' => 'required',
'help' => '请为本次课程打分10分制',
'select_item' => ['10分', '9分', '8分', '7分', '6分', '5分', '4分', '3分', '2分', '1分'],
'need_fill' => true,
'belong_user' => false,
'allow_input' => false
],
[
'name' => '意见建议',
'field' => 'suggestions',
'edit_input' => 'textarea',
'rule' => '',
'help' => '请提出您的宝贵意见和建议',
'select_item' => null,
'need_fill' => false,
'belong_user' => false,
'allow_input' => true
],
[
'name' => '您的姓名',
'field' => 'student_name',
'edit_input' => 'text',
'rule' => '',
'help' => '请填写您的真实姓名(可选)',
'select_item' => null,
'need_fill' => false,
'belong_user' => true,
'allow_input' => false
],
[
'name' => '联系方式',
'field' => 'contact_info',
'edit_input' => 'text',
'rule' => '',
'help' => '如需回访,请留下联系方式',
'select_item' => null,
'need_fill' => false,
'belong_user' => true,
'allow_input' => false
],
[
'name' => '课堂互动评价',
'field' => 'interaction_rating',
'edit_input' => 'radio',
'rule' => '',
'help' => '您对课堂互动环节的评价',
'select_item' => ['很活跃', '较活跃', '一般', '较沉闷', '很沉闷'],
'need_fill' => false,
'belong_user' => false,
'allow_input' => false
]
];
}
/**
* 根据字段类型生成对应的值
*/
private function generateFieldValue(CourseContentEvaluationAsk $ask, $faker)
{
switch ($ask->edit_input) {
case 'radio':
case 'select':
return $faker->randomElement($ask->select_item ?? []);
case 'checkbox':
$options = $ask->select_item ?? [];
$selected = $faker->randomElements($options, $faker->numberBetween(1, min(3, count($options))));
return implode(',', $selected);
case 'textarea':
$suggestions = [
'希望增加更多实践环节',
'课程进度可以适当放慢',
'案例分析很有帮助,建议增加',
'老师讲解很清晰,受益良多',
'课程资料很丰富,感谢分享',
'希望提供更多课后练习',
'建议增加小组讨论时间',
'整体非常满意,期待后续课程'
];
return $faker->optional(0.7)->randomElement($suggestions) ?: '';
case 'text':
if ($ask->field === 'student_name') {
return $faker->optional(0.4)->name ?: '';
} elseif ($ask->field === 'contact_info') {
return $faker->optional(0.3)->phoneNumber ?: '';
}
return $faker->optional(0.5)->words(3, true) ?: '';
default:
return '';
}
}
/**
* 创建示例课程和课程内容数据(如果不存在)
*/
private function createSampleCoursesAndContents($faker): void
{
$courseData = [
['title' => 'Python 程序设计基础', 'contents' => ['Python 语言概述', '数据类型与变量', '控制结构', '函数与模块', '面向对象编程']],
['title' => '数据库原理与应用', 'contents' => ['数据库基础概念', 'SQL 语言基础', '数据库设计', '事务处理', '性能优化']],
['title' => '项目管理实务', 'contents' => ['项目管理概述', '项目计划制定', '风险管理', '团队管理', '项目收尾']],
['title' => '市场营销学', 'contents' => ['市场营销概论', '消费者行为分析', '产品策略', '价格策略', '推广策略']],
['title' => 'Web 前端开发', 'contents' => ['HTML 基础', 'CSS 样式设计', 'JavaScript 编程', 'Vue.js 框架', '项目实战']]
];
foreach ($courseData as $data) {
$course = Course::create([
'title' => $data['title'],
'description' => $data['title'] . '课程',
'status' => 1,
'created_at' => now(),
'updated_at' => now()
]);
foreach ($data['contents'] as $index => $contentTitle) {
CourseContent::create([
'course_id' => $course->id,
'title' => $contentTitle,
'description' => $contentTitle . '相关内容',
'sort' => $index + 1,
'status' => 1,
'created_at' => now(),
'updated_at' => now()
]);
}
}
}
}
Loading…
Cancel
Save