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>
注意事项
- 确保已正确安装Dompdf扩展:
composer require barryvdh/laravel-dompdf - 若使用Laravel 9+,无需手动配置服务提供者,扩展会自动注册
内容的提问来源于stack exchange,提问作者SMH
相关产品推荐
相关产品推荐

