'名字','user.sex'=>'性别'] $this->fields = $exportFields; // 数据 $this->data = $data; // 检查是否有 users 字段 if (is_array($exportFields)) { $index = 1; foreach (array_keys($exportFields) as $field) { if (str_contains($field, 'users')) { $this->hasUsersField = true; $this->usersColumnIndex = $this->getColumnLetter($index); } $index++; } } } /** * 获取列字母 */ private function getColumnLetter($columnNumber) { $letter = ''; while ($columnNumber > 0) { $columnNumber--; $letter = chr(65 + ($columnNumber % 26)) . $letter; $columnNumber = intval($columnNumber / 26); } return $letter; } /** * 设置列宽 */ public function columnWidths(): array { $widths = []; $index = 1; foreach (array_keys($this->fields) as $field) { $letter = $this->getColumnLetter($index); if (str_contains($field, 'users')) { // 学员信息列设置较宽 $widths[$letter] = 80; } elseif (str_contains($field, 'partners') || str_contains($field, 'project_users')) { // 股东和项目经理列 $widths[$letter] = 50; } elseif (str_contains($field, 'all_course')) { // 课程列 $widths[$letter] = 40; } elseif (str_contains($field, 'company_name') || str_contains($field, 'address')) { // 公司名称和地址 $widths[$letter] = 30; } else { // 默认列宽 $widths[$letter] = 15; } $index++; } return $widths; } /** * 设置样式 */ public function styles(Worksheet $sheet): array { $rowCount = count($this->data) + 1; // 数据行数 + 表头 $colCount = count($this->fields); $lastCol = $this->getColumnLetter($colCount); return [ // 表头样式 1 => [ 'font' => ['bold' => true, 'size' => 12], 'alignment' => [ 'horizontal' => Alignment::HORIZONTAL_CENTER, 'vertical' => Alignment::VERTICAL_CENTER, ], 'fill' => [ 'fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID, 'startColor' => ['rgb' => 'E0E0E0'], ], ], // 所有数据区域样式 "A1:{$lastCol}{$rowCount}" => [ 'alignment' => [ 'vertical' => Alignment::VERTICAL_TOP, 'wrapText' => true, // 自动换行 ], 'borders' => [ 'allBorders' => [ 'borderStyle' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN, 'color' => ['rgb' => 'CCCCCC'], ], ], ], ]; } /** * 注册事件 */ public function registerEvents(): array { return [ AfterSheet::class => function (AfterSheet $event) { $sheet = $event->sheet->getDelegate(); $rowCount = count($this->data) + 1; // 设置表头行高 $sheet->getRowDimension(1)->setRowHeight(25); // 遍历数据行,根据内容设置行高 for ($row = 2; $row <= $rowCount; $row++) { // 获取该行的最大内容行数 $maxLines = 1; foreach (array_keys($this->fields) as $index => $field) { $col = $this->getColumnLetter($index + 1); $cellValue = $sheet->getCell($col . $row)->getValue(); if ($cellValue) { $lines = substr_count($cellValue, "\n") + 1; $maxLines = max($maxLines, $lines); } } // 设置行高(每行内容约15像素,最小20,最大400) $rowHeight = min(400, max(20, $maxLines * 15)); $sheet->getRowDimension($row)->setRowHeight($rowHeight); } // 冻结首行 $sheet->freezePane('A2'); }, ]; } /** * 数组转集合 * @throws ErrorException */ public function collection() { $clear = request('clear', 0); if (empty($this->fields)) { throw new ErrorException('导出字段不能为空'); } if (!is_array($this->fields)) { throw new ErrorException('导出字段必须是数组'); } // 获取表头 $header = array_values($this->fields); $moreFileds = []; if (empty($clear)) { // 表头追加附属数据 if (isset($this->data[0]['data']) && is_array($this->data[0]['data'])) { $moreHeader = array_column($this->data[0]['data'], 'name'); // 获取头信息 $header = array_merge($header, $moreHeader); // 获取字段信息 $moreFileds = array_column($this->data[0]['data'], 'field'); } } // 获取字段指向 $fields = array_keys($this->fields); $newList = []; foreach ($this->data as $info) { $temp = []; foreach ($fields as $field) { if (str_contains($field, 'idcard')) { // 身份证 $temp[$field] = ' ' . $this->getDotValue($info, $field); } elseif (str_contains($field, 'all_course')) { // 所有课程 $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); } elseif (str_contains($field, 'users')) { // 学员信息 $temp[$field] = $this->getUsers($info); } else { $temp[$field] = $this->getDotValue($info, $field); } } // 如果有自定义数据,全部附件上去 $t2 = []; if (empty($clear)) { if (isset($info['data']) && $info['data'] && !empty($moreFileds)) { $dataCollect = collect($info['data']); foreach ($moreFileds as $moreFiled) { $value = ($dataCollect->where('field', $moreFiled)->first()['value']) ?? ''; if (str_contains($moreFiled, 'idcard')) { $t2[$moreFiled] = ' ' . $value; } else { $t2[$moreFiled] = $value; } } } } $newList[] = $temp + $t2; } array_unshift($newList, $header); //插入表头 return new Collection($newList); } /** * .号转数组层级并返回对应的值 * @param $key * @param null $default * @return mixed|null */ function getDotValue($config, $key, $default = null) { // 如果在第一层,就直接返回 if (isset($config[$key])) { return $config[$key]; } // 如果找不到,直接返回默认值 if (false === strpos($key, '.')) { return $default; } // 临时数组 $tempArr = explode('.', $key); foreach ($tempArr as $segment) { if (!is_array($config) || !array_key_exists($segment, $config)) { return $default; } $config = $config[$segment]; } return $config; } /** * 获取所有课程名称 * @param $data */ function allCourse($data) { $list = []; foreach ($data['course_signs'] as $item) { $list[] = $item['course']['name'] ?? ''; } return implode("、\r\n", $list); } /** * 获取所有股东信息 * @param $data */ function partners($data) { $list = []; foreach ($data['partners'] as $item) { $list[] = $item['stockName'] . '-' . $item['stockPercent'] ?? ''; } return implode("、\r\n", $list); } /** * 获取所有项目经理 * @param $data */ function projectManager($data) { $list = []; foreach ($data['project_users'] as $item) { $list[] = $item['groupName'] . '-' . ($item['userName'] ?? '') . '-' . ($item['investDate'] ?? ''); } return implode("、\r\n", $list); } /** * 获取学员信息(优化显示格式) * @param $data */ function getUsers($data) { if (empty($data['users'])) { return ''; } $list = []; $index = 1; foreach ($data['users'] as $item) { // 基本信息行 $userInfo = []; $userInfo[] = "【学员{$index}】"; $userInfo[] = "学号: " . ($item['no'] ?? '-'); $userInfo[] = "姓名: " . ($item['username'] ?? '-'); $userInfo[] = "校友: " . ($item['is_schoolmate_text'] ?? '-'); $userInfo[] = "职位: " . ($item['company_position'] ?? '-'); $userInfo[] = "手机: " . ($item['mobile'] ?? '-'); // 课程报名信息 if (!empty($item['course_signs'])) { $userInfo[] = "报名课程:"; foreach ($item['course_signs'] as $signIndex => $sign) { $courseName = $sign['course']['name'] ?? '-'; $signDate = $sign['created_at'] ?? '-'; $userInfo[] = " " . ($signIndex + 1) . ". {$courseName} ({$signDate})"; } } $list[] = implode("\n", $userInfo); $index++; } // 用分隔线分隔不同学员 return implode("\n" . str_repeat("-", 40) . "\n", $list); } }