You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel提交表单至数据库前用Dompdf生成PDF是否可行?

当然可以实现,以下是具体实现方案:

核心思路

通过前端收集表单内的实时数据(无需先提交到数据库),将数据POST到后端,后端直接用这些数据渲染PDF模板并生成文件。


步骤1:调整前端按钮与数据收集逻辑

把当前的<a>标签替换为按钮,并用JS收集表单内的所有必要数据:

<!-- 替换原Generate PDF按钮 -->
<button type="button" target="_blank" class="btn btn-success" id="generate-pdf">Generate PDF</button>

在页面底部添加JS代码(可放在@push('scripts')或直接写在blade文件末尾):

document.getElementById('generate-pdf').addEventListener('click', function() {
    const formData = new FormData();
    // 收集基础订单信息
    formData.append('customer_id', document.querySelector('#customer_name').value);
    formData.append('customer_name', document.querySelector('#order_save_customerName').textContent.trim());
    formData.append('order_unq_id', document.querySelector('#order_unq_id').value.trim());
    formData.append('total', document.querySelector('#total').value.trim());

    // 收集选中的商品(仅收集数量>0的项)
    document.querySelectorAll('.item').forEach(item => {
        const linkedId = item.querySelector('#linked_id').value;
        const quantity = item.querySelector('[name="item_quantity"]').value;
        const itemName = item.querySelector('#item_name').textContent.trim();
        const itemCost = item.querySelector('.item_cost').textContent.trim();
        const productName = item.querySelector('h6 strong').textContent.trim();

        if (parseInt(quantity) > 0) {
            formData.append('items[]', JSON.stringify({
                linked_id: linkedId,
                quantity: quantity,
                item_name: itemName,
                item_cost: itemCost,
                product_name: productName
            }));
        }
    });

    // 创建临时表单提交数据到PDF路由
    const tempForm = document.createElement('form');
    tempForm.method = 'POST';
    tempForm.action = "{{ route('mht_order_pdf') }}";
    tempForm.target = '_blank';

    // 添加CSRF令牌
    const csrfInput = document.createElement('input');
    csrfInput.type = 'hidden';
    csrfInput.name = '_token';
    csrfInput.value = "{{ csrf_token() }}";
    tempForm.appendChild(csrfInput);

    // 转换FormData为表单输入项
    for (let [key, value] of formData.entries()) {
        const input = document.createElement('input');
        input.type = 'hidden';
        input.name = key;
        input.value = value;
        tempForm.appendChild(input);
    }

    document.body.appendChild(tempForm);
    tempForm.submit();
    document.body.removeChild(tempForm);
});

步骤2:修改路由为POST方法

在routes/web.php中更新PDF路由:

Route::post('/orders/generate-pdf', [OrderController::class, 'generatePdf'])->name('mht_order_pdf');

步骤3:编写后端PDF生成逻辑

在OrderController中添加generatePdf方法:

use Barryvdh\DomPDF\Facade\Pdf;
use Illuminate\Http\Request;

public function generatePdf(Request $request)
{
    // 验证必要数据
    $request->validate([
        'customer_id' => 'required',
        'customer_name' => 'required',
        'order_unq_id' => 'required',
        'total' => 'required',
        'items' => 'array|min:1'
    ]);

    // 处理商品数据,计算行总价
    $items = collect($request->items)->map(function($item) {
        $item = json_decode($item, true);
        $item['line_total'] = number_format($item['quantity'] * $item['item_cost'], 2);
        return $item;
    });

    // 计算小计和VAT(与前端逻辑保持一致)
    $subtotal = $items->sum(fn($item) => (float)$item['line_total']);
    $vat = number_format($subtotal * 0.05, 2);

    // 渲染PDF模板并生成文件
    $pdf = Pdf::loadView('order-pdf', [
        'customer_name' => $request->customer_name,
        'order_unq_id' => $request->order_unq_id,
        'items' => $items,
        'subtotal' => number_format($subtotal, 2),
        'vat' => $vat,
        'total' => $request->total
    ]);

    // 设置PDF参数
    $pdf->setPaper('A4', 'portrait');

    // 输出PDF(在新窗口打开)
    return $pdf->stream('order-' . $request->order_unq_id . '.pdf');
}

步骤4:创建PDF专用模板

新建resources/views/order-pdf.blade.php,编写PDF的内容结构:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Order Confirmation</title>
    <style>
        body { font-family: Arial, sans-serif; padding: 20px; }
        .header { text-align: center; margin-bottom: 30px; border-bottom: 1px solid #ddd; padding-bottom: 10px; }
        .items-table { width: 100%; border-collapse: collapse; margin: 20px 0; }
        .items-table th, .items-table td { border: 1px solid #ddd; padding: 8px; text-align: left; }
        .items-table th { background-color: #f5f5f5; }
        .total-section { text-align: right; margin-top: 30px; }
        .total-section p { margin: 5px 0; }
        .grand-total { font-size: 1.2em; font-weight: bold; color: #dc3545; }
    </style>
</head>
<body>
    <div class="header">
        <h1>Order Confirmation</h1>
        <p>Customer: {{ $customer_name }}</p>
        <p>Order UID: {{ $order_unq_id }}</p>
    </div>

    <table class="items-table">
        <thead>
            <tr>
                <th>Product Name</th>
                <th>Item Name</th>
                <th>Quantity</th>
                <th>Unit Price (AED)</th>
                <th>Line Total (AED)</th>
            </tr>
        </thead>
        <tbody>
            @foreach($items as $item)
            <tr>
                <td>{{ $item['product_name'] }}</td>
                <td>{{ $item['item_name'] }}</td>
                <td>{{ $item['quantity'] }}</td>
                <td>{{ $item['item_cost'] }}</td>
                <td>{{ $item['line_total'] }}</td>
            </tr>
            @endforeach
        </tbody>
    </table>

    <div class="total-section">
        <p>Subtotal: {{ $subtotal }} AED</p>
        <p>VAT (5%): {{ $vat }} AED</p>
        <p class="grand-total">Grand Total: {{ $total }} AED</p>
    </div>
</body>
</html>

注意事项

  1. 确保已正确安装Dompdf扩展:composer require barryvdh/laravel-dompdf
  2. 若使用Laravel 9+,无需手动配置服务提供者,扩展会自动注册

内容的提问来源于stack exchange,提问作者SMH

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 18:09:24