diff --git a/app/Exports/CommonExport.php b/app/Exports/CommonExport.php index c4b1a5c..053dd22 100755 --- a/app/Exports/CommonExport.php +++ b/app/Exports/CommonExport.php @@ -6,6 +6,7 @@ namespace App\Exports; use App\Exceptions\ErrorException; +use App\Models\CourseType; use Illuminate\Support\Collection; use Maatwebsite\Excel\Concerns\FromCollection; use Maatwebsite\Excel\Concerns\WithStyles; @@ -21,6 +22,7 @@ class CommonExport implements FromCollection, WithStyles, WithColumnWidths, With public $data; public $hasUsersField = false; public $hasProjectUsersField = false; + public $hasHistoryCoursesField = false; public $totalColumns = 0; public $totalRows = 0; public $expandedFields = []; @@ -45,6 +47,15 @@ class CommonExport implements FromCollection, WithStyles, WithColumnWidths, With 'pm_amount' => '投资金额', ]; + // 历史课程信息子列定义 + const HISTORY_COURSES_SUB_COLUMNS = [ + 'hc_course_type' => '课程体系', + 'hc_course_name' => '课程名称', + 'hc_signs_pass' => '培养人数未去重', + 'hc_signs_pass_unique' => '培养人数去重', + 'hc_course_signs_pass' => '课程培养人数', + ]; + public function __construct($data, $exportFields) { // 需要导出的字段。格式:['name'=>'名字','user.sex'=>'性别'] @@ -66,7 +77,13 @@ class CommonExport implements FromCollection, WithStyles, WithColumnWidths, With } $index = 1; + // 第一遍:处理除了历史课程之外的所有字段 foreach ($this->fields as $field => $label) { + if (str_contains($field, 'history_courses')) { + // 跳过历史课程,稍后处理 + continue; + } + if (str_contains($field, 'users') && !str_contains($field, 'project_users')) { $this->hasUsersField = true; // 展开学员信息为多列 @@ -86,6 +103,19 @@ class CommonExport implements FromCollection, WithStyles, WithColumnWidths, With $index++; } } + + // 第二遍:处理历史课程字段,放在最后 + foreach ($this->fields as $field => $label) { + if (str_contains($field, 'history_courses')) { + $this->hasHistoryCoursesField = true; + // 展开历史课程信息为多列 + foreach (self::HISTORY_COURSES_SUB_COLUMNS as $subField => $subLabel) { + $this->expandedFields[$subField] = $subLabel; + $index++; + } + } + } + $this->totalColumns = count($this->expandedFields); } @@ -94,7 +124,7 @@ class CommonExport implements FromCollection, WithStyles, WithColumnWidths, With */ private function needsDoubleHeader() { - return $this->hasUsersField || $this->hasProjectUsersField; + return $this->hasUsersField || $this->hasProjectUsersField || $this->hasHistoryCoursesField; } /** @@ -130,8 +160,12 @@ class CommonExport implements FromCollection, WithStyles, WithColumnWidths, With $widths[$letter] = 18; } elseif (str_contains($field, 'partners')) { $widths[$letter] = 50; + } elseif (str_contains($field, 'hc_course_type') || str_contains($field, 'hc_course_name')) { + $widths[$letter] = 25; + } elseif (str_contains($field, 'hc_')) { + $widths[$letter] = 18; } elseif (str_contains($field, 'history_courses')) { - // 历史课程信息通常较长,适当放宽列宽 + // 历史课程信息通常较长,适当放宽列宽(如果没有展开的情况) $widths[$letter] = 40; } elseif (str_contains($field, 'all_course')) { $widths[$letter] = 40; @@ -266,6 +300,13 @@ class CommonExport implements FromCollection, WithStyles, WithColumnWidths, With $sheet->mergeCells("{$startCol}1:{$endCol}1"); $sheet->setCellValue("{$startCol}1", $label); $index += count(self::PROJECT_USERS_SUB_COLUMNS); + } elseif (str_contains($field, 'history_courses')) { + // 历史课程信息列:合并第一行的多个单元格 + $startCol = $this->getColumnLetter($index); + $endCol = $this->getColumnLetter($index + count(self::HISTORY_COURSES_SUB_COLUMNS) - 1); + $sheet->mergeCells("{$startCol}1:{$endCol}1"); + $sheet->setCellValue("{$startCol}1", $label); + $index += count(self::HISTORY_COURSES_SUB_COLUMNS); } else { // 其他列:合并第一行和第二行 $col = $this->getColumnLetter($index); @@ -305,6 +346,10 @@ class CommonExport implements FromCollection, WithStyles, WithColumnWidths, With foreach (self::PROJECT_USERS_SUB_COLUMNS as $subLabel) { $header1[] = ''; } + } elseif (str_contains($field, 'history_courses')) { + foreach (self::HISTORY_COURSES_SUB_COLUMNS as $subLabel) { + $header1[] = ''; + } } else { $header1[] = ''; } @@ -322,6 +367,10 @@ class CommonExport implements FromCollection, WithStyles, WithColumnWidths, With foreach (self::PROJECT_USERS_SUB_COLUMNS as $subLabel) { $header2[] = $subLabel; } + } elseif (str_contains($field, 'history_courses')) { + foreach (self::HISTORY_COURSES_SUB_COLUMNS as $subLabel) { + $header2[] = $subLabel; + } } else { $header2[] = ''; } @@ -333,11 +382,11 @@ class CommonExport implements FromCollection, WithStyles, WithColumnWidths, With $expandedRows = $this->getExpandedRows($info); if (empty($expandedRows)) { // 没有展开数据,输出一行空数据 - $row = $this->buildExpandedRow($info, [], []); + $row = $this->buildExpandedRow($info, [], [], []); $newList[] = $row; } else { foreach ($expandedRows as $expandedRow) { - $row = $this->buildExpandedRow($info, $expandedRow['users'] ?? [], $expandedRow['project_users'] ?? []); + $row = $this->buildExpandedRow($info, $expandedRow['users'] ?? [], $expandedRow['project_users'] ?? [], $expandedRow['history_courses'] ?? []); $newList[] = $row; } } @@ -400,15 +449,17 @@ class CommonExport implements FromCollection, WithStyles, WithColumnWidths, With { $usersData = $this->hasUsersField ? $this->getUsersExpanded($info) : []; $projectUsersData = $this->hasProjectUsersField ? $this->getProjectUsersExpanded($info) : []; + $historyCoursesData = $this->hasHistoryCoursesField ? $this->getHistoryCoursesExpanded($info) : []; // 计算最大行数 - $maxRows = max(count($usersData), count($projectUsersData), 1); + $maxRows = max(count($usersData), count($projectUsersData), count($historyCoursesData), 1); $result = []; for ($i = 0; $i < $maxRows; $i++) { $result[] = [ 'users' => $usersData[$i] ?? [], 'project_users' => $projectUsersData[$i] ?? [], + 'history_courses' => $historyCoursesData[$i] ?? [], ]; } @@ -436,6 +487,51 @@ class CommonExport implements FromCollection, WithStyles, WithColumnWidths, With return $result; } + /** + * 获取展开的历史课程数据(每条历史课程一行) + */ + private function getHistoryCoursesExpanded($info) + { + if (empty($info['history_courses']) || !is_array($info['history_courses'])) { + return []; + } + + $result = []; + foreach ($info['history_courses'] as $item) { + // 获取课程体系名称 + $courseTypeName = ''; + if (isset($item['type_detail']) && isset($item['type_detail']['name'])) { + // 关联数据可能是 type_detail(下划线形式) + $courseTypeName = $item['type_detail']['name']; + } elseif (isset($item['typeDetail']) && isset($item['typeDetail']['name'])) { + // 关联数据可能是 typeDetail(驼峰形式) + $courseTypeName = $item['typeDetail']['name']; + } elseif (isset($item['type'])) { + // 如果只有类型ID,尝试查询类型名称 + $typeId = $item['type']; + try { + $courseType = CourseType::find($typeId); + if ($courseType) { + $courseTypeName = $courseType->name; + } else { + $courseTypeName = $typeId; // 如果查询不到,显示ID + } + } catch (\Exception $e) { + $courseTypeName = $typeId; // 查询失败,显示ID + } + } + + $result[] = [ + 'hc_course_type' => $courseTypeName, + 'hc_course_name' => $item['course_name'] ?? '', + 'hc_signs_pass' => $item['course_type_signs_pass'] ?? 0, + 'hc_signs_pass_unique' => $item['course_type_signs_pass_unique'] ?? 0, + 'hc_course_signs_pass' => $item['course_signs_pass'] ?? 0, + ]; + } + return $result; + } + /** * 获取展开的学员数据(每个学员每条课程一行) */ @@ -481,7 +577,7 @@ class CommonExport implements FromCollection, WithStyles, WithColumnWidths, With /** * 构建包含展开数据的行 */ - private function buildExpandedRow($info, $userData, $projectUserData) + private function buildExpandedRow($info, $userData, $projectUserData, $historyCourseData = []) { $row = []; foreach ($this->fields as $field => $label) { @@ -495,15 +591,17 @@ class CommonExport implements FromCollection, WithStyles, WithColumnWidths, With foreach (array_keys(self::PROJECT_USERS_SUB_COLUMNS) as $subField) { $row[] = $projectUserData[$subField] ?? ''; } + } elseif (str_contains($field, 'history_courses')) { + // 填充历史课程信息列 + foreach (array_keys(self::HISTORY_COURSES_SUB_COLUMNS) as $subField) { + $row[] = $historyCourseData[$subField] ?? ''; + } } elseif (str_contains($field, 'idcard')) { $row[] = ' ' . $this->getDotValue($info, $field); } elseif (str_contains($field, 'all_course')) { $row[] = $this->allCourse($info); } elseif (str_contains($field, 'partners')) { $row[] = $this->partners($info); - } elseif (str_contains($field, 'history_courses')) { - // 历史课程信息字段,格式化为多行文本 - $row[] = $this->historyCourses($info); } else { $row[] = $this->getDotValue($info, $field); } diff --git a/app/Http/Controllers/Admin/CompanyController.php b/app/Http/Controllers/Admin/CompanyController.php index 60a09ae..fcd0fed 100644 --- a/app/Http/Controllers/Admin/CompanyController.php +++ b/app/Http/Controllers/Admin/CompanyController.php @@ -126,7 +126,7 @@ class CompanyController extends BaseController // 使用 LIKE 匹配 JSON 字符串中的年份范围 $query->where(function ($q) use ($start_year, $end_year) { for ($year = (int)$start_year; $year <= (int)$end_year; $year++) { - $q->orWhere('project_users', 'like', '%"investDate":"' . $year . '%'); + $q->orWhere('project_users', 'like', '%' . $year . '%'); } }); } @@ -209,17 +209,15 @@ class CompanyController extends BaseController 'company_invested_after_enrollment_total' => 0, 'company_invested_year_total' => 0, ]; - $start_date = $start_year ? $start_year . '-01-01' : CourseType::START_DATE; + $start_date = $start_year ? $start_year . '-01-01' : date('Y-01-01'); $end_date = $end_year ? $end_year . '-12-31' : date('Y-m-d'); if ($start_date && $end_date) { // 累计被投企业数(从起始日期到结束日期) - $statistics['course_signs_invested'] = CourseSign::yhInvestedTotal(CourseType::START_DATE, $end_date, null); - + $statistics['course_signs_invested'] = Company::yhInvestedTotal($end_date); + // 今年年份范围内被投企业数 + $statistics['company_invested_year_total'] = Company::companyInvestedYear($start_date, $end_date); // 入学后被投企业数量(在指定时间范围内报名的学员所在公司中,在入学后被投的公司数量) - $statistics['company_invested_after_enrollment_total'] = CourseSign::companyInvestedAfterEnrollment($start_date, $end_date, null); - - // 年份范围内被投企业数(在指定时间范围内报名的学员所在公司中,被投时间在年份范围内的公司数量) - $statistics['company_invested_year_total'] = CourseSign::companyInvestedYear($start_date, $end_date, null); + $statistics['company_invested_after_enrollment_total'] = CourseSign::companyInvestedAfterEnrollment($start_date, $end_date); } // 将统计数据添加到返回结果中 diff --git a/app/Http/Controllers/Admin/OtherController.php b/app/Http/Controllers/Admin/OtherController.php index 03e75e2..ae9ef0f 100755 --- a/app/Http/Controllers/Admin/OtherController.php +++ b/app/Http/Controllers/Admin/OtherController.php @@ -146,24 +146,32 @@ class OtherController extends CommonController ->get(); // 课程统计 $courseTypes = CourseType::where('is_chart', 1)->where('is_history', 0)->get(); + // 默认开始时间 $start_date = CourseType::START_DATE; - $end_date = date('Y-m-d'); + // 默认结束日期一年以后 + $end_date = date('Y-m-d', strtotime('+10 year')); + foreach ($courseTypes as $courseType) { // 历史已开设期数 $historyCourse = HistoryCourse::whereHas('typeDetail', function ($query) use ($courseType) { $query->where('name', 'like', '%' . $courseType->name . '%'); })->get(); + // 课程 + $courses = Course::where('type', $courseType->id)->get(); // 历史课程期数 $courseType->history_course_periods_total = $historyCourse->count(); + // 现在课程数据 + $courseType->now_course_periods_total = Course::where('type', $courseType->id)->count(); + // 历史课程培养人数去重 $courseType->history_course_signs_total = $historyCourse->sum('course_type_signs_pass_unique'); + // 现在课程培养人数 + $courseType->now_course_signs_total = CourseSign::courseSignsTotalByUnique($start_date, $end_date, 1, $courses->pluck('id'), false, false); - // 课程 - $courses = Course::where('type', $courseType->id)->get(); // 已开设期数 - $courseType->course_periods_total = Course::where('type', $courseType->id)->count() + $courseType->history_course_periods_total; + $courseType->course_periods_total = $courseType->now_course_periods_total + $courseType->history_course_periods_total; // 培养人数去重 - $courseType->course_signs_total = $courseType->history_course_signs_total + CourseSign::courseSignsTotalByUnique($start_date, $end_date, 1, $courses->pluck('id'), null); + $courseType->course_signs_total = $courseType->history_course_signs_total + $courseType->now_course_signs_total; } @@ -240,36 +248,9 @@ class OtherController extends CommonController // 审核通过人数去重 $list['course_signs_pass_unique'] = CourseSign::courseSignsTotalByUnique($start_date, $end_date, 1, $courses->pluck('id'), null); // 开课场次 - // 开课场次 - $calendar = Calendar::where(function ($query) use ($start_date, $end_date) { - $query->whereBetween('start_time', [$start_date, $end_date]) - ->orWhereBetween('end_time', [$start_date, $end_date]); - })->where(function ($query) use ($course_type_id) { - // 条件1:有 course_id 的数据,通过 course.type 匹配课程体系 - // 条件2:没有 course_id 的数据,直接用 course_type_id 字段匹配 - // 两个条件是或关系 - - if ($course_type_id) { - $course_type_id_array = is_array($course_type_id) ? $course_type_id : explode(',', $course_type_id); - - // 条件1:有 course_id 时,通过关联的 course.type 匹配 - $query->where(function ($q) use ($course_type_id_array) { - - $q->whereHas('course', function ($subQ) use ($course_type_id_array) { - $subQ->whereIn('type', $course_type_id_array); - }); - }); - - // 条件2:没有 course_id 时,直接用 course_type_id 字段匹配(或关系) - $query->orWhere(function ($q) use ($course_type_id_array) { - $q->whereIn('course_type_id', $course_type_id_array); - }); - } - })->get(); - - $list['course_total'] = (clone $calendar)->count(); + $list['course_total'] = Calendar::getCourseTotal($start_date, $end_date, $course_type_id); // 开课天数 - $list['course_day_total'] = (clone $calendar)->where('is_count_days', 1)->sum('days'); + $list['course_day_total'] = Calendar::getCourseDayTotal($start_date, $end_date, $course_type_id); $course_ids = $courses->pluck('id'); @@ -411,7 +392,7 @@ class OtherController extends CommonController switch ($export_type) { case 'course_signs_invested': // 被投企业明细 - 使用与coursesHome相同的算法 - $companies = CourseSign::yhInvestedTotal($start_date, $end_date, $course_ids, true); + $companies = CourseSign::yhInvestedTotal(CourseType::START_DATE, $end_date, $course_ids, true); foreach ($companies as $company) { $data[] = [ 'company_name' => $company->company_name, @@ -543,20 +524,57 @@ class OtherController extends CommonController // 课程分类明细 - 与coursesHome中的courseTypesSum逻辑保持一致 $courseTypes = CourseType::whereIn('id', $course_type_id)->get(); foreach ($courseTypes as $courseType) { - $courses2 = Course::where('type', $courseType->id)->get(); + // 获取课程 - 添加日期筛选逻辑 + $courses2 = Course::where('type', $courseType->id) + ->where(function ($query) use ($start_date, $end_date) { + // 开始结束日期的筛选。or查询 + if ($start_date && $end_date) { + $query->whereBetween('start_date', [$start_date, $end_date]) + ->orWhereBetween('end_date', [$start_date, $end_date]); + } + })->orderBy('start_date', 'asc')->get(); foreach ($courses2 as $course) { $data[] = [ 'course_type' => $courseType->name, 'course_name' => $course->name, - 'course_type_signs_pass' => CourseSign::courseSignsTotal($start_date, $end_date, 1, $courses2->pluck('id')), - 'course_type_signs_pass_unique' => CourseSign::courseSignsTotalByUnique($start_date, $end_date, 1, $courses2->pluck('id'), null), - 'course_signs_pass' => CourseSign::courseSignsTotal($start_date, $end_date, 1, [$course->id]), + 'course_type_signs_pass' => CourseSign::courseSignsTotal($start_date, $end_date, 1, $courses2->pluck('id'), false, false), + 'course_type_signs_pass_unique' => CourseSign::courseSignsTotalByUnique($start_date, $end_date, 1, $courses2->pluck('id'), false, false), + 'course_signs_pass' => CourseSign::courseSignsTotal($start_date, $end_date, 1, [$course->id], false, false), 'genban_total' => CourseSign::genban($start_date, $end_date, [$course->id]), 'yh_invested_total' => CourseSign::yhInvested($start_date, $end_date, [$course->id]), 'company_join_total' => CourseSign::companyJoin($start_date, $end_date, [$course->id]), ]; } } + // 附加历史课程数据 + $courseTypesHistory = CourseType::where('is_history', 1)->whereIn('id', $course_type_id)->get(); + foreach ($courseTypesHistory as $historyCourse) { + $courses3 = HistoryCourse::whereHas('calendar', function ($query) { + $query->where('is_count_people', 1); + })->where(function ($query) use ($start_date, $end_date) { + // 开始结束日期的筛选。or查询 + $query->whereBetween('start_time', [$start_date, $end_date]) + ->orWhereBetween('end_time', [$start_date, $end_date]); + })->where('type', $historyCourse->id)->get(); + foreach ($courses3 as $course) { + $data[] = [ + 'course_type' => $historyCourse->name, + 'course_name' => $course->course_name, + // 课程类型培养人数 + 'course_type_signs_pass' => $courses3->sum('course_type_signs_pass'), + // 课程类型去重培养人数 + 'course_type_signs_pass_unique' => $courses3->sum('course_type_signs_pass_unique'), + // 课程人数 + 'course_signs_pass' => $course->course_signs_pass, + // 跟班学员数量 + 'genban_total' => 0, + // 被投企业数 + 'yh_invested_total' => 0, + // 元禾同事数 + 'company_join_total' => 0, + ]; + } + } $fields = [ 'course_type' => '课程体系', 'course_name' => '课程名称', @@ -871,7 +889,7 @@ class OtherController extends CommonController // 年份范围内被投企业明细 - 所有年份范围内被投企业,关联学员、课程信息 // 数据结构:主表是公司,子数据是学员信息 // 导出时:公司信息只在第一行显示,后续行公司信息为空 - $companiesData = CourseSign::companyInvestedYear($start_date, $end_date, $course_ids->toArray(), true); + $companiesData = CourseSign::companyInvestedYear($start_date, $end_date, $course_ids, true); foreach ($companiesData as $item) { $company = $item['company']; @@ -955,14 +973,8 @@ class OtherController extends CommonController case 'course_total': // 开课场次明细 - 与coursesHome算法一致 - $calendars = Calendar::whereBetween('date', [$start_date, $end_date]) - ->where(function ($query) use ($course_ids) { - $course_type_id = request('course_type_id'); - if ($course_type_id) { - $course_type_id = explode(',', $course_type_id); - $query->whereIn('course_type_id', $course_type_id); - } - })->with('course') + $calendars = Calendar::getCalendarsByDateRange($start_date, $end_date, $course_type_id) + ->with('course') ->get(); foreach ($calendars as $calendar) { @@ -988,14 +1000,8 @@ class OtherController extends CommonController case 'course_day_total': // 开课天数明细 - 与coursesHome算法一致 - $calendars = Calendar::whereBetween('date', [$start_date, $end_date]) - ->where(function ($query) use ($course_ids) { - $course_type_id = request('course_type_id'); - if ($course_type_id) { - $course_type_id = explode(',', $course_type_id); - $query->whereIn('course_type_id', $course_type_id); - } - })->where('is_count_days', 1) + $calendars = Calendar::getCalendarsByDateRange($start_date, $end_date, $course_type_id) + ->where('is_count_days', 1) ->with('course') ->get(); @@ -1140,8 +1146,9 @@ class OtherController extends CommonController case 'cover_stock_total': // 重点上市公司明细 - 使用模型方法 - $companies = CourseSign::shangshi($start_date, $end_date, $course_ids, true); - foreach ($companies as $company) { + $companiesData = CourseSign::shangshi($start_date, $end_date, $course_ids, true); + foreach ($companiesData as $item) { + $company = $item['company']; $data[] = [ 'company_name' => $company->company_name, 'company_legal_representative' => $company->company_legal_representative ?? '', diff --git a/app/Http/Controllers/Admin/UserController.php b/app/Http/Controllers/Admin/UserController.php index bc0bdc0..c0a05b1 100755 --- a/app/Http/Controllers/Admin/UserController.php +++ b/app/Http/Controllers/Admin/UserController.php @@ -9,6 +9,7 @@ use App\Helpers\StarterResponseCode; use App\Models\Course; use App\Models\CourseAppointmentTotal; use App\Models\CourseSign; +use App\Models\CourseType; use App\Models\CustomForm; use App\Models\CustomFormField; use App\Models\User; @@ -338,6 +339,9 @@ class UserController extends BaseController if (isset($all['is_schoolmate'])) { $query->where('is_schoolmate', $all['is_schoolmate']); } + if (isset($all['year'])) { + $query->where('created_at', 'like', '%' . $all['year'] . '%'); + } if (isset($all['company_need_fund'])) { $query->where('company_need_fund', $all['company_need_fund']); } @@ -371,13 +375,13 @@ class UserController extends BaseController return Excel::download(new CommonExport($list, $all['export_fields'] ?? ''), $all['file_name'] ?? '' . date('YmdHis') . '.xlsx'); } else { // 累计总数 - $total = CourseSign::courseSignsTotalByUnique('2020-01-01', date('Y-m-d')); + $total = CourseSign::courseSignsTotalByUnique(CourseType::START_DATE, date('Y-m-d')); // 报名人数 $year_total = CourseSign::courseSignsTotalByUnique($start_date, $end_date); // 年度培养学员 $year_training_total = CourseSign::courseSignsTotalByUnique($start_date, $end_date, 1); // 累计培养学员 - $training_total = CourseSign::courseSignsTotalByUnique('2020-01-01', date('Y-m-d'), 1); + $training_total = CourseSign::courseSignsTotalByUnique(CourseType::START_DATE, date('Y-m-d'), 1); $list = $list->paginate($all['page_size'] ?? 20); } return $this->success(['list' => $list, 'year_total' => $year_total, 'total' => $total, 'year_training_total' => $year_training_total, 'training_total' => $training_total]); diff --git a/app/Models/Calendar.php b/app/Models/Calendar.php index e9bd64f..b247246 100755 --- a/app/Models/Calendar.php +++ b/app/Models/Calendar.php @@ -18,7 +18,7 @@ class Calendar extends SoftDeletesModel public function getTypeTextAttribute() { - $array = [1=>'课程', 3=>'自定义事件', 4=>'资讯']; + $array = [1 => '课程', 3 => '自定义事件', 4 => '资讯']; return $array[$this->attributes['type']] ?? ''; } @@ -52,5 +52,66 @@ class Calendar extends SoftDeletesModel return $this->belongsTo(CourseType::class, 'course_type_id', 'id'); } + /** + * 根据日期范围和课程体系获取日历查询构建器 + * @param string|null $start_date 开始日期 + * @param string|null $end_date 结束日期 + * @param array|null $course_type_id 课程体系ID数组 + * @return \Illuminate\Database\Eloquent\Builder + */ + public static function getCalendarsByDateRange($start_date = null, $end_date = null, $course_type_id = null) + { + return self::where(function ($query) use ($start_date, $end_date) { + $query->whereBetween('start_time', [$start_date, $end_date]) + ->orWhereBetween('end_time', [$start_date, $end_date]); + })->where(function ($query) use ($course_type_id) { + // 条件1:有 course_id 的数据,通过 course.type 匹配课程体系 + // 条件2:没有 course_id 的数据,直接用 course_type_id 字段匹配 + // 两个条件是或关系 + + if ($course_type_id) { + $course_type_id_array = is_array($course_type_id) ? $course_type_id : explode(',', $course_type_id); + + // 条件1:有 course_id 时,通过关联的 course.type 匹配 + $query->where(function ($q) use ($course_type_id_array) { + $q->whereHas('course', function ($subQ) use ($course_type_id_array) { + $subQ->whereIn('type', $course_type_id_array); + }); + }); + + // 条件2:没有 course_id 时,直接用 course_type_id 字段匹配(或关系) + $query->orWhere(function ($q) use ($course_type_id_array) { + $q->whereIn('course_type_id', $course_type_id_array); + }); + } + }); + } + + /** + * 获取开课场次数量 + * @param string|null $start_date 开始日期 + * @param string|null $end_date 结束日期 + * @param array|null $course_type_id 课程体系ID数组 + * @return int + */ + public static function getCourseTotal($start_date = null, $end_date = null, $course_type_id = null) + { + return self::getCalendarsByDateRange($start_date, $end_date, $course_type_id)->count(); + } + + /** + * 获取开课天数总和 + * @param string|null $start_date 开始日期 + * @param string|null $end_date 结束日期 + * @param array|null $course_type_id 课程体系ID数组 + * @return int|float + */ + public static function getCourseDayTotal($start_date = null, $end_date = null, $course_type_id = null) + { + return self::getCalendarsByDateRange($start_date, $end_date, $course_type_id) + ->where('is_count_days', 1) + ->sum('days'); + } + } diff --git a/app/Models/Company.php b/app/Models/Company.php index e5a10b2..0d67a9f 100644 --- a/app/Models/Company.php +++ b/app/Models/Company.php @@ -58,4 +58,107 @@ class Company extends SoftDeletesModel } } + /** + * 累计被投企业统计 + * @param string|null $start_date 开始日期 + * @param string|null $end_date 结束日期 + * @param array|null $course_ids 课程ID(仅在自定义时间时生效) + * @param bool $retList 是否返回列表 + */ + public static function yhInvestedTotal($end_date = null, $retList = false) + { + // 获取这些学员所在的被投企业 + $companies = Company::where('is_yh_invested', 1)->get(); + // 自定义时间:需要按被投时间筛选 + // 筛选出被投时间在范围内的企业 + $filteredCompanies = []; + foreach ($companies as $company) { + $projectUsers = $company->project_users ?? []; + $hasValidInvestDate = false; + $allInvestDatesNull = true; + + foreach ($projectUsers as $item) { + $investDate = $item['investDate'] ?? null; + // 检查是否有有效的被投时间 + if ($investDate) { + $allInvestDatesNull = false; + // 检查被投时间是否在范围内 + if ($investDate <= $end_date) { + $hasValidInvestDate = true; + break; // 只要有一条满足就加入 + } + } + } + + // 如果有有效的被投时间在范围内,或者所有被投时间都是null,则加入结果 + if ($hasValidInvestDate || $allInvestDatesNull) { + $filteredCompanies[] = $company; + } + } + $companies = collect($filteredCompanies); + + // 返回结果 + if ($retList) { + return $companies->values(); + } else { + return $companies->count(); + } + } + + /** + * 今年被投企业统计(统计或列表)- 按年份范围统计 + * @param string|null $start_date 开始日期 + * @param string|null $end_date 结束日期 + * @param array|null $course_ids 课程ID数组,不传则统计所有课程 + * @param bool $retList 是否返回列表,false返回数量,true返回列表(包含学员、课程信息) + * @return int|array + */ + public static function companyInvestedYear($start_date = null, $end_date = null, $retList = false) + { + // 计算年份范围 + $years = []; + if ($start_date && $end_date) { + // 从开始和结束日期中提取年份范围 + $startYear = (int) date('Y', strtotime($start_date)); + $endYear = (int) date('Y', strtotime($end_date)); + // 生成所有年份的数组 + for ($year = $startYear; $year <= $endYear; $year++) { + $years[] = $year; + } + } else { + // 如果没有提供日期,使用当前年份 + $years[] = (int) date('Y'); + } + + // 获取这些公司中标记为被投的公司 + $allInvestedCompanies = Company::where('is_yh_invested', 1)->get(); + // 筛选出被投时间在年份范围内的企业 + $companies = []; + foreach ($allInvestedCompanies as $company) { + $projectUsers = $company->project_users ?? []; + $hasInvestInYears = false; + foreach ($projectUsers as $item) { + $investDate = $item['investDate'] ?? null; + if ($investDate) { + $investYear = (int) date('Y', strtotime($investDate)); + if (in_array($investYear, $years)) { + $hasInvestInYears = true; + break; + } + } + } + if ($hasInvestInYears) { + $companies[$company->id] = $company; + } + } + $companies = collect($companies); + // 返回结果 + if ($retList) { + return $companies->values(); + } else { + return $companies->count(); + } + } + + } diff --git a/app/Models/CourseSign.php b/app/Models/CourseSign.php index cc97210..a522f58 100755 --- a/app/Models/CourseSign.php +++ b/app/Models/CourseSign.php @@ -296,15 +296,15 @@ class CourseSign extends SoftDeletesModel $years = []; if ($start_date && $end_date) { // 从开始和结束日期中提取年份范围 - $startYear = (int)date('Y', strtotime($start_date)); - $endYear = (int)date('Y', strtotime($end_date)); + $startYear = (int) date('Y', strtotime($start_date)); + $endYear = (int) date('Y', strtotime($end_date)); // 生成所有年份的数组 for ($year = $startYear; $year <= $endYear; $year++) { $years[] = $year; } } else { // 如果没有提供日期,使用当前年份 - $years[] = (int)date('Y'); + $years[] = (int) date('Y'); } // 获取这些公司中标记为被投的公司 @@ -320,7 +320,7 @@ class CourseSign extends SoftDeletesModel foreach ($projectUsers as $item) { $investDate = $item['investDate'] ?? null; if ($investDate) { - $investYear = (int)date('Y', strtotime($investDate)); + $investYear = (int) date('Y', strtotime($investDate)); if (in_array($investYear, $years)) { $hasInvestInYears = true; break; @@ -468,30 +468,47 @@ class CourseSign extends SoftDeletesModel public static function companyInvestedAfterEnrollment($start_date, $end_date, $course_ids = null, $retList = false) { $courseSignsQuery = self::getStudentList($start_date, $end_date, 1, $course_ids); - $courseSignsForInvest = $courseSignsQuery->with('user.company')->get(); + $courseSignsForInvest = $courseSignsQuery->with(['user.company', 'course'])->get(); $companiesAfterEnrollment = []; foreach ($courseSignsForInvest as $sign) { if ($sign->user && $sign->user->company && $sign->user->company->is_yh_invested == 1) { - $signDate = \Carbon\Carbon::parse($sign->created_at)->format('Y-m-d'); - // 从 project_users 中获取最早的被投时间 + // 使用课程开课时间作为入学时间 + $enrollmentDate = null; + if ($sign->course && $sign->course->start_date) { + $enrollmentDate = \Carbon\Carbon::parse($sign->course->start_date)->format('Y-m-d'); + } + + // 如果没有开课时间,跳过这条记录 + if (!$enrollmentDate) { + continue; + } + + // 从 project_users 中检查是否有任何一个被投时间 >= 课程开课时间 $projectUsers = $sign->user->company->project_users; + $hasInvestAfterEnrollment = false; $investDate = null; if (!empty($projectUsers) && is_array($projectUsers)) { foreach ($projectUsers as $projectUser) { if (!empty($projectUser['investDate'])) { - if ($investDate === null || $projectUser['investDate'] < $investDate) { - $investDate = $projectUser['investDate']; + $currentInvestDate = $projectUser['investDate']; + // 只要有一个被投时间 >= 课程开课时间,就满足条件 + if ($currentInvestDate >= $enrollmentDate) { + $hasInvestAfterEnrollment = true; + // 记录满足条件的被投时间(如果有多个,记录最早的) + if ($investDate === null || $currentInvestDate < $investDate) { + $investDate = $currentInvestDate; + } } } } } - // 被投时间 >= 报名时间,说明是入学后被投 - if ($investDate && $investDate >= $signDate) { + // 只要有一个被投时间 >= 课程开课时间,说明是入学后被投 + if ($hasInvestAfterEnrollment && $investDate) { $companyId = $sign->user->company->id; if (!isset($companiesAfterEnrollment[$companyId])) { $companiesAfterEnrollment[$companyId] = [ 'company' => $sign->user->company, - 'first_sign_date' => $signDate, + 'first_sign_date' => $enrollmentDate, 'invest_date' => $investDate, 'users' => [], ];