lion 2 weeks ago
commit 50f61a6540

@ -20,7 +20,7 @@ class CommonExport implements FromCollection, WithStyles, WithColumnWidths, With
public $fields;
public $data;
public $hasUsersField = false;
public $usersColumnStartIndex = null;
public $hasProjectUsersField = false;
public $totalColumns = 0;
public $totalRows = 0;
public $expandedFields = [];
@ -37,6 +37,14 @@ class CommonExport implements FromCollection, WithStyles, WithColumnWidths, With
'user_sign_date' => '报名时间',
];
// 项目经理信息子列定义
const PROJECT_USERS_SUB_COLUMNS = [
'pm_platform' => '管理平台',
'pm_name' => '项目经理',
'pm_invest_date' => '首次出资时间',
'pm_amount' => '投资金额',
];
public function __construct($data, $exportFields)
{
// 需要导出的字段。格式:['name'=>'名字','user.sex'=>'性别']
@ -49,7 +57,7 @@ class CommonExport implements FromCollection, WithStyles, WithColumnWidths, With
}
/**
* 构建扩展后的字段列表将users字段展开成多列
* 构建扩展后的字段列表将users和project_users字段展开成多列)
*/
private function buildExpandedFields()
{
@ -59,14 +67,20 @@ class CommonExport implements FromCollection, WithStyles, WithColumnWidths, With
$index = 1;
foreach ($this->fields as $field => $label) {
if (str_contains($field, 'users')) {
if (str_contains($field, 'users') && !str_contains($field, 'project_users')) {
$this->hasUsersField = true;
$this->usersColumnStartIndex = $index;
// 展开学员信息为多列
foreach (self::USERS_SUB_COLUMNS as $subField => $subLabel) {
$this->expandedFields[$subField] = $subLabel;
$index++;
}
} elseif (str_contains($field, 'project_users')) {
$this->hasProjectUsersField = true;
// 展开项目经理信息为多列
foreach (self::PROJECT_USERS_SUB_COLUMNS as $subField => $subLabel) {
$this->expandedFields[$subField] = $subLabel;
$index++;
}
} else {
$this->expandedFields[$field] = $label;
$index++;
@ -75,6 +89,14 @@ class CommonExport implements FromCollection, WithStyles, WithColumnWidths, With
$this->totalColumns = count($this->expandedFields);
}
/**
* 是否需要二级表头
*/
private function needsDoubleHeader()
{
return $this->hasUsersField || $this->hasProjectUsersField;
}
/**
* 获取列字母
*/
@ -100,11 +122,13 @@ class CommonExport implements FromCollection, WithStyles, WithColumnWidths, With
$letter = $this->getColumnLetter($index);
if (in_array($field, ['user_course', 'user_name'])) {
$widths[$letter] = 25;
} elseif (in_array($field, ['user_mobile', 'user_sign_date'])) {
} elseif (in_array($field, ['user_mobile', 'user_sign_date', 'pm_invest_date', 'pm_amount'])) {
$widths[$letter] = 15;
} elseif (in_array($field, ['user_index', 'user_schoolmate'])) {
$widths[$letter] = 8;
} elseif (str_contains($field, 'partners') || str_contains($field, 'project_users')) {
} elseif (in_array($field, ['pm_platform', 'pm_name'])) {
$widths[$letter] = 18;
} elseif (str_contains($field, 'partners')) {
$widths[$letter] = 50;
} elseif (str_contains($field, 'all_course')) {
$widths[$letter] = 40;
@ -124,11 +148,11 @@ class CommonExport implements FromCollection, WithStyles, WithColumnWidths, With
public function styles(Worksheet $sheet): array
{
$lastCol = $this->getColumnLetter($this->totalColumns);
$dataStartRow = $this->hasUsersField ? 3 : 2;
$dataStartRow = $this->needsDoubleHeader() ? 3 : 2;
$styles = [];
if ($this->hasUsersField) {
if ($this->needsDoubleHeader()) {
// 二级表头样式 - 第一行
$styles[1] = [
'font' => ['bold' => true, 'size' => 12],
@ -194,7 +218,7 @@ class CommonExport implements FromCollection, WithStyles, WithColumnWidths, With
AfterSheet::class => function (AfterSheet $event) {
$sheet = $event->sheet->getDelegate();
if ($this->hasUsersField) {
if ($this->needsDoubleHeader()) {
// 处理二级表头的单元格合并
$this->mergeHeaderCells($sheet);
@ -210,7 +234,7 @@ class CommonExport implements FromCollection, WithStyles, WithColumnWidths, With
}
// 设置数据行高
$dataStartRow = $this->hasUsersField ? 3 : 2;
$dataStartRow = $this->needsDoubleHeader() ? 3 : 2;
for ($row = $dataStartRow; $row <= $this->totalRows + $dataStartRow - 1; $row++) {
$sheet->getRowDimension($row)->setRowHeight(22);
}
@ -225,17 +249,22 @@ class CommonExport implements FromCollection, WithStyles, WithColumnWidths, With
{
$index = 1;
foreach ($this->fields as $field => $label) {
if (str_contains($field, 'users')) {
if (str_contains($field, 'users') && !str_contains($field, 'project_users')) {
// 学员信息列:合并第一行的多个单元格
$startCol = $this->getColumnLetter($index);
$endCol = $this->getColumnLetter($index + count(self::USERS_SUB_COLUMNS) - 1);
$sheet->mergeCells("{$startCol}1:{$endCol}1");
$sheet->setCellValue("{$startCol}1", $label);
// 学员信息子表头不需要合并
$index += count(self::USERS_SUB_COLUMNS);
} elseif (str_contains($field, 'project_users')) {
// 项目经理信息列:合并第一行的多个单元格
$startCol = $this->getColumnLetter($index);
$endCol = $this->getColumnLetter($index + count(self::PROJECT_USERS_SUB_COLUMNS) - 1);
$sheet->mergeCells("{$startCol}1:{$endCol}1");
$sheet->setCellValue("{$startCol}1", $label);
$index += count(self::PROJECT_USERS_SUB_COLUMNS);
} else {
// 非学员信息列:合并第一行和第二行
// 其他列:合并第一行和第二行
$col = $this->getColumnLetter($index);
$sheet->mergeCells("{$col}1:{$col}2");
$sheet->setCellValue("{$col}1", $label);
@ -260,16 +289,19 @@ class CommonExport implements FromCollection, WithStyles, WithColumnWidths, With
$newList = [];
if ($this->hasUsersField) {
// 有学员字段:创建二级表头
if ($this->needsDoubleHeader()) {
// 有需要展开的字段:创建二级表头
// 第一行表头(主表头)- 在 mergeHeaderCells 中处理
$header1 = [];
foreach ($this->fields as $field => $label) {
if (str_contains($field, 'users')) {
// 学员信息占用多列,第一行只需要占位
if (str_contains($field, 'users') && !str_contains($field, 'project_users')) {
foreach (self::USERS_SUB_COLUMNS as $subLabel) {
$header1[] = '';
}
} elseif (str_contains($field, 'project_users')) {
foreach (self::PROJECT_USERS_SUB_COLUMNS as $subLabel) {
$header1[] = '';
}
} else {
$header1[] = '';
}
@ -279,33 +311,36 @@ class CommonExport implements FromCollection, WithStyles, WithColumnWidths, With
// 第二行表头(子表头)
$header2 = [];
foreach ($this->fields as $field => $label) {
if (str_contains($field, 'users')) {
if (str_contains($field, 'users') && !str_contains($field, 'project_users')) {
foreach (self::USERS_SUB_COLUMNS as $subLabel) {
$header2[] = $subLabel;
}
} elseif (str_contains($field, 'project_users')) {
foreach (self::PROJECT_USERS_SUB_COLUMNS as $subLabel) {
$header2[] = $subLabel;
}
} else {
$header2[] = '';
}
}
$newList[] = $header2;
// 数据行:每个学员的每条课程记录占一行
// 数据行:每个展开记录占一行
foreach ($this->data as $info) {
$usersData = $this->getUsersExpanded($info);
if (empty($usersData)) {
// 没有学员数据,输出一行空数据
$row = $this->buildRowWithoutUsers($info, []);
$expandedRows = $this->getExpandedRows($info);
if (empty($expandedRows)) {
// 没有展开数据,输出一行空数据
$row = $this->buildExpandedRow($info, [], []);
$newList[] = $row;
} else {
// 每个学员记录一行
foreach ($usersData as $userData) {
$row = $this->buildRowWithoutUsers($info, $userData);
foreach ($expandedRows as $expandedRow) {
$row = $this->buildExpandedRow($info, $expandedRow['users'] ?? [], $expandedRow['project_users'] ?? []);
$newList[] = $row;
}
}
}
} else {
// 没有学员字段:使用原有逻辑
// 没有需要展开的字段:使用原有逻辑
$header = array_values($this->fields);
$moreFileds = [];
if (empty($clear)) {
@ -326,8 +361,6 @@ class CommonExport implements FromCollection, WithStyles, WithColumnWidths, With
$temp[$field] = $this->allCourse($info);
} elseif (str_contains($field, 'partners')) {
$temp[$field] = $this->partners($info);
} elseif (str_contains($field, 'project_users')) {
$temp[$field] = $this->projectManager($info);
} else {
$temp[$field] = $this->getDotValue($info, $field);
}
@ -350,10 +383,53 @@ class CommonExport implements FromCollection, WithStyles, WithColumnWidths, With
}
}
$this->totalRows = count($newList) - ($this->hasUsersField ? 2 : 1);
$this->totalRows = count($newList) - ($this->needsDoubleHeader() ? 2 : 1);
return new Collection($newList);
}
/**
* 获取展开后的所有行数据
*/
private function getExpandedRows($info)
{
$usersData = $this->hasUsersField ? $this->getUsersExpanded($info) : [];
$projectUsersData = $this->hasProjectUsersField ? $this->getProjectUsersExpanded($info) : [];
// 计算最大行数
$maxRows = max(count($usersData), count($projectUsersData), 1);
$result = [];
for ($i = 0; $i < $maxRows; $i++) {
$result[] = [
'users' => $usersData[$i] ?? [],
'project_users' => $projectUsersData[$i] ?? [],
];
}
return $result;
}
/**
* 获取展开的项目经理数据(每条记录一行)
*/
private function getProjectUsersExpanded($info)
{
if (empty($info['project_users'])) {
return [];
}
$result = [];
foreach ($info['project_users'] as $item) {
$result[] = [
'pm_platform' => $item['groupName'] ?? '-',
'pm_name' => $item['userName'] ?? '-',
'pm_invest_date' => $item['investDate'] ?? '-',
'pm_amount' => $item['amount'] ?? '-',
];
}
return $result;
}
/**
* 获取展开的学员数据(每个学员每条课程一行)
*/
@ -397,25 +473,28 @@ class CommonExport implements FromCollection, WithStyles, WithColumnWidths, With
}
/**
* 构建包含学员数据的行
* 构建包含展开数据的行
*/
private function buildRowWithoutUsers($info, $userData)
private function buildExpandedRow($info, $userData, $projectUserData)
{
$row = [];
foreach ($this->fields as $field => $label) {
if (str_contains($field, 'users')) {
if (str_contains($field, 'users') && !str_contains($field, 'project_users')) {
// 填充学员信息列
foreach (array_keys(self::USERS_SUB_COLUMNS) as $subField) {
$row[] = $userData[$subField] ?? '';
}
} elseif (str_contains($field, 'project_users')) {
// 填充项目经理信息列
foreach (array_keys(self::PROJECT_USERS_SUB_COLUMNS) as $subField) {
$row[] = $projectUserData[$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, 'project_users')) {
$row[] = $this->projectManager($info);
} else {
$row[] = $this->getDotValue($info, $field);
}
@ -484,7 +563,7 @@ class CommonExport implements FromCollection, WithStyles, WithColumnWidths, With
{
$list = [];
foreach ($data['project_users'] as $item) {
$list[] = $item['groupName'] . '-' . ($item['userName'] ?? '') . '-' . ($item['investDate'] ?? '');
$list[] = $item['groupName'] . '-' . ($item['userName'] ?? '') . '-' . ($item['investDate'] ?? '') . '-' . ($item['amount'] ?? '');
}
return implode("、\r\n", $list);
}

@ -222,7 +222,7 @@ class OtherController extends CommonController
$course_type_id = $params['course_type_id'];
$courses = $params['courses'];
// 被投企业数
$list['course_signs_invested'] = CourseSign::yhInvested($start_date, $end_date);
$list['course_signs_invested'] = CourseSign::yhInvested($start_date, $end_date, $courses->pluck('id')->toArray());
// 报名人数
$list['course_signs_total'] = CourseSign::courseSignsTotal($start_date, $end_date, null, $courses->pluck('id'));
// 审核通过人数
@ -233,7 +233,11 @@ class OtherController extends CommonController
$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]);
})->whereIn('course_id', $courses->pluck('id'));
})->where(function ($query) use ($courses) {
if (request('course_type_id')) {
$query->whereIn('course_id', $courses->pluck('id'));
}
});
$list['course_total'] = (clone $calendar)->count();
// 开课天数
$list['course_day_total'] = (clone $calendar)->where('is_count_days', 1)->sum('days');
@ -288,6 +292,12 @@ class OtherController extends CommonController
'course_type_signs_pass_unique' => CourseSign::courseSignsTotalByUnique($start_date, $end_date, 1, $courses2->pluck('id'), null),
'course_name' => $course->name,
'course_signs_pass' => CourseSign::courseSignsTotal($start_date, $end_date, 1, [$course->id]),
// 跟班学员数量
'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]),
];
}
}
@ -355,7 +365,7 @@ class OtherController extends CommonController
switch ($export_type) {
case 'course_signs_invested':
// 被投企业明细 - 使用与coursesHome相同的算法
$companies = CourseSign::yhInvested($start_date, $end_date, true);
$companies = CourseSign::yhInvested($start_date, $end_date, $course_ids, true);
foreach ($companies as $company) {
$data[] = [
'company_name' => $company->company_name,
@ -495,6 +505,9 @@ class OtherController extends CommonController
'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]),
'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]),
];
}
}
@ -504,6 +517,9 @@ class OtherController extends CommonController
'course_type_signs_pass' => '课程体系培养人数',
'course_type_signs_pass_unique' => '课程体系去重培养人数',
'course_signs_pass' => '课程培养人数',
'genban_total' => '跟班学员数',
'yh_invested_total' => '被投企业数',
'company_join_total' => '元禾同事数',
];
$filename = '课程分类明细';
break;
@ -679,8 +695,12 @@ class OtherController extends CommonController
case 'course_total':
// 开课场次明细 - 与coursesHome算法一致
$calendars = Calendar::whereIn('course_id', $course_ids)
->whereBetween('date', [$start_date, $end_date])
$calendars = Calendar::whereBetween('date', [$start_date, $end_date])
->where(function ($query) use ($course_ids) {
if (request('course_type_id')) {
$query->whereIn('course_id', $course_ids);
}
})
->with('course')
->get();
@ -707,8 +727,12 @@ class OtherController extends CommonController
case 'course_day_total':
// 开课天数明细 - 与coursesHome算法一致
$calendars = Calendar::whereIn('course_id', $course_ids)
->whereBetween('date', [$start_date, $end_date])
$calendars = Calendar::whereBetween('date', [$start_date, $end_date])
->where(function ($query) use ($course_ids) {
if (request('course_type_id')) {
$query->whereIn('course_id', $course_ids);
}
})->where('is_count_days', 1)
->with('course')
->get();

@ -148,20 +148,57 @@ class CourseSign extends SoftDeletesModel
}
/**
* 指定时间内的被投企业
* 被投企业统计
* @param string|null $start_date 开始日期
* @param string|null $end_date 结束日期
* @param array|null $course_ids 课程ID仅在自定义时间时生效
* @param bool $retList 是否返回列表
*/
public static function yhInvested($start_date = null, $end_date = null, $retList = false)
public static function yhInvested($start_date = null, $end_date = null, $course_ids = null, $retList = false)
{
$courseSignByTypeQuery = self::getStudentList($start_date, $end_date, 1, null);
$list = Company::whereHas('users', function ($query) use ($courseSignByTypeQuery) {
$query->whereIn('id', $courseSignByTypeQuery->get()->pluck('user_id'));
// 判断是否使用默认时间
$isDefaultDate = empty($start_date) || $start_date == CourseType::START_DATE;
// 获取学员ID列表
if ($isDefaultDate) {
// 默认时间:获取所有学员,不限制课程
$userIds = self::getStudentList($start_date, $end_date, 1, null)->get()->pluck('user_id');
} else {
// 自定义时间:按课程筛选学员
$userIds = self::getStudentList($start_date, $end_date, 1, $course_ids)->get()->pluck('user_id');
}
// 获取这些学员所在的被投企业
$companies = Company::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) {
// 返回列表
return $list;
return $companies->values();
} else {
// 返回统计数据
return $list->count();
return $companies->count();
}
}
@ -341,10 +378,21 @@ class CourseSign extends SoftDeletesModel
// 检测关键词
$companyNameKeyword = [
'元禾控股', '元禾原点', '元禾厚望', '元禾重元',
'元禾璞华', '元禾谷风', '元禾绿柳', '元禾辰坤', '元禾沙湖',
'禾裕集团', '苏州科服', '信诚管理咨询',
'集成电路公司', '常州团队', '国企元禾'
'元禾控股',
'元禾原点',
'元禾厚望',
'元禾重元',
'元禾璞华',
'元禾谷风',
'元禾绿柳',
'元禾辰坤',
'元禾沙湖',
'禾裕集团',
'苏州科服',
'信诚管理咨询',
'集成电路公司',
'常州团队',
'国企元禾'
];
$company = Company::where(function ($query) use ($companyNameKeyword) {
foreach ($companyNameKeyword as $item) {

Loading…
Cancel
Save