Thực hiện chức năng xuất biểu mẫu và In ấn trực tiếp trên web Danh sách sản phẩm (print)

Step 1: cài đặt các thư viện CSS

Cài đặt thư viện CSS để chuẩn hóa các lề, padding, margin khi in

  • Ta sẽ sử dụng thư viện định dạng kích thước khổ giấy NormalizeCSS.
  • Trang chủ: https://github.com/necolas/normalize.css/
  • Download file normalize.min.css
  • Chép vào thư mục public/vendor/normalize

Cài đặt thư viện CSS để quy định kích thước khổ giấy khi in PaperCSS

  • Ta sẽ sử dụng thư viện định dạng kích thước khổ giấy ParerCSS.
  • Trang chủ: https://github.com/cognitom/paper-css
  • Download file paper.css hoặc paper.min.css
  • Chép vào thư mục public/vendor/paper-css
Tối ưu CSS khi xuất nhiều trang cùng lúc
  • Tạo file public/vendor/paper-css/custom-paper.css
  • Nội dung file
/* --- Hacking multi pages sheet --- */
.sheet {
    overflow: visible;
    height: auto !important;
}

.paper-toolbar {
    margin: auto;
    background: #0d8a05;
    padding: 5px;
    z-index: 999;
}

.paper-toolbar-top {
    position: fixed;
    top: 0;
    left: 0;
}

.paper-toolbar-bottom {
    position: fixed;
    bottom: 0;
    left: 0;
}

.paper-toolbar.paper-toolbar-A3 {
    width: 297mm;
}

.paper-toolbar.paper-toolbar-A3.landscape {
    width: 420mm;
}

.paper-toolbar.paper-toolbar-A4  {
    width: 210mm;
}

.paper-toolbar.paper-toolbar-A4.landscape  {
    width: 297mm;
}

.paper-toolbar.paper-toolbar-A5  {
    width: 148mm;
}

.paper-toolbar.paper-toolbar-A5.landscape  {
    width: 210mm;
}

.paper-toolbar.letter.sheet {
    width: 216mm;
}

.paper-toolbar.letter.landscape.sheet {
    width: 280mm;
}

.paper-toolbar.legal.sheet {
    width: 216mm;
}

.paper-toolbar.legal.landscape.sheet {
    width: 357mm;
}

@media print {
    .paper-show-when-print {
        display: block !important;
    }

    .paper-hide-when-print {
        display: none !important;
    }

    .no-print, .no-print *
    {
        display: none !important;
    }

    h2 { 
        page-break-before: always;
    }

    h3, h4 {
        page-break-after: avoid;
    }

    pre, blockquote {
        page-break-inside: avoid;
    }

    .page-break-inside-avoid {
        page-break-inside: avoid;
    }

    tbody {
        page-break-inside: avoid;
    }
    
    thead {
        display: table-header-group;
        margin-top: 100px;
    }

    table.report-container {
        page-break-after:always;
    }

    thead.report-header {
        display:table-header-group;
    }

    tfoot.report-footer {
        display:table-footer-group;
    } 
}

Step 2: tạo bố cục (layout) dành riêng cho các chức năng in ấn

Tạo cấu trúc folder layouts như sau:
views
---print
------layouts
---------paper.blade.php
------partials
---------paper-toolbar.blade.php
Nội dung file paper.blade.php
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <title>@yield('title')</title>

  <!-- Normalize or reset CSS with your favorite library -->
  <link rel="stylesheet" href="{{ asset('vendor/normalize/normalize.min.css') }}">

  <!-- Load paper.css for happy printing -->
  <link rel="stylesheet" href="{{ asset('vendor/paper-css/paper.min.css') }}">
  <link rel="stylesheet" href="{{ asset('vendor/paper-css/custom-paper.css') }}">

  <!-- Set page size here: A5, A4 or A3 -->
  <!-- Set also "landscape" if you need -->
  <style>@page { size: @yield('paper-size') }</style>

  @yield('custom-css')
</head>

<!-- Set "A5", "A4" or "A3" for class name -->
<!-- Set also "landscape" if you need -->
<body class="@yield('paper-class')">
  @include('print.partials.paper-toolbar')
  @yield('content')
</body>

</html>
Nội dung file paper-toolbar.blade.php
<section class="paper-toolbar paper-toolbar-top no-print">
    <form>
        <input type="button" value="In trang này" onClick="window.print()" />
    </form>

    @yield('paper-toolbar-top')
</section>

<section class="paper-toolbar paper-toolbar-bottom no-print">
    <form>
        <input type="button" value="In trang này" onClick="window.print()" />
    </form>

    @yield('paper-toolbar-bottom')
