API流式导出大数据
<?php
namespace App\Admin\Exports;
use App\Admin\Services\Statistics\ExaminationRecordsDataService;
use App\Enums\ExaminationStatus;
use App\Utilities\Conversion\VersionHelper;
use Generator;
use Maatwebsite\Excel\Concerns\FromGenerator;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithStrictNullComparison;
class ExaminationRecordExport implements FromGenerator, WithHeadings, WithStrictNullComparison
{
private array $search;
public function __construct(array $search)
{
$this->search = $search;
}
/**
* @return Generator
*/
public function generator(): Generator
{
$service = new ExaminationRecordsDataService();
$this->search['sort'] = 'examination_records.id';
$query = $service->getExaminationRecordsQuery($this->search);
foreach($query->cursor() as $item) {
yield [
'user_name' => $item->user_name,
'company_name' => $item->company_name,
'department_name' => $item->department_name,
'group_name' => $item->group_name,
'position_name' => $item->position_name,
'title' => $item->title,
'course_serial_number' => $item->course_serial_number,
'version' => VersionHelper::formatting($item->version),
'name' => $item->name,
'serial_number' =>$item->serial_number,
'examination_status' => ExaminationStatus::from($item->examination_status)->label(),
'exam_nums' => $item->exam_nums,
'total_score' => $item->total_score,
'passing_score' => $item->passing_score,
'score' => $item->score,
'test_start_time' => $item->test_start_time->format('Y-m-d H:i:s'),
'test_end_time' => $item->test_end_time->format('Y-m-d H:i:s'),
'total_test_duration' => $item->total_test_duration,
'test_duration' => floor($item->test_duration / 60 * 100) / 100, // 分钟
];
}
}
public function headings(): array
{
return [
'user_name' => '姓名',
'company_name' => '公司',
'department_name' => '部門',
'group_name' => '組別',
'position_name' => '崗位',
'title' => '所屬課程名稱',
'course_serial_number' => '所屬課程編號',
'version' => '版本號',
'name' => '考試名稱',
'serial_number' => '考試編號',
'examination_status' => '考試狀態',
'exam_nums' => '考試次數',
'total_score' => '總分',
'passing_score' => '通過分數',
'score' => '考試最高分數',
'test_start_time' => '最高分考試的開始時間',
'test_end_time' => '最高分考試的結束時間',
'total_test_duration' => '考試規定時長(分鐘)',
'test_duration' => '最高分考試的進行時長(分鐘)',
];
}
}
<?php
namespace App\Admin\Controllers;
use App\Admin\Exports\ExaminationRecordExport;
use App\Admin\Requests\Examination\GetExaminationRecordsListRequest;
use App\Admin\Resources\ExaminationRecord\ExaminationRecordCollection;
use App\Admin\Services\Statistics\ExaminationRecordsDataService;
use App\Traits\SearchStaffGroupTrait;
use App\Traits\SearchTrait;
class ExaminationController extends BaseController
{
use SearchTrait, SearchStaffGroupTrait;
public function getExaminationRecordsList(GetExaminationRecordsListRequest $request)
{
$search = $request->validated();
$examinationRecords = (new ExaminationRecordsDataService())->getExaminationRecordsPage($search);
return new ExaminationRecordCollection($examinationRecords);
}
public function export(GetExaminationRecordsListRequest $request)
{
set_time_limit(0);
ini_set('memory_limit', '1024M');
$search = $request->validated();
$export = new ExaminationRecordExport($search);
$total = (new ExaminationRecordsDataService())->getExaminationRecordsTotal($search);
if ($total <= 10000) {
return Excel::download($export, '學員考試記錄.xlsx');
} else {
header("Content-Type: application/force-download");
header("Content-Type: application/octet-stream");
header("Content-Type: application/download");
header('Content-Disposition: attachment; filename=學員考試記錄.csv');
header('Content-Type: text/csv; charset=gb18030');
header("Content-Transfer-Encoding: binary");
header("Pragma: no-cache");
echo mb_convert_encoding(implode(',', array_values($export->headings())), 'gb18030') . "\n";
foreach ($export->generator() as $item) {
echo mb_convert_encoding(implode(',', array_values($item)), 'gb18030') . "\n";
}
}
}
}
const fileUrl = 'https://api.xxx.com/...';
const a = document.createElement('a');
const event = new MouseEvent('click');
a.href = fileUrl;
// a.download = fileName;
a.dispatchEvent(event);