触发 PDF 下载 PHP - Laravel 7

Trigger PDF Download PHP - Laravel 7

我有一个简单的报告页面,我正在使用 Laravel 7 来构建它。

我想触发自动下载具有该视图的 PDF。

我应该研究的最轻量级是什么? 我快速地做了一个 Google,然后我看到了很多选项。

我决定尝试 this 并完成所有步骤,下面是我的最终代码

最终代码

注意这一行:$pdf = PDF::loadView('layouts.be.baby.report', get_defined_vars());

public function downloadReportPDF($id) {


    $code = Request::get('code'); 
    $baby = Baby::where('adminCode',$code)->where('id',strtolower($id))
    ->orWhere('readOnlyCode',$code)->where('id',strtolower($id))
    ->first();
    
    if($baby){


        $inputs    = Request::all();
        $interval  = 'week';

        if(array_key_exists('interval', $inputs)){
            $interval  = $inputs['interval'];
        }

        switch ($interval) {
            case 'day':
            $q = BabyLog::where('created_at', '>', now()->today());
            break;
            case 'week':
            $q = BabyLog::where('created_at', '>', now()->subWeek());
            break;
            case 'month':
            $q = BabyLog::where('created_at', '>', now()->subMonth());
            break;
            case 'year':
            $q = BabyLog::where('created_at', '>', now()->subYear());
            break;
            default:
            $q = BabyLog::orderBy('created_at', 'desc');
            break;
        }


        $logs = $q->where('babyId',$baby->id)->orderBy('created_at', 'desc')->get()->groupBy(function ($log) {
            return $log->created_at->format('m/d/y');
        });


        // dd($logs);

        $graphData = [];

        foreach($logs as $date => $logsOnThatDay){


            $pee      = 0;
            $poop     = 0;
            $feed     = 0;
            $medicine = 0;
            $sleep    = 0;


            foreach($logsOnThatDay as $logOnThatDay){

                // if(strtotime($logOnThatDay->created_at) < strtotime(date('Y-m-d H:i:s'))){

                if($logOnThatDay->type == 'pee'){
                    $pee++;
                }

                if($logOnThatDay->type == 'poop'){
                    $poop++;
                }

                if($logOnThatDay->type == 'feed'){
                    $feed++;
                }

                if($logOnThatDay->type == 'medicine'){
                    $medicine++;
                }

                if($logOnThatDay->type == 'sleep'){
                    $sleep++;
                }


                $graphData[$date]['pee']      = $pee;
                $graphData[$date]['poop']     = $poop;
                $graphData[$date]['feed']     = $feed;
                $graphData[$date]['medicine'] = $medicine;
                $graphData[$date]['sleep']    = $sleep;

            }
        }


        array_pop($graphData);

        //PDF 
        $pdf = PDF::loadView('layouts.be.baby.report', get_defined_vars());

        return $pdf->download('file.pdf');
    }


}

它正在工作,当我访问路线时:

Route::get('/baby/{id}/report/download','BabyController@downloadReportPDF');

但是样式好像很乱

我该如何改进?


已更新

我现在已将我的图片链接更新到远程 url...它们现在已加载。

不知何故样式仍然乱七八糟。

