From 0f77ee2de722f278d88e6320441b668164876b7f Mon Sep 17 00:00:00 2001 From: cody <648753004@qq.com> Date: Sat, 29 Nov 2025 17:19:42 +0800 Subject: [PATCH] update --- app/Exports/CommonExport.php | 104 ++++++++++++++++++++++++++++++++--- 1 file changed, 95 insertions(+), 9 deletions(-) diff --git a/app/Exports/CommonExport.php b/app/Exports/CommonExport.php index c4b1a5c..7f06973 100755 --- a/app/Exports/CommonExport.php +++ b/app/Exports/CommonExport.php @@ -6,6 +6,7 @@ namespace App\Exports; use App\Exceptions\ErrorException; +use App\Models\CourseType; use Illuminate\Support\Collection; use Maatwebsite\Excel\Concerns\FromCollection; use Maatwebsite\Excel\Concerns\WithStyles; @@ -21,6 +22,7 @@ class CommonExport implements FromCollection, WithStyles, WithColumnWidths, With public $data; public $hasUsersField = false; public $hasProjectUsersField = false; + public $hasHistoryCoursesField = false; public $totalColumns = 0; public $totalRows = 0; public $expandedFields = []; @@ -45,6 +47,15 @@ class CommonExport implements FromCollection, WithStyles, WithColumnWidths, With 'pm_amount' => '投资金额', ]; + // 历史课程信息子列定义 + const HISTORY_COURSES_SUB_COLUMNS = [ + 'hc_course_type' => '课程体系', + 'hc_course_name' => '课程名称', + 'hc_signs_pass' => '培养人数未去重', + 'hc_signs_pass_unique' => '培养人数去重', + 'hc_course_signs_pass' => '课程培养人数', + ]; + public function __construct($data, $exportFields) { // 需要导出的字段。格式:['name'=>'名字','user.sex'=>'性别'] @@ -81,6 +92,13 @@ class CommonExport implements FromCollection, WithStyles, WithColumnWidths, With $this->expandedFields[$subField] = $subLabel; $index++; } + } elseif (str_contains($field, 'history_courses')) { + $this->hasHistoryCoursesField = true; + // 展开历史课程信息为多列 + foreach (self::HISTORY_COURSES_SUB_COLUMNS as $subField => $subLabel) { + $this->expandedFields[$subField] = $subLabel; + $index++; + } } else { $this->expandedFields[$field] = $label; $index++; @@ -94,7 +112,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 +148,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 +288,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 +334,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 +355,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 +370,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 +437,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 +475,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 +565,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 +579,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); }