diff --git a/app/Http/Controllers/Admin/OtherController.php b/app/Http/Controllers/Admin/OtherController.php index 372db79..663a4b7 100755 --- a/app/Http/Controllers/Admin/OtherController.php +++ b/app/Http/Controllers/Admin/OtherController.php @@ -258,18 +258,28 @@ class OtherController extends CommonController $courseType->course_signs_total = $courseType->history_course_signs_total + $courseType->now_course_signs_total; } + // 统计 is_chart=0 的课程类型数据,组成"其他"统计项 + $otherCourseType = CourseType::getOtherStatistics($configStartDate, $configEndDate); + + // 将"其他"添加到 courseTypes 集合中 + $courseTypes->push($otherCourseType); + // 将统计数据直接组合到配置对象中 $config->courseTypes = $courseTypes; - // 总期数 + // 总期数(包含"其他") $config->course_periods_total = $courseTypes->sum('course_periods_total'); - // 总去重人数 + // 总去重人数(包含"其他") $coursesAll = Course::whereIn('type', $allCourseTypes->pluck('id')) ->where('is_chart', 1) ->where(function ($query) use ($configStartDate, $configEndDate) { $query->whereBetween('start_date', [$configStartDate, $configEndDate]) ->orWhereBetween('end_date', [$configStartDate, $configEndDate]); })->get(); - $config->course_signs_unique_total = $courseTypes->sum('history_course_signs_total') + CourseSign::courseSignsTotalByUnique($configStartDate, $configEndDate, 1, $coursesAll->pluck('id'), false, false); + + // 获取"其他"课程类型的课程ID列表 + $otherCourseIds = CourseType::getOtherCourseIds($configStartDate, $configEndDate); + + $config->course_signs_unique_total = $courseTypes->sum('history_course_signs_total') + CourseSign::courseSignsTotalByUnique($configStartDate, $configEndDate, 1, $coursesAll->pluck('id')->merge($otherCourseIds), false, false); } return $this->success(compact('list', 'suzhou', 'country', 'monthCourses', 'time_axis', 'article', 'yearConfigs')); @@ -378,7 +388,7 @@ class OtherController extends CommonController // 被投企业数 'yh_invested_total' => CourseSign::yhInvested($start_date, $end_date, [$course->id]), // 元禾同事数 - 'company_join_total' => CourseSign::companyJoin($start_date, $end_date, [$course->id], false, false, false), + 'company_join_total' => CourseSign::companyJoin($start_date, $end_date, [$course->id], false, false), ]; } } @@ -415,10 +425,13 @@ class OtherController extends CommonController // 区域明细统计 $areas = CourseSign::area($start_date, $end_date, 1, $courses->pluck('id'), true); + // 校友的区域明细统计 + $areas_schoolmate = CourseSign::area($start_date, $end_date, 1, $courses->pluck('id'), true, true); + // 获取统计项元数据 $statistics_metadata = Course::getStatisticsMetadata(); - return $this->success(compact('list', 'courseTypesSum', 'areas', 'statistics_metadata')); + return $this->success(compact('list', 'courseTypesSum', 'areas', 'areas_schoolmate', 'statistics_metadata')); } /** @@ -462,107 +475,119 @@ class OtherController extends CommonController // 被投企业明细 - 使用与coursesHome相同的算法 // 确保 $course_ids 是数组格式 $courseIdsArray = $course_ids ? (is_array($course_ids) ? $course_ids : $course_ids->toArray()) : null; - $companies = CourseSign::yhInvestedTotal(CourseType::START_DATE, $end_date, $courseIdsArray, true); - foreach ($companies as $company) { - // 获取该公司的学员信息 - // 使用与yhInvestedTotal相同的筛选逻辑:status=1,筛选course_ids和日期范围 - // 直接通过公司ID查询学员 - $userIds = User::where('company_id', $company->id)->pluck('id')->toArray(); - - // 公司基本信息 - $companyInfo = [ - 'company_name' => $company->company_name, - 'company_legal_representative' => $company->company_legal_representative ?? '', - 'company_date' => $company->company_date ?? '', - 'company_address' => $company->company_address ?? '', - 'business_scope' => $company->business_scope ?? '', - 'contact_phone' => $company->contact_phone ?? '', - 'contact_mail' => $company->contact_mail ?? '', - 'company_tag' => $company->company_tag ?? '', - // 'credit_code' => ($company->credit_code ? ' ' . $company->credit_code : ''), - ]; - if (empty($userIds)) { - // 如果没有学员,仍然导出公司基本信息 - $data[] = array_merge($companyInfo, [ - 'user_name' => '', - 'course_names' => '', - 'course_types' => '', - 'course_count' => 0, - ]); - } else { - $userCourseSigns = CourseSign::getStudentList(CourseType::START_DATE, $end_date, 1, $courseIdsArray) - ->whereIn('user_id', $userIds) - ->with(['user', 'course.typeDetail']) - ->get(); + // 辅助函数:构建被投企业数据 + $buildInvestedCompanyData = function ($start_date, $end_date, $courseIdsArray) { + $data = []; + $companies = CourseSign::yhInvestedTotal($start_date, $end_date, $courseIdsArray, true); + + foreach ($companies as $company) { + // 获取该公司的学员信息 + $userIds = User::where('company_id', $company->id)->pluck('id')->toArray(); + + // 公司基本信息 + $companyInfo = [ + 'company_name' => $company->company_name, + 'company_legal_representative' => $company->company_legal_representative ?? '', + 'company_date' => $company->company_date ?? '', + 'company_address' => $company->company_address ?? '', + 'business_scope' => $company->business_scope ?? '', + 'contact_phone' => $company->contact_phone ?? '', + 'contact_mail' => $company->contact_mail ?? '', + 'company_tag' => $company->company_tag ?? '', + ]; - // 按学员分组 - $usersData = []; - foreach ($userCourseSigns as $sign) { - if (!$sign->user) { - continue; + if (empty($userIds)) { + // 如果没有学员,仍然导出公司基本信息 + $data[] = array_merge($companyInfo, [ + 'user_name' => '', + 'course_names' => '', + 'course_types' => '', + 'course_count' => 0, + ]); + } else { + $userCourseSigns = CourseSign::getStudentList($start_date, $end_date, 1, $courseIdsArray) + ->whereIn('user_id', $userIds) + ->with(['user', 'course.typeDetail']) + ->get(); + + // 按学员分组 + $usersData = []; + foreach ($userCourseSigns as $sign) { + if (!$sign->user) { + continue; + } + $userId = $sign->user_id; + if (!isset($usersData[$userId])) { + $usersData[$userId] = [ + 'user' => $sign->user, + 'courseSigns' => [], + ]; + } + $usersData[$userId]['courseSigns'][] = $sign; } - $userId = $sign->user_id; - if (!isset($usersData[$userId])) { - $usersData[$userId] = [ - 'user' => $sign->user, - 'courseSigns' => [], - ]; + + // 每个学员一行,公司信息只在第一行显示,后续行公司信息为空 + $isFirstRow = true; + foreach ($usersData as $userData) { + $user = $userData['user']; + $courseSigns = collect($userData['courseSigns']); + + if ($courseSigns->isNotEmpty()) { + // 获取课程名称列表,用中文顿号分隔 + $courseNames = $courseSigns->pluck('course.name')->filter()->unique()->values()->implode('、'); + + // 获取课程体系列表,用中文顿号分隔 + $courseTypes = $courseSigns->pluck('course.typeDetail.name') + ->filter() + ->unique() + ->values() + ->implode('、'); + + // 报名课程数 + $courseCount = $courseSigns->count(); + + if ($isFirstRow) { + // 第一行:显示公司信息 + $data[] = array_merge($companyInfo, [ + 'user_name' => $user->name ?? '', + 'course_names' => $courseNames, + 'course_types' => $courseTypes, + 'course_count' => $courseCount, + ]); + $isFirstRow = false; + } else { + // 后续行:公司信息为空 + $data[] = [ + 'company_name' => '', + 'company_legal_representative' => '', + 'company_date' => '', + 'company_address' => '', + 'business_scope' => '', + 'contact_phone' => '', + 'contact_mail' => '', + 'company_tag' => '', + 'credit_code' => '', + 'user_name' => $user->name ?? '', + 'course_names' => $courseNames, + 'course_types' => $courseTypes, + 'course_count' => $courseCount, + ]; + } + } } - $usersData[$userId]['courseSigns'][] = $sign; } + } - // 每个学员一行,公司信息只在第一行显示,后续行公司信息为空 - $isFirstRow = true; - foreach ($usersData as $userData) { - $user = $userData['user']; - $courseSigns = collect($userData['courseSigns']); - - if ($courseSigns->isNotEmpty()) { - // 获取课程名称列表,用中文顿号分隔 - $courseNames = $courseSigns->pluck('course.name')->filter()->unique()->values()->implode('、'); + return $data; + }; - // 获取课程体系列表,用中文顿号分隔 - $courseTypes = $courseSigns->pluck('course.typeDetail.name') - ->filter() - ->unique() - ->values() - ->implode('、'); + // 第一个 sheet:累计被投企业覆盖数(从 CourseType::START_DATE 开始) + $cumulativeData = $buildInvestedCompanyData(CourseType::START_DATE, $end_date, $courseIdsArray); - // 报名课程数 - $courseCount = $courseSigns->count(); + // 第二个 sheet:当前被投企业覆盖数(从传入的开始日期开始) + $currentData = $buildInvestedCompanyData($start_date, $end_date, $courseIdsArray); - if ($isFirstRow) { - // 第一行:显示公司信息 - $data[] = array_merge($companyInfo, [ - 'user_name' => $user->name ?? '', - 'course_names' => $courseNames, - 'course_types' => $courseTypes, - 'course_count' => $courseCount, - ]); - $isFirstRow = false; - } else { - // 后续行:公司信息为空 - $data[] = [ - 'company_name' => '', - 'company_legal_representative' => '', - 'company_date' => '', - 'company_address' => '', - 'business_scope' => '', - 'contact_phone' => '', - 'contact_mail' => '', - 'company_tag' => '', - 'credit_code' => '', - 'user_name' => $user->name ?? '', - 'course_names' => $courseNames, - 'course_types' => $courseTypes, - 'course_count' => $courseCount, - ]; - } - } - } - } - } $fields = [ 'company_name' => '企业名称', 'company_legal_representative' => '法人', @@ -572,13 +597,25 @@ class OtherController extends CommonController 'contact_phone' => '联系电话', 'contact_mail' => '联系邮箱', 'company_tag' => '企业资质', - // 'credit_code' => '统一社会信用代码', 'user_name' => '学员姓名', 'course_names' => '课程名称', 'course_types' => '课程体系', 'course_count' => '报名课程数', ]; + + // 创建多 sheet 导出 + $sheets = [ + new SheetExport($cumulativeData, $fields, '被投企业覆盖数'), + new SheetExport($currentData, $fields, '当前被投企业覆盖数'), + ]; + $filename = '被投企业明细'; + + // 直接返回多 sheet 导出 + return Excel::download( + new MultiSheetExport($sheets), + $filename . '_' . date('YmdHis') . '.xlsx' + ); break; case 'course_signs_total': @@ -843,7 +880,7 @@ class OtherController extends CommonController $query->whereBetween('start_date', [$start_date, $end_date]) ->orWhereBetween('end_date', [$start_date, $end_date]); } - })->orderBy('start_date', 'asc')->get(); + })->where('is_chart', 1)->orderBy('start_date', 'asc')->get(); foreach ($courses2 as $course) { $data[] = [ 'course_type' => $courseType->name, @@ -1349,23 +1386,36 @@ class OtherController extends CommonController case 'company_invested_after_enrollment_total': // 入学后被投企业明细 - 使用模型方法 - $companiesAfterEnrollment = CourseSign::companyInvestedAfterEnrollment($start_date, $end_date, $course_ids, true); + // 辅助函数:构建入学后被投企业数据 + $buildAfterEnrollmentData = function ($start_date, $end_date, $course_ids) { + $data = []; + $companiesAfterEnrollment = CourseSign::companyInvestedAfterEnrollment($start_date, $end_date, $course_ids, true); + + foreach ($companiesAfterEnrollment as $item) { + $company = $item['company']; + $userNames = collect($item['users'])->pluck('name')->filter()->unique()->implode("\n\r"); + $data[] = [ + 'company_name' => $company->company_name, + 'company_legal_representative' => $company->company_legal_representative ?? '', + 'company_date' => $company->company_date ?? '', + 'invest_date' => $item['invest_date'] ?? '', + 'first_sign_date' => $item['first_enrollment_date'] ?? '', + 'user_names' => $userNames, + 'company_address' => $company->company_address ?? '', + 'company_city' => $company->company_city ?? '', + 'company_area' => $company->company_area ?? '', + ]; + } + + return $data; + }; + + // 第一个 sheet:当前入学后被投企业(从传入的开始日期开始) + $currentData = $buildAfterEnrollmentData($start_date, $end_date, $course_ids); + + // 第二个 sheet:累计入学后被投企业(从 CourseType::START_DATE 开始) + $cumulativeData = $buildAfterEnrollmentData(CourseType::START_DATE, $end_date, $course_ids); - foreach ($companiesAfterEnrollment as $item) { - $company = $item['company']; - $userNames = collect($item['users'])->pluck('name')->filter()->unique()->implode("\n\r"); - $data[] = [ - 'company_name' => $company->company_name, - 'company_legal_representative' => $company->company_legal_representative ?? '', - 'company_date' => $company->company_date ?? '', - 'invest_date' => $item['invest_date'] ?? '', - 'first_sign_date' => $item['first_enrollment_date'] ?? '', - 'user_names' => $userNames, - 'company_address' => $company->company_address ?? '', - 'company_city' => $company->company_city ?? '', - 'company_area' => $company->company_area ?? '', - ]; - } $fields = [ 'company_name' => '企业名称', 'company_legal_representative' => '法人', @@ -1377,7 +1427,20 @@ class OtherController extends CommonController 'company_city' => '所在城市', 'company_area' => '所在区域', ]; + + // 创建多 sheet 导出 + $sheets = [ + new SheetExport($currentData, $fields, '当前入学后被投企业'), + new SheetExport($cumulativeData, $fields, '累计入学后被投企业'), + ]; + $filename = '入学后被投企业明细'; + + // 直接返回多 sheet 导出 + return Excel::download( + new MultiSheetExport($sheets), + $filename . '_' . date('YmdHis') . '.xlsx' + ); break; case 'company_invested_year_total': diff --git a/app/Models/CourseSign.php b/app/Models/CourseSign.php index ebfeaff..3f4fe69 100755 --- a/app/Models/CourseSign.php +++ b/app/Models/CourseSign.php @@ -221,25 +221,6 @@ class CourseSign extends SoftDeletesModel $companies = Company::approvedStudents()->whereHas('users', function ($query) use ($userIds) { $query->whereIn('id', $userIds); })->where('is_yh_invested', 1)->get(); - // 自定义时间:需要按被投时间筛选 - if (!$isDefaultDate) { - $startDate = substr($start_date, 0, 10); - $endDate = substr($end_date, 0, 10); - // 筛选出被投时间在范围内的企业 - $filteredCompanies = []; - foreach ($companies as $company) { - $projectUsers = $company->project_users ?? []; - foreach ($projectUsers as $item) { - $investDate = $item['investDate'] ?? null; - // 检查被投时间是否在范围内 - if ($investDate && $investDate >= $startDate && $investDate <= $endDate) { - $filteredCompanies[] = $company; - break; // 只要有一条满足就加入 - } - } - } - $companies = collect($filteredCompanies); - } // 返回结果 if ($retList) { @@ -551,11 +532,19 @@ class CourseSign extends SoftDeletesModel * @param string $end_date 结束日期 * @param array|null $course_ids 课程ID数组,不传则统计所有课程 * @param bool $retList 是否返回列表,false返回详情,true返回列表 + * @param bool $is_schoolmate 是否只统计校友,false统计所有,true只统计校友 */ - public static function area($start_date, $end_date, $status = null, $course_ids = null, $retList = false) + public static function area($start_date, $end_date, $status = null, $course_ids = null, $retList = false, $is_schoolmate = false) { $courseSignList = self::getStudentList($start_date, $end_date, $status, $course_ids); + // 如果只统计校友,添加校友筛选条件 + if ($is_schoolmate) { + $courseSignList->whereHas('user', function ($query) { + $query->where('is_schoolmate', 1); + }); + } + // 地区 $suzhouArea = Company::approvedStudents()->where('company_city', '苏州市')->pluck('company_area')->unique(); $list = []; diff --git a/app/Models/CourseType.php b/app/Models/CourseType.php index 9354b6f..97d6d4e 100755 --- a/app/Models/CourseType.php +++ b/app/Models/CourseType.php @@ -23,5 +23,94 @@ class CourseType extends SoftDeletesModel return $this->hasMany(Course::class, 'type', 'id'); } + /** + * 获取"其他"统计项(is_chart=0 的课程类型合并统计) + * @param string $startDate 开始日期 + * @param string $endDate 结束日期 + * @return CourseType + */ + public static function getOtherStatistics($startDate, $endDate) + { + // 获取所有 is_chart=0 的课程类型 + $otherCourseTypes = self::where('is_chart', 0) + ->where('is_history', 0) + ->get(); + + $otherCourseTypeIds = $otherCourseTypes->pluck('id')->toArray(); + + // 如果没有"其他"课程类型,返回空统计 + if (empty($otherCourseTypeIds)) { + $otherCourseType = new self(); + $otherCourseType->id = 0; + $otherCourseType->name = '其他'; + $otherCourseType->history_course_periods_total = 0; + $otherCourseType->now_course_periods_total = 0; + $otherCourseType->history_course_signs_total = 0; + $otherCourseType->now_course_signs_total = 0; + $otherCourseType->course_periods_total = 0; + $otherCourseType->course_signs_total = 0; + return $otherCourseType; + } + + // 历史课程数据(所有 is_chart=0 的课程类型) + $otherHistoryCourse = HistoryCourse::whereIn('type', $otherCourseTypeIds) + ->where(function ($query) use ($startDate, $endDate) { + $query->whereBetween('start_time', [$startDate, $endDate]) + ->orWhereBetween('end_time', [$startDate, $endDate]); + })->get(); + + // 实际课程数据(所有 is_chart=0 的课程类型下的课程) + $otherCourses = Course::whereIn('type', $otherCourseTypeIds)->where('is_chart', 1) + ->where(function ($query) use ($startDate, $endDate) { + $query->whereBetween('start_date', [$startDate, $endDate]) + ->orWhereBetween('end_date', [$startDate, $endDate]); + })->get(); + + $otherHistoryCoursePeriodsTotal = $otherHistoryCourse->count(); + $otherNowCoursePeriodsTotal = $otherCourses->count(); + $otherHistoryCourseSignsTotal = $otherHistoryCourse->sum('course_type_signs_pass_unique'); + $otherNowCourseSignsTotal = CourseSign::courseSignsTotalByUnique($startDate, $endDate, 1, $otherCourses->pluck('id'), false, false); + + // 创建"其他"统计项 + $otherCourseType = new self(); + $otherCourseType->id = 0; + $otherCourseType->name = '其他'; + $otherCourseType->history_course_periods_total = $otherHistoryCoursePeriodsTotal; + $otherCourseType->now_course_periods_total = $otherNowCoursePeriodsTotal; + $otherCourseType->history_course_signs_total = $otherHistoryCourseSignsTotal; + $otherCourseType->now_course_signs_total = $otherNowCourseSignsTotal; + $otherCourseType->course_periods_total = $otherCourseType->now_course_periods_total + $otherCourseType->history_course_periods_total; + $otherCourseType->course_signs_total = $otherCourseType->history_course_signs_total + $otherCourseType->now_course_signs_total; + + return $otherCourseType; + } + + /** + * 获取"其他"课程类型的课程ID列表(用于计算总去重人数) + * @param string $startDate 开始日期 + * @param string $endDate 结束日期 + * @return \Illuminate\Support\Collection + */ + public static function getOtherCourseIds($startDate, $endDate) + { + // 获取所有 is_chart=0 的课程类型ID + $otherCourseTypeIds = self::where('is_chart', 0) + ->where('is_history', 0) + ->pluck('id')->toArray(); + + if (empty($otherCourseTypeIds)) { + return collect([]); + } + + // 获取"其他"课程类型的课程数据 + $otherCoursesAll = Course::whereIn('type', $otherCourseTypeIds) + ->where('is_chart', 1) + ->where(function ($query) use ($startDate, $endDate) { + $query->whereBetween('start_date', [$startDate, $endDate]) + ->orWhereBetween('end_date', [$startDate, $endDate]); + })->get(); + + return $otherCoursesAll->pluck('id'); + } }