</section>

Mô hình hoạt động của print:

Step 1: tạo route xuất Biểu mẫu và In ấn Danh mục sản phẩm

  • Hiệu chỉnh file routes/web.php
Route::get('/admin/sanpham/print', 'Backend\SanPhamController@print')->name('admin.sanpham.print');

Step 2: tạo nút nhấn In ấn trên giao diện index:

  • Hiệu chỉnh file resources/views/backend/sanpham/index.blade.php
<!-- Tạo nút xem biểu mẫu khi in trên web
- Theo quy ước, các route đã được đăng ký trong file `web.php` đều phải được đặt tên để dễ dàng bảo trì code sau này.
- Đường dẫn URL là đường dẫn được tạo ra bằng route có tên `admin.sanpham.print`
- Sẽ có dạng http://tenmiencuaban.com/admin/sanpham/print
-->
<a href="{{ route('admin.sanpham.print') }}" class="btn btn-primary">In ấn</a>

Step 3: viết code action

Viết code cho action print():

  • Action print() dùng để lấy danh sách sản phẩm có trong table sanpham và hiển thị ra màn hình với các định dạng CSS in ấn.
Hiệu chỉnh file app/Http/Controllers/Backend/SanphamController.php
/**
 * Action hiển thị biểu mẫu xem trước khi in trên Web
 */
public function print()
{
    $ds_sanpham = Sanpham::all();
    $ds_loai    = Loai::all();

    return view('backend.sanpham.print')
        ->with('danhsachsanpham', $ds_sanpham)
        ->with('danhsachloai', $ds_loai);
}
Tạo view print.blade.php
  • Để dễ dàng quản lý các view, ta sẽ tạo 1 thư mục tương ứng với tên Controller, mỗi action sẽ tương ứng với tên view.
  • Tạo folder resources/views/sanpham
  • Tạo file resources/views/sanpham/print.blade.php
@extends('print.layouts.paper')

@section('title')
Biểu mẫu Phiếu in danh sách sản phẩm
@endsection

@section('paper-size') A4 @endsection
@section('paper-class') A4 @endsection

@section('custom-css')
@endsection

@section('content')
<section class="sheet padding-10mm">
    <article>
        <table border="0" align="center">
            <tr>
                <td class="companyInfo" align="center">
                    Công ty TNHH Sunshine<br />
                    http://sunshine.com/<br />
                    (0292)3.888.999 # 01.222.888.999<br />
                    <img src="{{ asset('assets/storage/sunshine_wm64.png') }}" />
                </td>
            </tr>
        </table>
        <br />
        <br />
        <?php 
        $tongSoTrang = ceil(count($danhsachsanpham)/5);
        ?>
        <table border="1" align="center" cellpadding="5">
            <caption>Danh sách sản phẩm</caption>
            <tr>
                <th colspan="6" align="center">Trang 1 / {{ $tongSoTrang }}</th>
            </tr>
            <tr>
                <th>STT</th>
                <th>Hình sản phẩm</th>
                <th>Tên sản phẩm</th>
                <th>Giá gốc</th>
                <th>Giá bán</th>
                <th>Loại sản phẩm</th>
            </tr>
            @foreach ($danhsachsanpham as $sp)
            <tr>
                <td align="center">{{ $loop->index + 1 }}</td>
                <td align="center">
                    <img class="hinhSanPham" src="{{ asset('assets/storage/photos/' . $sp->sp_hinh) }}" />
                </td>
                <td align="left">{{ $sp->sp_ten }}</td>
                <td align="right">{{ $sp->sp_giaGoc }}</td>
                <td align="right">{{ $sp->sp_giaBan }}</td>
                @foreach ($danhsachloai as $l)
                @if ($sp->l_ma == $l->l_ma)
                <td align="left">{{ $l->l_ten }}</td>
                @endif
                @endforeach
            </tr>
            @if (($loop->index + 1) % 5 == 0)
        </table>
        <div class="page-break"></div>
        <table border="1" align="center" cellpadding="5">
            <tr>
                <th colspan="6" align="center">Trang {{ 1 + floor(($loop->index + 1) / 5) }} / {{ $tongSoTrang }}</th>
            </tr>
            <tr>
                <th>STT</th>
                <th>Hình sản phẩm</th>
                <th>Tên sản phẩm</th>
                <th>Giá gốc</th>
                <th>Giá bán</th>
                <th>Loại sản phẩm</th>
            </tr>
            @endif
            @endforeach
        </table>
    </article>
</section>
@endsection