lion 1 week ago
commit 392ba5ae4d

@ -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);
}

@ -39,8 +39,6 @@ class CompanyController extends BaseController
* tags={"公司管理"},
* summary="参数",
* 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="token", in="query", @OA\Schema(type="string"), required=true, description="token"),
* @OA\Response(
* response="200",
@ -50,9 +48,6 @@ class CompanyController extends BaseController
*/
public function config()
{
// 如果提供了开始时间和结束时间,则计算统计
$start_date = request('start_date', CourseType::START_DATE);
$end_date = request('end_date', date('Y-m-d'));
// 企业标签
$companiesTags = Company::where('company_tag', '!=', '')->pluck('company_tag');
$companiesTags = $companiesTags->flatten()->implode(',');
@ -63,17 +58,7 @@ class CompanyController extends BaseController
});
$companiesTags = array_values($companiesTags);
// 累计被投企业数(从起始日期到结束日期)
$course_signs_invested = CourseSign::yhInvestedTotal(CourseType::START_DATE, $end_date, null);
// 入学后被投企业数量(在指定时间范围内报名的学员所在公司中,在入学后被投的公司数量)
$company_invested_after_enrollment_total = CourseSign::companyInvestedAfterEnrollment($start_date, $end_date, null);
// 今年范围内被投企业数(在指定时间范围内报名的学员所在公司中,被投时间在年份范围内的公司数量)
$company_invested_year_total = CourseSign::companyInvestedYear($start_date, $end_date, null);
return $this->success(compact('companiesTags', 'course_signs_invested', 'company_invested_after_enrollment_total', 'company_invested_year_total'));
return $this->success(compact('companiesTags'));
}
@ -92,6 +77,10 @@ class CompanyController extends BaseController
* @OA\Parameter(name="sort_name", in="query", @OA\Schema(type="string"), required=false, description="排序字段名字"),
* @OA\Parameter(name="sort_type", in="query", @OA\Schema(type="string"), required=false, description="排序类型"),
* @OA\Parameter(name="token", in="query", @OA\Schema(type="string"), required=true, description="token"),
* @OA\Parameter(name="start_year", in="query", @OA\Schema(type="string"), required=false, description="开始年份"),
* @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="学员名称"),
@ -105,6 +94,9 @@ class CompanyController extends BaseController
public function index()
{
$all = request()->all();
$start_year = $all['start_year'] ?? null;
$end_year = $all['end_year'] ?? null;
$list = $this->model->with([
'users' => function ($query) use ($all) {
$query->whereHas('courseSigns', function ($q) {
@ -128,7 +120,17 @@ class CompanyController extends BaseController
if (isset($all['is_schoolmate'])) {
$query->where('is_schoolmate', $all['is_schoolmate']);
}
})->where(function ($query) use ($all) {
})->where(function ($query) use ($all, $start_year, $end_year) {
// 根据开始和结束年份筛选 project_users 中的 investDate
if ($start_year && $end_year) {
// 使用 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', '%' . $year . '%');
}
});
}
if (isset($all['filter']) && !empty($all['filter'])) {
foreach ($all['filter'] as $condition) {
$key = $condition['key'] ?? null;
@ -200,7 +202,28 @@ class CompanyController extends BaseController
// 输出
$list = $list->paginate($all['page_size'] ?? 20);
}
return $this->success($list);
// 计算统计数据(如果提供了开始和结束年份)
$statistics = [
'course_signs_invested' => 0,
'company_invested_after_enrollment_total' => 0,
'company_invested_year_total' => 0,
];
$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'] = 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);
}
// 将统计数据添加到返回结果中
$result = $list->toArray();
$result['statistics'] = $statistics;
return $this->success($result);
}
/**

@ -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 ?? '',

@ -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]);

@ -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');
}
}

@ -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();
}
}
}

@ -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' => [],
];
@ -598,8 +615,18 @@ class CourseSign extends SoftDeletesModel
// 返回列表
return $list;
} else {
// 基础数据
$baseCount = $list->count();
// 额外数据
$employeeParticipations = EmployeeParticipation::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]);
}
})->where('type', 1)->sum('total');
// 返回统计数据
return $list->count();
return $baseCount + $employeeParticipations;
}
}
@ -626,7 +653,16 @@ class CourseSign extends SoftDeletesModel
if ($retList) {
return User::with('company')->whereIn('id', $courseSigns->pluck('user_id'))->get();
} else {
return User::whereIn('id', $courseSigns->pluck('user_id'))->count();
$baseCount = User::whereIn('id', $courseSigns->pluck('user_id'))->count();
// 额外数据
$employeeParticipations = EmployeeParticipation::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]);
}
})->where('type', 2)->sum('total');
return $baseCount + $employeeParticipations;
}
}

Loading…
Cancel
Save