我什至为我的填充尝试了内联样式,但仍然呈现错误...:(

report.blade.php

<!DOCTYPE html>
<html>
<head>

    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="author" content="Bunlong Heng">
    <meta name="csrf-token" value="{{ csrf_token() }}">

    <title>Report</title>

    <link id="favicon" rel="shortcut icon" href="{{$baby->babyProfilePath}}?q={{microtime()}}" type="image/x-icon" />
    <link rel="shortcut icon" href="{{$baby->babyProfilePath}}?q={{microtime()}}" type="image/favicon.ico" />
    <link rel="apple-touch-icon" href="{{$baby->babyProfilePath}}?q={{microtime()}}" sizes="152x152">


    <link  href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://www.chartjs.org/dist/2.8.0/Chart.min.js"></script>
    <script src="https://www.chartjs.org/samples/latest/utils.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>


    <style type="text/css">

        body {
            background-color: white; 
            color: black;

        }

        h5 {
            font-weight: normal;
            color: #86868b;
        }

    
        .text-poop {
            border: #ffb54c 1px solid !important;  
            color: #ffb54c; 
        }

        .text-pee { 
            border: #46b8da 1px solid !important;  
            color: #46b8da;
        }

        .text-medicine { 
            border: #ffdf0a 1px solid !important;  
            color: #ffdf0a;
        }

        .text-sleep { 
            border: #ca88ff 1px solid !important;  
            color:  #ca88ff;
        }

        .text-feed { 
            border: black 1px solid !important;  
            color:  black;

        }



    </style>


</head>


<body>

    <div class="container ">
        <div class="row ">

            <div class="col-sm-2 "></div>
            <div class="col-sm-8">


                <h1>{{ $baby->babyName }}</h1>

                <hr>

                <h5> Interval : {{ $interval }}ly. </h5>
                <h5> Today : {{ date('D F j, Y, g:i a') }}</h5>
                <h5> Parents : {{ $baby->name }} ({{ $baby->email }})</h5>
                <h5> URL : {{ env('APP_URL') }}/baby/{{ $baby->id }}/report?code={{ $baby->readOnlyCode }}</h5>

                <hr>

                <canvas id="canvas"></canvas>

                <hr>

                <table class="table skill-table">
                    <thead class="thin-border-bottom">
                        <th>date</th>
                        <th>Ago</th>
                        <th><img src="https://i.imgur.com/Xhg4Iwi.png" /> </th>
                        <th><img src="https://i.imgur.com/peU9Bas.png" /> </th>
                        <th><img src="https://i.imgur.com/Y3rrj9T.png" /> </th>
                        <th><img src="https://i.imgur.com/zQrE1o5.png" /> </th>
                        <th><img src="https://i.imgur.com/yCk62aM.png" /> </th>
                    </thead>

                    <tbody>


                        @foreach ($graphData as $date => $graph)

                        <tr>

                            <td >
                                {{$date}}
                            </td>
                            <td>{{ DateHelper::ago($date) }} ago.</td>

                            <td >
                                <a style="padding: 5px; " class="text-poop">{{$graph['poop'] ?? '' }}</a>
                            </td>

                            <td >
                                <a style="padding: 5px; " class="text-pee">{{$graph['pee'] ?? '' }}</a>
                            </td>

                            <td >
                                <a style="padding: 5px; " class="text-feed">{{$graph['feed'] ?? '' }}</a>
                            </td>

                            <td >
                                <a style="padding: 5px; " class="text-medicine">{{$graph['medicine'] ?? '' }}</a>
                            </td>

                            <td >
                                <a style="padding: 5px; " class="text-sleep">{{$graph['sleep'] ?? '' }}</a>
                            </td>

                        </tr>

                        @endforeach

                    </div>
                </div>
            </div>


            <script type="text/javascript">


                function hexToRgb(hex, opacity=1) {

                    var h=hex.replace('#', '');
                    h =  h.match(new RegExp('(.{'+h.length/3+'})', 'g'));

                    for(var i=0; i<h.length; i++)
                        h[i] = parseInt(h[i].length==1? h[i]+h[i]:h[i], 16);

                    if (typeof opacity != 'undefined')  h.push(opacity);

                    return 'rgba('+h.join(',')+')';

                }



                var url_string    = window.location.href;
                var url           = new URL(url_string);




                var data  = {};
                if(url.searchParams.get("interval") != null){
                    data.interval = url.searchParams.get("interval");
                }

                // console.log(data.interval);  

                $.ajax({
                    method: 'POST',
                    url: '/baby/{{$id}}/graphsData',
                    crossDomain: true,
                    contentType: false,
                    headers: {
                        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('value'),
                        "Accept": "application/json",
                        "Content-Type": "application/x-www-form-urlencoded",
                        "Cache-Control": "no-cache"
                    },
                    data: data,
                    success: function(response){
                        // console.log(response);


                        keys = [];
                        
                        peeData      = [];
                        poopData     = [];
                        feedData     = [];
                        medicineData = [];
                        sleepData    = [];

                        $.each(response, function(key,val) {

                            keys.push(key);

                            peeData.push(val.pee);
                            poopData.push(val.poop);
                            feedData.push(val.feed);
                            medicineData.push(val.medicine);
                            sleepData.push(val.sleep);


                        });



                        // console.log(peeData, poopData, feedData, medicineData, sleepData);


                        var originalLineDraw = Chart.controllers.line.prototype.draw;
                        Chart.helpers.extend(Chart.controllers.line.prototype, {
                            draw: function() {
                                originalLineDraw.apply(this, arguments);

                                var chart = this.chart;
                                var ctx = chart.chart.ctx;

                                var index = chart.config.data.lineAtIndex;
                                if (index) {
                                    var xaxis = chart.scales['x-axis-0'];
                                    var yaxis = chart.scales['y-axis-0'];

                                    ctx.save();
                                    ctx.beginPath();
                                    ctx.moveTo(xaxis.getPixelForValue(undefined, index), yaxis.top);
                                    ctx.strokeStyle = '#ff0000';
                                    ctx.textAlign = '#ff0000';
                                    ctx.fillText('NOW',0,0);
                                    ctx.lineTo(xaxis.getPixelForValue(undefined, index), yaxis.bottom);
                                    ctx.stroke();
                                    ctx.restore();
                                }
                            }
                        });

                        var options = {  weekday: 'long', year: 'numeric', month: 'long', day: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false };
                        var fullDayText = new Date().toLocaleTimeString('en-us', options);


                        var chartColors = [hexToRgb('#fff',1), hexToRgb("ccc",1)];

                        let canvas = document.getElementById('canvas').getContext('2d');
                        canvas.height = 2000;


                        var renderChart = function() {

                            new Chart(canvas, {
                                type:'bar', 
                                data:{
                                    labels: keys,
                                    datasets:[
                                    {
                                        label: 'poop',
                                        data: poopData,
                                        backgroundColor: hexToRgb('#ffb54c',.5),
                                        borderWidth:1,
                                        borderColor: hexToRgb('#ffb54c',1),
                                        hoverBorderWidth:3,
                                    },
                                    {
                                        label: 'pee',
                                        data: peeData,
                                        backgroundColor: hexToRgb('#46b8da',.5),
                                        borderWidth:1,
                                        borderColor: hexToRgb('#46b8da',1),
                                        hoverBorderWidth:3,
                                    },
                                    {
                                        label: 'feed',
                                        data: feedData,
                                        backgroundColor: hexToRgb('#fff',.5),
                                        borderWidth:1,
                                        borderColor: hexToRgb('#ccc',1),
                                        hoverBorderWidth:3,
                                    },
                                    {
                                        label: 'medecine',
                                        data: medicineData,
                                        backgroundColor: hexToRgb('#ffdf0a',.5),
                                        borderWidth:1,
                                        borderColor: hexToRgb('#ffdf0a',1),
                                        hoverBorderWidth:3,
                                    },
                                    {
                                        label: 'sleep',
                                        data: sleepData,
                                        backgroundColor: hexToRgb('#ca88ff',.5),
                                        borderWidth:1,
                                        borderColor: hexToRgb('#ca88ff',1),
                                        hoverBorderWidth:3,
                                    }
                                    ],
                                    lineAtIndex: new Date().getHours()
                                },
                                options:{
                                    legend:{
                                        display:true,
                                        position:'right',
                                        labels:{
                                            fontColor:'#000'
                                        }
                                    }
                                }


                            });

                        };

                        renderChart();
                        setTimeout(renderChart(), 1000);



                    },
                    error: function(jqXHR, textStatus, errorThrown) {
                        console.log(JSON.stringify(jqXHR));
                        console.log("AJAX error: " + textStatus + ' : ' + errorThrown);
                    }
                });


            </script>




        </body>
        </html>

如果您想使用触发打印,您可以使用 window.print 来实现,它会显示包含 pdf 格式打印的打印对话框。示例代码

<input type="button" value="Print" onClick="window.print()">
this will show in print preview

要打印另一页,您可以使用 iframe。您也可以使用 CSS 隐藏它。示例:

<button onclick='window.frames["printf"].print();'>print</button>
<iframe id="printf" name="printf" src="test.html" height="1%" width="100%" style="visibility: hidden"></iframe>

我试过包含 chartjs 的打印页面并且 100% 有效,你可以 test it out

如果你想触发下载为 PDF,你应该使用 package. JS 解决方案是 jsPDF and PHP/laravel solution is laravel-dompdf 。这两个包都不会完全按照浏览器渲染打印,特别是如果您使用 CSS3 或来自本地的图像源。您需要自定义兼容两个包的 CSS 和资产。

如果您使用的是 laravel dompdf,则需要更改以下代码:

<img src="/media/image.png" />

<img src="{{ public_path('/media/image.png') }}">

您可以使用 asset(),但您也需要在 laravel dompdf 中激活远程资产。

您可以检查 DomPDF CSS 兼容性 here