You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
wx.sstbc.com/app/Exports/CourseRegistrationExport.php

90 lines
5.4 KiB

<?php
namespace App\Exports;
use App\Services\Course\CourseFormSchema;
use Maatwebsite\Excel\Concerns\FromArray;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Events\AfterSheet;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Cell\DataType;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
/** Registration-only export: union schemas instead of deriving headers from the first answer. */
class CourseRegistrationExport implements FromArray, WithEvents
{
private array $rows;
private array $columns;
private array $sheet;
public function __construct(array $rows, $baseFields, array $current = [])
{
$this->rows = $rows;
$this->columns = [];
$baseFields = is_array($baseFields) ? $baseFields : [];
foreach ($rows as $row) if (!empty($row['replaces_sign_id']) || !empty($row['replaced_by_sign_id'])) {
$baseFields += ['company_name_snapshot' => '报名公司', 'replacement_text' => '报名更换记录', 'giveup_reason' => '放弃原因', 'replaced_at' => '更换时间'];
break;
}
foreach (['id' => '报名ID'] + $baseFields as $key => $name) $this->columns[] = ['base' => $key, 'name' => $name];
$fields = [];
foreach (array_merge($current, ...array_map(fn ($row) => is_array($row['data'] ?? null) ? $row['data'] : [], $rows)) as $field) {
if (!is_array($field) || !isset($field['field'])) continue;
$field = CourseFormSchema::field($field);
// A renamed historical field keeps its own title/column and can never shift another answer.
$key = $field['field']."\0".($field['name'] ?? $field['field']);
if (!isset($fields[$key])) $fields[$key] = $field;
elseif (!empty($field['option_texts']) || !empty($field['other_text'])) $fields[$key]['has_notes'] = true;
}
foreach ($fields as $field) {
$this->columns[] = ['field' => $field['field'], 'title' => $field['name'] ?? $field['field'], 'name' => $field['name'] ?? $field['field']];
if (!empty($field['config']['option_notes']) || !empty($field['config']['other_key']) || !empty($field['option_texts']) || !empty($field['other_text']) || !empty($field['has_notes'])) {
$this->columns[] = ['field' => $field['field'], 'title' => $field['name'] ?? $field['field'], 'notes' => true, 'name' => ($field['name'] ?? $field['field']).'-补充说明'];
}
}
$this->sheet = [array_column($this->columns, 'name')];
foreach ($rows as $row) {
$answers = CourseFormSchema::display(is_array($row['data'] ?? null) ? $row['data'] : []);
$cells = [];
foreach ($this->columns as $column) {
if (isset($column['base'])) { $value = data_get($row, $column['base']); $cells[] = is_scalar($value) ? (string) $value : ''; continue; }
$matches = array_values(array_filter($answers, fn ($answer) => ($answer['field'] ?? null) === $column['field'] && ($answer['name'] ?? $answer['field']) === $column['title']));
$answer = $matches[0] ?? [];
$value = !empty($answer['hidden']) ? '' : ($answer[!empty($column['notes']) ? 'supplement_text' : 'display_value'] ?? '');
if (empty($column['notes']) && empty($answer['hidden']) && ($answer['edit_input'] ?? '') === 'checkbox' && isset($answer['selected_keys'])) {
$selected = array_map('strval', $answer['selected_keys']);
$value = implode("\n", array_column(array_filter($answer['select_item'], fn ($option) => in_array((string) $option['key'], $selected, true)), 'value'));
}
$cells[] = $value;
}
$this->sheet[] = $cells;
}
}
public function array(): array { return $this->sheet; }
public function registerEvents(): array
{
return [AfterSheet::class => function (AfterSheet $event) {
$sheet = $event->sheet->getDelegate();
$last = Coordinate::stringFromColumnIndex(max(1, count($this->columns)));
$range = 'A1:'.$last.count($this->sheet);
$sheet->getStyle($range)->getAlignment()->setWrapText(true)->setVertical(Alignment::VERTICAL_TOP);
$sheet->getStyle('A1:'.$last.'1')->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER)->setVertical(Alignment::VERTICAL_CENTER);
$sheet->getStyle('A1:'.$last.'1')->getFont()->setBold(true);
$sheet->getRowDimension(1)->setRowHeight(42);
$sheet->freezePane('A2');
$sheet->setAutoFilter('A1:'.$last.count($this->sheet));
foreach ($this->columns as $index => $column) $sheet->getColumnDimension(Coordinate::stringFromColumnIndex($index + 1))->setWidth(isset($column['base']) ? 20 : (!empty($column['notes']) ? 42 : 30));
foreach ($this->sheet as $index => $row) {
foreach ($row as $col => $value) $sheet->setCellValueExplicit(Coordinate::stringFromColumnIndex($col + 1).($index + 1), (string) $value, DataType::TYPE_STRING);
if ($index > 0) {
$lines = 1;
foreach ($row as $value) $lines = max($lines, count(explode("\n", (string) $value)), (int) ceil(mb_strwidth((string) $value) / 28));
$sheet->getRowDimension($index + 1)->setRowHeight(min(300, max(32, 18 * $lines + 10)));
}
}
}];
}
}