diff --git a/app/Http/Controllers/Admin/CompanyController.php b/app/Http/Controllers/Admin/CompanyController.php index 3738eb6..8ee3b8b 100644 --- a/app/Http/Controllers/Admin/CompanyController.php +++ b/app/Http/Controllers/Admin/CompanyController.php @@ -111,10 +111,12 @@ class CompanyController extends BaseController * @OA\Parameter(name="end_year", in="query", @OA\Schema(type="string"), required=false, description="结束年份"), * @OA\Parameter(name="start_date", in="query", @OA\Schema(type="string"), required=false, description="开始日期(用于统计)"), * @OA\Parameter(name="end_date", in="query", @OA\Schema(type="string"), required=false, description="结束日期(用于统计)"), - * @OA\Parameter(name="course_type_id", in="query", @OA\Schema(type="string"), required=true, description="课程体系id"), - * @OA\Parameter(name="course_name", in="query", @OA\Schema(type="string"), required=true, description="课程名称"), - * @OA\Parameter(name="user_name", in="query", @OA\Schema(type="string"), required=true, description="学员名称"), - * @OA\Parameter(name="is_schoolmate", in="query", @OA\Schema(type="string"), required=true, description="是否校友0否1是"), + * @OA\Parameter(name="course_type_id", in="query", @OA\Schema(type="string"), required=false, description="课程体系id"), + * @OA\Parameter(name="course_name", in="query", @OA\Schema(type="string"), required=false, description="课程名称"), + * @OA\Parameter(name="user_name", in="query", @OA\Schema(type="string"), required=false, description="学员名称"), + * @OA\Parameter(name="is_schoolmate", in="query", @OA\Schema(type="string"), required=false, description="是否校友0否1是"), + * @OA\Parameter(name="course_start_date", in="query", @OA\Schema(type="string"), required=false, description="课程开始日期(筛选课程起止时间在范围内的企业)"), + * @OA\Parameter(name="course_end_date", in="query", @OA\Schema(type="string"), required=false, description="课程结束日期(筛选课程起止时间在范围内的企业)"), * @OA\Response( * response="200", * description="暂无" @@ -134,20 +136,41 @@ class CompanyController extends BaseController })->with('courseSigns.course'); } ])->whereHas('users', function ($query) use ($all) { - if (isset($all['course_type_id'])) { + if (isset($all['course_type_id']) && !empty($all['course_type_id'])) { $query->whereHas('courses', function ($q) use ($all) { $q->where('type', $all['course_type_id']); }); } - if (isset($all['course_name'])) { + if (isset($all['course_name']) && !empty($all['course_name'])) { $query->whereHas('courses', function ($q) use ($all) { $q->where('name', 'like', '%' . $all['course_name'] . '%'); }); } - if (isset($all['user_name'])) { + // 课程起止时间筛选 + if ((isset($all['course_start_date']) && !empty($all['course_start_date'])) || + (isset($all['course_end_date']) && !empty($all['course_end_date']))) { + $query->whereHas('courses', function ($q) use ($all) { + $course_start_date = $all['course_start_date'] ?? null; + $course_end_date = $all['course_end_date'] ?? null; + if ($course_start_date && $course_end_date) { + // 课程开始时间或结束时间在指定时间范围内 + $q->where(function ($subQuery) use ($course_start_date, $course_end_date) { + $subQuery->whereBetween('start_date', [$course_start_date, $course_end_date]) + ->orWhereBetween('end_date', [$course_start_date, $course_end_date]); + }); + } elseif ($course_start_date) { + // 只指定开始日期,筛选课程结束时间 >= 开始日期 + $q->where('end_date', '>=', $course_start_date); + } elseif ($course_end_date) { + // 只指定结束日期,筛选课程开始时间 <= 结束日期 + $q->where('start_date', '<=', $course_end_date); + } + }); + } + if (isset($all['user_name']) && !empty($all['user_name'])) { $query->where('username', 'like', '%' . $all['user_name'] . '%'); } - if (isset($all['is_schoolmate'])) { + if (isset($all['is_schoolmate']) && $all['is_schoolmate'] !== '') { $query->where('is_schoolmate', $all['is_schoolmate']); } })->where(function ($query) use ($all, $start_year, $end_year) { diff --git a/app/Http/Controllers/Admin/CourseController.php b/app/Http/Controllers/Admin/CourseController.php index 2ecc06c..6854257 100755 --- a/app/Http/Controllers/Admin/CourseController.php +++ b/app/Http/Controllers/Admin/CourseController.php @@ -63,119 +63,155 @@ class CourseController extends BaseController $query->whereNotIn('status', [4, 5]); } ])->withCount([ - 'courseSigns as sign_pass_total' => function ($query) { - $query->where('status', 1)->whereHas('user'); - } - ])->withCount([ - 'courseSigns as sign_wait_total' => function ($query) { - $query->where('status', 0)->whereHas('user'); - } - ])->withCount([ - 'courseSigns as sign_fault_total' => function ($query) { - $query->where('status', 2)->whereHas('user'); - } - ])->withCount([ - 'courseSigns as sign_prepare_total' => function ($query) { - $query->where('status', 3)->whereHas('user'); - } - ])->withCount([ - 'courseSigns as sign_cancel_total' => function ($query) { - $query->where('status', 4)->whereHas('user'); - } - ])->withCount([ - 'courseSigns as sign_give_up_total' => function ($query) { - $query->where('status', 5)->whereHas('user'); - } - ])->withCount([ - 'courseSigns as sign_black_total' => function ($query) { - $query->where('status', 6)->whereHas('user'); - } - ])->where(function ($query) use ($all) { - if (isset($all['has_course_forms']) && !empty($all['has_course_forms'])) { - $query->whereHas('courseForms'); - } - if (isset($all['start_date'])) { - $query->where('start_date', '>=', $all['start_date']); - } - if (isset($all['end_date'])) { - $query->where('end_date', '<=', $all['end_date']); - } - if (isset($all['course_type_id'])) { - $course_type_id = explode(',', $all['course_type_id']); - $query->whereIn('type', $course_type_id); - } - if (isset($all['filter']) && !empty($all['filter'])) { - foreach ($all['filter'] as $condition) { - $key = $condition['key'] ?? null; - $op = $condition['op'] ?? null; - $value = $condition['value'] ?? null; - if (!isset($key) || !isset($op) || !isset($value)) { - continue; - } - if ($key == 'start_date') { - list($from, $to) = explode(',', $value); - $query->where(function ($q) use ($from, $to) { - $q->whereBetween('start_date', [$from, $to])->orWhereBetween('end_date', [$from, $to]); - }); - continue; - } - - // 等于 - if ($op == 'eq') { - $query->where($key, $value); - } - // 不等于 - if ($op == 'neq') { - $query->where($key, '!=', $value); - } - // 大于 - if ($op == 'gt') { - $query->where($key, '>', $value); - } - // 大于等于 - if ($op == 'egt') { - $query->where($key, '>=', $value); - } - // 小于 - if ($op == 'lt') { - $query->where($key, '<', $value); - } - // 小于等于 - if ($op == 'elt') { - $query->where($key, '<=', $value); - } - // 模糊搜索 - if ($op == 'like') { - $query->where($key, 'like', '%' . $value . '%'); - } - // 否定模糊搜索 - if ($op == 'notlike') { - $query->where($key, 'not like', '%' . $value . '%'); - } - // 范围搜索 - if ($op == 'range') { - list($from, $to) = explode(',', $value); - if (empty($from) || empty($to)) { + 'courseSigns as sign_pass_total' => function ($query) { + $query->where('status', 1)->whereHas('user'); + } + ])->withCount([ + 'courseSigns as sign_wait_total' => function ($query) { + $query->where('status', 0)->whereHas('user'); + } + ])->withCount([ + 'courseSigns as sign_fault_total' => function ($query) { + $query->where('status', 2)->whereHas('user'); + } + ])->withCount([ + 'courseSigns as sign_prepare_total' => function ($query) { + $query->where('status', 3)->whereHas('user'); + } + ])->withCount([ + 'courseSigns as sign_cancel_total' => function ($query) { + $query->where('status', 4)->whereHas('user'); + } + ])->withCount([ + 'courseSigns as sign_give_up_total' => function ($query) { + $query->where('status', 5)->whereHas('user'); + } + ])->withCount([ + 'courseSigns as sign_black_total' => function ($query) { + $query->where('status', 6)->whereHas('user'); + } + ])->where(function ($query) use ($all) { + if (isset($all['has_course_forms']) && !empty($all['has_course_forms'])) { + $query->whereHas('courseForms'); + } + if (isset($all['start_date'])) { + $query->where('start_date', '>=', $all['start_date']); + } + if (isset($all['end_date'])) { + $query->where('end_date', '<=', $all['end_date']); + } + if (isset($all['course_type_id'])) { + $course_type_id = explode(',', $all['course_type_id']); + $query->whereIn('type', $course_type_id); + } + if (isset($all['filter']) && !empty($all['filter'])) { + foreach ($all['filter'] as $condition) { + $key = $condition['key'] ?? null; + $op = $condition['op'] ?? null; + $value = $condition['value'] ?? null; + if (!isset($key) || !isset($op) || !isset($value)) { continue; } - $query->whereBetween($key, [$from, $to]); - } - if ($op == 'in') { - $array = explode(',', $value); - $query->whereIn($key, $array); + if ($key == 'start_date') { + list($from, $to) = explode(',', $value); + $query->where(function ($q) use ($from, $to) { + $q->whereBetween('start_date', [$from, $to])->orWhereBetween('end_date', [$from, $to]); + }); + continue; + } + + // 等于 + if ($op == 'eq') { + $query->where($key, $value); + } + // 不等于 + if ($op == 'neq') { + $query->where($key, '!=', $value); + } + // 大于 + if ($op == 'gt') { + $query->where($key, '>', $value); + } + // 大于等于 + if ($op == 'egt') { + $query->where($key, '>=', $value); + } + // 小于 + if ($op == 'lt') { + $query->where($key, '<', $value); + } + // 小于等于 + if ($op == 'elt') { + $query->where($key, '<=', $value); + } + // 模糊搜索 + if ($op == 'like') { + $query->where($key, 'like', '%' . $value . '%'); + } + // 否定模糊搜索 + if ($op == 'notlike') { + $query->where($key, 'not like', '%' . $value . '%'); + } + // 范围搜索 + if ($op == 'range') { + list($from, $to) = explode(',', $value); + if (empty($from) || empty($to)) { + continue; + } + $query->whereBetween($key, [$from, $to]); + } + if ($op == 'in') { + $array = explode(',', $value); + $query->whereIn($key, $array); + } } } - } - }); + }); $list = $list->orderBy($all['sort_name'] ?? 'sign_status', $all['sort_type'] ?? 'asc'); if (isset($all['is_export']) && !empty($all['is_export'])) { $list = $list->limit(5000)->get()->toArray(); return Excel::download(new CommonExport($list, $all['export_fields'] ?? ''), $all['file_name'] ?? '' . date('YmdHis') . '.xlsx'); } else { - // 输出 + // 在分页之前,克隆查询构建器用于计算总和 + $totalStatsQuery = clone $list; + + // 输出分页数据 $list = $list->paginate($all['page_size'] ?? 20); + + // 计算所有符合条件的数据的统计总和(不仅仅是当前页) + // 移除排序,获取所有数据 + $totalStatsQuery->getQuery()->orders = null; + + // 获取所有符合条件的数据并计算总和 + $allCourses = $totalStatsQuery->get(); + $totalStats = [ + 'course_signs_count' => 0, + 'sign_pass_total' => 0, + 'sign_wait_total' => 0, + 'sign_fault_total' => 0, + 'sign_prepare_total' => 0, + 'sign_cancel_total' => 0, + 'sign_give_up_total' => 0, + 'sign_black_total' => 0, + ]; + + foreach ($allCourses as $course) { + $totalStats['course_signs_count'] += $course->course_signs_count ?? 0; + $totalStats['sign_pass_total'] += $course->sign_pass_total ?? 0; + $totalStats['sign_wait_total'] += $course->sign_wait_total ?? 0; + $totalStats['sign_fault_total'] += $course->sign_fault_total ?? 0; + $totalStats['sign_prepare_total'] += $course->sign_prepare_total ?? 0; + $totalStats['sign_cancel_total'] += $course->sign_cancel_total ?? 0; + $totalStats['sign_give_up_total'] += $course->sign_give_up_total ?? 0; + $totalStats['sign_black_total'] += $course->sign_black_total ?? 0; + } + + // 将分页数据转换为数组,并在最外层追加统计总和 + $result = $list->toArray(); + $result['statistics_total'] = $totalStats; + + return $this->success($result); } - return $this->success($list); } /** diff --git a/app/Http/Controllers/Admin/OtherController.php b/app/Http/Controllers/Admin/OtherController.php index 0a707a2..f0dcf65 100755 --- a/app/Http/Controllers/Admin/OtherController.php +++ b/app/Http/Controllers/Admin/OtherController.php @@ -143,14 +143,13 @@ class OtherController extends CommonController // 全市干部参与企业 $list['company_ganbu_total'] = CourseSign::ganbu(); // 三个全覆盖 - // 苏州头部企业 + // 苏州苏州头部企业 $list['cover_head_total'] = CourseSign::toubuqiye(); - // 高层次人才 - // 获取人才培训课程 + // 苏州高层次人才 $list['cover_rencai_total'] = CourseSign::rencai(); - // 重点上市公司 + // 苏州重点上市公司 $list['cover_stock_total'] = CourseSign::shangshi(); - // 培养人次1 + // 培养人次 $start_date = CourseType::START_DATE; // 默认结束日期一年以后 $end_date = date('Y-m-d', strtotime('+10 year')); @@ -165,8 +164,8 @@ class OtherController extends CommonController ->where('start_time', 'like', '%' . date('Y-m') . '%') ->get(); - // 苏州区域数据 - 使用 CourseSign::area 方法实现数据一致 - $areasData = CourseSign::area($start_date, $end_date, null, null, true, true); + // 苏州区域数据 - 使用 CourseSign::getAreaData 方法实现数据一致 + $areasData = CourseSign::getAreaData($start_date, $end_date, 1, null, true, 'statistics'); $suzhou = []; foreach ($areasData as $item) { $suzhou[] = [ @@ -735,26 +734,8 @@ class OtherController extends CommonController // 当前课程数据(已去重) $currentData = []; foreach ($users as $user) { - // 获取该学员报名的课程列表 - 使用与getStudentList完全一致的逻辑 - $userCourseSigns = CourseSign::where(function ($query) use ($course_ids) { - // status = 1 - $query->where('status', 1); - // course_ids筛选 - if ($course_ids && $course_ids->isNotEmpty()) { - $query->whereIn('course_id', $course_ids); - } - }) - ->whereHas('course', function ($query) use ($start_date, $end_date) { - $query->where('is_chart', 1); - // 开始结束日期的筛选。or查询 - if ($start_date && $end_date) { - $query->where(function ($q) use ($start_date, $end_date) { - $q->whereBetween('start_date', [$start_date, $end_date]) - ->orWhereBetween('end_date', [$start_date, $end_date]); - }); - } - }) - ->whereNotIn('status', [4, 5, 6]) + // 获取该学员报名的课程列表 - 使用getStudentList方法确保与统计逻辑一致 + $userCourseSigns = CourseSign::getStudentList($start_date, $end_date, 1, $course_ids) ->where('user_id', $user->id) ->with(['course.typeDetail']) ->get(); @@ -933,130 +914,24 @@ class OtherController extends CommonController break; case 'areas': - // 区域明细 - 使用与coursesHome统计逻辑一致的CourseSign::area方法 + // 区域明细 - 使用 CourseSign::getAreaData 方法,统一统计和导出逻辑 // 第一个sheet:普通学员区域明细 - $courseSignList = CourseSign::getStudentList($start_date, $end_date, 1, $courses->pluck('id')); - - // 从数据字典获取区域列表(与CourseSign::area逻辑一致) - $suzhouAreas = ParameterDetail::where('parameter_id', 5) - ->where('status', 1) - ->orderBy('sort', 'asc') - ->pluck('value') - ->toArray(); - - $areasData = []; - foreach ($suzhouAreas as $area) { - // 按照CourseSign::area的逻辑获取该区域下的CourseSign - if ($area === '高新区') { - $areaCourseSigns = (clone $courseSignList)->whereHas('user', function ($query) { - $query->whereHas('company', function ($query) { - $query->where('company_city', '苏州市') - ->where(function ($q) { - $q->where('company_area', '高新区') - ->orWhere('company_area', '虎丘区'); - }); - }); - })->get(); - } elseif ($area === '苏州市外') { - // 苏州市外:统计除了苏州之外的所有数据 - $areaCourseSigns = (clone $courseSignList)->whereHas('user', function ($query) { - $query->whereHas('company', function ($query) { - $query->where('company_city', '!=', '苏州市'); - }); - })->get(); - } else { - // 其他区域:正常统计 - $areaCourseSigns = (clone $courseSignList)->whereHas('user', function ($query) use ($area) { - $query->whereHas('company', function ($query) use ($area) { - $query->where('company_city', '苏州市') - ->where('company_area', 'like', '%' . $area . '%'); - }); - })->get(); - } - - // 加载关联关系 - $areaCourseSigns->load(['user.company', 'course']); - - // 将该区域下的学员明细添加到导出数据 - foreach ($areaCourseSigns as $sign) { - $areasData[] = [ - 'area' => $area, - 'company_name' => $sign->user->company->company_name ?? '', - 'company_area' => $sign->user->company->company_area ?? '', - 'company_city' => $sign->user->company->company_city ?? '', - 'company_province' => $sign->user->company->company_province ?? '', - 'user_name' => $sign->user->name ?? '', - 'mobile' => $sign->user->mobile ?? '', - 'course_name' => $sign->course->name ?? '', - ]; - } - } + $areasData = CourseSign::getAreaData($start_date, $end_date, 1, $courses->pluck('id'), false, 'export'); $fields = [ - 'area' => '区域', 'company_name' => '企业名称', 'company_area' => '公司区域', 'company_city' => '公司城市', 'company_province' => '公司省份', + 'company_address' => '公司地址', 'user_name' => '学员姓名', 'mobile' => '手机号', + 'course_type' => '课程体系', 'course_name' => '课程名称', ]; - // 第二个sheet:校友区域明细 - 使用CourseSign::area方法,is_schoolmate=true - $courseSignListSchoolmate = CourseSign::getStudentList($start_date, $end_date, 1, $courses->pluck('id')); - // 添加校友筛选条件 - $courseSignListSchoolmate->whereHas('user', function ($query) { - $query->where('is_schoolmate', 1); - }); - - $areasSchoolmateData = []; - foreach ($suzhouAreas as $area) { - // 按照CourseSign::area的逻辑获取该区域下的CourseSign(校友) - if ($area === '高新区') { - $areaCourseSigns = (clone $courseSignListSchoolmate)->whereHas('user', function ($query) { - $query->whereHas('company', function ($query) { - $query->where('company_city', '苏州市') - ->where(function ($q) { - $q->where('company_area', '高新区') - ->orWhere('company_area', '虎丘区'); - }); - }); - })->get(); - } elseif ($area === '苏州市外') { - // 苏州市外:统计除了苏州之外的所有数据 - $areaCourseSigns = (clone $courseSignListSchoolmate)->whereHas('user', function ($query) { - $query->whereHas('company', function ($query) { - $query->where('company_city', '!=', '苏州市'); - }); - })->get(); - } else { - // 其他区域:正常统计 - $areaCourseSigns = (clone $courseSignListSchoolmate)->whereHas('user', function ($query) use ($area) { - $query->whereHas('company', function ($query) use ($area) { - $query->where('company_city', '苏州市') - ->where('company_area', 'like', '%' . $area . '%'); - }); - })->get(); - } - - // 加载关联关系 - $areaCourseSigns->load(['user.company', 'course']); - - // 将该区域下的校友明细添加到导出数据 - foreach ($areaCourseSigns as $sign) { - $areasSchoolmateData[] = [ - 'area' => $area, - 'company_name' => $sign->user->company->company_name ?? '', - 'company_area' => $sign->user->company->company_area ?? '', - 'company_city' => $sign->user->company->company_city ?? '', - 'company_province' => $sign->user->company->company_province ?? '', - 'user_name' => $sign->user->name ?? '', - 'mobile' => $sign->user->mobile ?? '', - 'course_name' => $sign->course->name ?? '', - ]; - } - } + // 第二个sheet:校友区域明细 + $areasSchoolmateData = CourseSign::getAreaData($start_date, $end_date, 1, $courses->pluck('id'), true, 'export'); $sheets = [ new SheetExport($areasData, $fields, '区域明细'), @@ -1183,26 +1058,8 @@ class OtherController extends CommonController // 跟班学员明细 - 使用模型方法 $users = CourseSign::genban($start_date, $end_date, $course_ids, true); foreach ($users as $user) { - // 获取该学员的课程报名记录 - $userCourseSigns = CourseSign::where(function ($query) use ($course_ids) { - // status = 1 - $query->where('status', 1); - // course_ids筛选 - if ($course_ids && $course_ids->isNotEmpty()) { - $query->whereIn('course_id', $course_ids); - } - }) - ->whereHas('course', function ($query) use ($start_date, $end_date) { - $query->where('is_chart', 1); - // 开始结束日期的筛选。or查询 - if ($start_date && $end_date) { - $query->where(function ($q) use ($start_date, $end_date) { - $q->whereBetween('start_date', [$start_date, $end_date]) - ->orWhereBetween('end_date', [$start_date, $end_date]); - }); - } - }) - ->whereNotIn('status', [4, 5, 6]) + // 获取该学员的课程报名记录 - 使用getStudentList方法确保与统计逻辑一致 + $userCourseSigns = CourseSign::getStudentList($start_date, $end_date, 1, $course_ids) ->where('user_id', $user->id) ->with(['course.typeDetail']) ->get(); @@ -1490,7 +1347,7 @@ class OtherController extends CommonController break; case 'company_invested_after_enrollment_total': - // 入学后被投企业明细 - 使用模型方法 + // 入学后被投企业明细 - 使用模型方法,与其他导出学员信息保持一致 // 辅助函数:构建入学后被投企业数据 $buildAfterEnrollmentData = function ($start_date, $end_date, $course_ids) { $data = []; @@ -1498,18 +1355,136 @@ class OtherController extends CommonController foreach ($companiesAfterEnrollment as $item) { $company = $item['company']; - $userNames = collect($item['users'])->pluck('name')->filter()->unique()->implode("\n\r"); - $data[] = [ + $users = $item['users'] ?? []; + + // 公司基本信息(只在第一行使用) + $companyInfo = [ '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 ?? '', ]; + + if (empty($users)) { + // 如果没有学员,仍然导出公司基本信息 + $data[] = array_merge($companyInfo, [ + 'user_name' => '', + 'course_names' => '', + 'course_types' => '', + 'course_count' => 0, + ]); + } else { + // 获取该公司的学员ID列表 + $userIds = collect($users)->pluck('id')->toArray(); + + // 使用getStudentList获取学员的课程报名记录(与统计逻辑一致) + $userCourseSigns = CourseSign::getStudentList($start_date, $end_date, 1, $course_ids) + ->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; + } + + // 如果没有找到课程报名记录,仍然导出学员基本信息 + if (empty($usersData)) { + foreach ($users as $user) { + $data[] = array_merge($companyInfo, [ + 'user_name' => $user->name ?? '', + 'course_names' => '', + 'course_types' => '', + 'course_count' => 0, + ]); + // 后续行的公司信息为空 + $companyInfo = array_fill_keys(array_keys($companyInfo), ''); + } + } else { + // 每个学员一行,公司信息只在第一行显示,后续行公司信息为空 + $isFirstRow = true; + foreach ($usersData as $userData) { + $user = $userData['user']; + $courseSigns = collect($userData['courseSigns']); + + // 获取课程名称列表,用中文顿号分隔 + $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' => '', + 'invest_date' => '', + 'first_sign_date' => '', + 'company_address' => '', + 'company_city' => '', + 'company_area' => '', + 'user_name' => $user->name ?? '', + 'course_names' => $courseNames, + 'course_types' => $courseTypes, + 'course_count' => $courseCount, + ]; + } + } + + // 处理没有课程报名记录的学员(如果有) + $processedUserIds = array_keys($usersData); + foreach ($users as $user) { + if (!in_array($user->id, $processedUserIds)) { + $data[] = [ + 'company_name' => '', + 'company_legal_representative' => '', + 'company_date' => '', + 'invest_date' => '', + 'first_sign_date' => '', + 'company_address' => '', + 'company_city' => '', + 'company_area' => '', + 'user_name' => $user->name ?? '', + 'course_names' => '', + 'course_types' => '', + 'course_count' => 0, + ]; + } + } + } + } } return $data; @@ -1527,10 +1502,13 @@ class OtherController extends CommonController 'company_date' => '成立时间', 'invest_date' => '被投日期', 'first_sign_date' => '首次报名时间', - 'user_names' => '学员姓名', 'company_address' => '地址', 'company_city' => '所在城市', 'company_area' => '所在区域', + 'user_name' => '学员姓名', + 'course_names' => '课程名称', + 'course_types' => '课程体系', + 'course_count' => '报名课程数', ]; // 创建多 sheet 导出 diff --git a/app/Models/CourseSign.php b/app/Models/CourseSign.php index b83e40a..7bda817 100755 --- a/app/Models/CourseSign.php +++ b/app/Models/CourseSign.php @@ -600,6 +600,99 @@ class CourseSign extends SoftDeletesModel } } + /** + * 获取区域数据(统计或导出) + * @param string $start_date 开始日期 + * @param string $end_date 结束日期 + * @param int|null $status 状态,1表示审核通过 + * @param array|null $course_ids 课程ID数组 + * @param bool $is_schoolmate 是否只统计校友 + * @param string $returnType 返回类型:'statistics' 返回统计数据,'export' 返回导出数据 + * @return array + */ + public static function getAreaData($start_date, $end_date, $status = 1, $course_ids = null, $is_schoolmate = false, $returnType = 'statistics') + { + $courseSignList = self::getStudentList($start_date, $end_date, $status, $course_ids); + + // 如果只统计校友,添加校友筛选条件 + if ($is_schoolmate) { + $courseSignList->whereHas('user', function ($query) { + $query->where('is_schoolmate', 1); + }); + } + + // 从数据字典获取区域列表 + $suzhouAreas = ParameterDetail::where('parameter_id', 5) + ->where('status', 1) + ->orderBy('sort', 'asc') + ->pluck('value') + ->toArray(); + + $result = []; + foreach ($suzhouAreas as $area) { + // 根据区域获取对应的CourseSign记录 + if ($area === '高新区') { + // 高新区:统计高新区+虎丘区 + $areaCourseSigns = (clone $courseSignList)->whereHas('user', function ($query) { + $query->whereHas('company', function ($query) { + $query->where('company_city', '苏州市') + ->where(function ($q) { + $q->where('company_area', '高新区') + ->orWhere('company_area', '虎丘区'); + }); + }); + })->get(); + } elseif ($area === '苏州市外') { + // 苏州市外:统计除了苏州之外的所有数据 + $areaCourseSigns = (clone $courseSignList)->whereHas('user', function ($query) { + $query->whereHas('company', function ($query) { + $query->where('company_city', '!=', '苏州市'); + }); + })->get(); + } else { + // 其他区域:正常统计 + $areaCourseSigns = (clone $courseSignList)->whereHas('user', function ($query) use ($area) { + $query->whereHas('company', function ($query) use ($area) { + $query->where('company_city', '苏州市') + ->where('company_area', 'like', '%' . $area . '%'); + }); + })->get(); + } + + if ($returnType === 'statistics') { + // 返回统计数据 + $result[] = [ + 'area' => $area, + // 未去重 + 'total' => $areaCourseSigns->count(), + // 已去重 + 'total_unique' => User::whereIn('id', $areaCourseSigns->pluck('user_id'))->groupBy('mobile')->get()->count(), + ]; + } else { + // 返回导出数据(详细的学员列表) + // 加载关联关系 + $areaCourseSigns->load(['user.company', 'course.typeDetail']); + + // 将该区域下的学员明细添加到结果(一行一个学员) + foreach ($areaCourseSigns as $sign) { + $result[] = [ + 'company_name' => $sign->user->company->company_name ?? '', + 'company_area' => $sign->user->company->company_area ?? '', + 'company_city' => $sign->user->company->company_city ?? '', + 'company_province' => $sign->user->company->company_province ?? '', + 'company_address' => $sign->user->company->company_address ?? '', + 'user_name' => $sign->user->name ?? '', + 'mobile' => $sign->user->mobile ?? '', + 'course_type' => $sign->course->typeDetail->name ?? '', + 'course_name' => $sign->course->name ?? '', + ]; + } + } + } + + return $result; + } + /** * 元和员工参人员 */ diff --git a/app/Models/User.php b/app/Models/User.php index fd37771..35c01e8 100755 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -78,7 +78,7 @@ class User extends Authenticatable implements Auditable 'open_course_types', 'talent_tags' ]; - protected $appends = ['is_vip_text', 'is_schoolmate_text', 'appointment_total', 'name', 'is_company_schoolmate', 'is_company_schoolmate_text']; + protected $appends = ['is_vip_text', 'is_schoolmate_text', 'appointment_total', 'is_company_schoolmate', 'is_company_schoolmate_text']; // 更新时候覆盖更新的字段 public static $coverFields = [