You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

303 lines
11 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<?php
namespace App\Console\Commands;
use App\Models\Course;
use App\Models\Calendar;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
class LinkCoursesToCalendar extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'link:courses-to-calendar';
/**
* The console command description.
*
* @var string
*/
protected $description = '将指定的课程列表关联到calendars日历表';
/**
* 课程列表
*
* @var array
*/
protected $courseList = [
'第三期:张平院士— 6G通信与AI融合',
'高研班|第四期高级科创人才研修班-第七模块',
'高研班|第五期高级科创人才研修班-第五模块',
'校友返校日AI+产业融合创新论坛',
'高研班|第六期高级科创人才研修班-第三模块',
'第二课堂|走进珂玛科技',
'人才培训|省科技厅高级技术经理人专班-开学模块',
'初创班|首期技术经理人领航班-第一模块',
'专题培训|苏州市科技企业资本运作公开课',
'初创班|首期高校科技成果转化班-第一模块',
'高研班|第五期高级科创人才研修班-毕业模块',
'高研班|第四期高级科创人才研修班-第八模块',
'第二课堂|走进世华科技',
'初创班|首期高校科技成果转化班-第二模块',
'高研班|第六期高级科创人才研修班-第四模块',
'人才培训|省科技厅高级技术经理人专班-实践模块',
'初创班|首期技术经理人领航班-第二模块',
'攀峰班|首期苏州科技企业资本运作研修班-开学模块',
'初创班|首期技术经理人领航班-结业模块',
'高研班|第七期高级科创人才研修班-开学模块',
'产业加速营|具身智能极客营-开学模块',
'产业加速营|苏州市人工智能潜在独角兽训练营-开学模块',
'初创班|首期高校科技成果转化班-结业模块',
'第二课堂|走进姑苏区',
'高研班|第六期高级科创人才研修班-第五模块',
'产业加速营|苏州市人工智能潜在独角兽训练营-第二模块',
'夏令营2025年度小科学家夏令营',
'攀峰班|首期苏州科技企业资本运作研修班-第二模块',
'产业加速营|苏州市人工智能潜在独角兽训练营-第三模块',
'人才培训|江苏青年科技人才"U35青创学院"培训',
'高研班|第七期高级科创人才研修班-第二模块',
'第二课堂|走进科沃斯',
'高研班|第四期高级科创人才研修班-开学模块',
'高研班|第三期高级科创人才研修班-结业模块',
'第二课堂|走进永鼎',
'第二课堂|走进旭创',
'高研班|第五期高级科创人才研修班-开学模块',
'高研班|第四期高级科创人才研修班-第二模块',
'第二课堂|走进亨通',
'第二课堂|走进企查查',
'科技大讲堂|第一期: 凯文凯利、丁文江院士领衔',
'高研班|第四期高级科创人才研修班-第三模块',
'第二课堂|走进华为苏研所',
'人才培训2024年姑苏领军人才培育营',
'专题培训|苏州市标杆孵化器培训',
'高研班|第五期高级科创人才研修班-第一模块',
'第二课堂|走进亚盛医药',
'第二课堂|新加坡海外游学',
'第二课堂|走进苏州市市场监督管理局',
'第二课堂|走进信达生物',
'人才培训|江苏省高层次人才专题培训',
'夏令营2024年度小科学家夏令营',
'高研班|第五期高级科创人才研修班-第二模块',
'高研班|第四期高级科创人才研修班-第四模块',
'专题培训|太仓市国资审计高质量发展专题培训',
'第二课堂|走进天准科技',
'高研班|第五期高级科创人才研修班-第三模块',
'科技金融沙龙|上海交通大学新能源沙龙',
'科技大讲堂|第二期:伊雷娜·克罗宁解析空间计算',
'人才培训|苏州市科技企业孵化器沙龙',
'高研班|第四期高级科创人才研修班-第五模块',
'人才培训|苏州乡镇党委书记专题研修班',
'科技金融沙龙|资本市场新机遇研讨沙龙',
'产业加速营|人工智能产业加速营',
'高研班|第六期高级科创人才研修班-开学模块',
'第二课堂|走进苏州市低空经济发展展示馆',
'高研班|第四期高级科创人才研修班-第六模块',
'人才培训2024姑苏领军人才创业营',
'产业加速营|集成电路产业专班',
'专题培训关税与出海应对2025美国新政',
'高研班|第五期高级科创人才研修班-第四模块',
'高研班|第六期高级科创人才研修班-第二模块',
];
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$this->info("开始将课程关联到calendars日历表...");
$this->info("总共需要处理 " . count($this->courseList) . " 个课程");
$linkedCount = 0;
$notFoundCourses = [];
$alreadyLinkedCourses = [];
DB::beginTransaction();
try {
foreach ($this->courseList as $courseName) {
$this->info("正在处理课程: {$courseName}");
// 查找匹配的课程
$course = $this->findCourse($courseName);
if (!$course) {
$this->warn("✗ 未找到匹配的课程: {$courseName}");
$notFoundCourses[] = $courseName;
continue;
}
$this->info("✓ 找到匹配课程: {$course->name} (ID: {$course->id})");
// 检查是否已经存在日历记录
$existingCalendar = Calendar::where('course_id', $course->id)
->where('type', 1) // 类型1为课程
->first();
if ($existingCalendar) {
$this->warn("⚠ 课程已存在日历记录: {$course->name}");
$alreadyLinkedCourses[] = $course->name;
continue;
}
// 创建日历记录
$calendarData = $this->createCalendarData($course);
$calendar = Calendar::create($calendarData);
$this->info("✓ 成功创建日历记录 (ID: {$calendar->id}) 关联课程: {$course->name}");
$linkedCount++;
}
DB::commit();
$this->info("\n" . str_repeat('=', 60));
$this->info("处理完成!");
$this->info("成功关联课程数量: {$linkedCount}");
$this->info("已存在日历记录: " . count($alreadyLinkedCourses));
$this->info("未找到匹配课程: " . count($notFoundCourses));
// 显示未找到的课程
if (!empty($notFoundCourses)) {
$this->warn("\n未找到匹配的课程列表:");
foreach ($notFoundCourses as $course) {
$this->warn(" - {$course}");
}
}
// 显示已存在日历记录的课程
if (!empty($alreadyLinkedCourses)) {
$this->warn("\n已存在日历记录的课程列表:");
foreach ($alreadyLinkedCourses as $course) {
$this->warn(" - {$course}");
}
}
} catch (\Exception $e) {
DB::rollback();
$this->error("处理过程中发生错误: " . $e->getMessage());
$this->error("已回滚所有更改");
return;
}
$this->info("\n所有操作已完成!");
}
/**
* 查找匹配的课程
*/
private function findCourse($courseName)
{
// 1. 精确匹配
$course = Course::where('name', $courseName)
->whereNull('deleted_at')
->first();
if ($course) {
return $course;
}
// 2. 模糊匹配
$course = Course::where('name', 'like', "%{$courseName}%")
->whereNull('deleted_at')
->first();
if ($course) {
$this->info("通过模糊匹配找到课程: '{$course->name}'");
return $course;
}
// 3. 相似度匹配
$courses = Course::whereNull('deleted_at')
->whereNotNull('name')
->where('name', '!=', '')
->get();
$bestMatch = null;
$highestSimilarity = 0;
foreach ($courses as $course) {
$similarity = $this->calculateSimilarity($courseName, $course->name);
if ($similarity > $highestSimilarity) {
$highestSimilarity = $similarity;
$bestMatch = $course;
}
}
if ($bestMatch && $highestSimilarity > 0.3) { // 设置最低相似度阈值
$this->info("通过相似度匹配找到课程 (相似度: " . round($highestSimilarity * 100, 2) . "%): '{$bestMatch->name}'");
return $bestMatch;
}
return null;
}
/**
* 创建日历数据
*/
private function createCalendarData($course)
{
return [
'type' => 1, // 类型1为课程
'course_id' => $course->id,
'date' => $course->start_date ?? now()->format('Y-m-d'),
'title' => $course->name,
'content' => $course->content ?? '',
'start_time' => $course->start_date ? $course->start_date . ' 09:00:00' : null,
'end_time' => $course->end_date ? $course->end_date . ' 17:00:00' : null,
'url' => $course->url ?? '',
'created_at' => now(),
'updated_at' => now(),
];
}
/**
* 计算字符串相似度
*/
private function calculateSimilarity($str1, $str2)
{
// 移除空格并转换为小写
$str1 = strtolower(preg_replace('/\s+/', '', $str1));
$str2 = strtolower(preg_replace('/\s+/', '', $str2));
if ($str1 === $str2) {
return 1.0;
}
if (empty($str1) || empty($str2)) {
return 0.0;
}
// 使用Levenshtein距离计算相似度
$maxLen = max(strlen($str1), strlen($str2));
if ($maxLen == 0) {
return 1.0;
}
$distance = levenshtein($str1, $str2);
$similarity = 1 - ($distance / $maxLen);
// 如果其中一个字符串包含另一个,提高相似度
if (strpos($str1, $str2) !== false || strpos($str2, $str1) !== false) {
$containsSimilarity = min(strlen($str1), strlen($str2)) / $maxLen;
$similarity = max($similarity, $containsSimilarity);
}
return max(0, $similarity);
}
}