From 620ef3fe3aa7b9d0e4b28027794f0f749402ec62 Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Fri, 9 Jan 2026 13:08:17 +0800 Subject: [PATCH] =?UTF-8?q?=E7=94=9F=E6=88=90pdf?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/common/controller/UsedCarController.php | 47 +++++++++ app/common/model/UsedCar.php | 2 +- app/common/service/UsedCarService.php | 18 ++++ app/common/utils/pdf/service/MpdfDriver.php | 101 +++++++++++++++----- app/common/utils/pdf/template/usedCar.stub | 10 +- composer.json | 3 +- config/route.php | 2 + 7 files changed, 151 insertions(+), 32 deletions(-) diff --git a/app/common/controller/UsedCarController.php b/app/common/controller/UsedCarController.php index 2c3433d..c6e3f42 100644 --- a/app/common/controller/UsedCarController.php +++ b/app/common/controller/UsedCarController.php @@ -2,9 +2,11 @@ namespace app\common\controller; use app\common\controller\BaseController; +use app\common\model\UsedCar; use app\common\service\OssService; use app\common\traits\crud\CrudControllerTrait; use app\common\service\UsedCarService; +use app\common\utils\pdf\service\MpdfDriver; use support\Request; class UsedCarController extends BaseController @@ -64,6 +66,16 @@ class UsedCarController extends BaseController } $data['images_pull'] = $images_pull; + } + if (!empty($data['attachment'])){ + $attachments = explode(',', $data['attachment']); + $ossService = new OssService(); + $attachment_pull = []; + foreach ($attachments as $attachment){ + $attachment_pull[] = $ossService->generatePrivateUrl($attachment); + } + $data['attachment_pull'] = $attachment_pull; + } return $data; } @@ -77,4 +89,39 @@ class UsedCarController extends BaseController return $this->error($e->getMessage()); } } + + public function producePdf(Request $request){ + try { + $raw = $this->service->serviceShow($request); + $data = $this->transformData($raw, method_exists($this, 'showFormat') + ? [$this, 'showFormat'] + : null); + $images = []; + foreach ($data['images_pull'] as $key => $image){ + $images[] = $this->service->downloadImage($image); + } + $data['images'] = $images; + $pdf = (new MpdfDriver())->exportUsedCarPdf($data); + UsedCar::where('id', $data['id'])->update(['pdf_src' => $pdf]); + + array_map('unlink', glob(runtime_path('pdf/images/*.jpg'))); + return $this->success($pdf); + } catch (\Throwable $e) { + return $this->error($e->getMessage().$e->getLine().$e->getFile()); + } + } + + public function downloadPdf(Request $request){ + $raw = $this->service->serviceShow($request); + $filePath = runtime_path('pdf') . $raw['pdf_src']; + + if (!file_exists($filePath)) { + return response('文件不存在', 404); + } + + return response()->download( + $filePath, + $raw['product_name'].'-'.$raw['id'].'pdf' // 下载时显示的文件名 + ); + } } \ No newline at end of file diff --git a/app/common/model/UsedCar.php b/app/common/model/UsedCar.php index ebdfbb3..567ae08 100644 --- a/app/common/model/UsedCar.php +++ b/app/common/model/UsedCar.php @@ -40,7 +40,7 @@ class UsedCar extends Model /** * 允许自动填充模型字段 */ - protected $fillable = ['id', 'user_id', 'product_name', 'vin', 'price', 'source_place', 'plate_place', 'plate_time', 'displacement','mileage','power', 'body_color', 'images', 'condition_desc', 'crawl_title', 'crawl_brand', 'crawl_series', 'crawl_year', 'crawl_msrp', 'crawl_car_id', 'status', 'sort', 'created_at', 'updated_at']; + protected $fillable = ['id', 'user_id', 'product_name', 'vin', 'price', 'source_place', 'plate_place', 'plate_time', 'displacement','mileage','power', 'body_color', 'images', 'condition_desc', 'attachment', 'crawl_title', 'crawl_brand', 'crawl_series', 'crawl_year', 'crawl_msrp', 'crawl_car_id', 'status', 'sort', 'created_at', 'updated_at']; /** * 不允许自动填充模型字段 diff --git a/app/common/service/UsedCarService.php b/app/common/service/UsedCarService.php index ea7fdb9..cdf6614 100644 --- a/app/common/service/UsedCarService.php +++ b/app/common/service/UsedCarService.php @@ -250,4 +250,22 @@ class UsedCarService return null; } + + function downloadImage(string $url): string + { + $dir = runtime_path('pdf/images/'); + if (!is_dir($dir)) { + mkdir($dir, 0755, true); + } + + $filename = md5($url) . '.jpg'; + $path = $dir . $filename; + + if (!file_exists($path)) { + $img = file_get_contents($url); + file_put_contents($path, $img); + } + + return $path; + } } \ No newline at end of file diff --git a/app/common/utils/pdf/service/MpdfDriver.php b/app/common/utils/pdf/service/MpdfDriver.php index d59427a..2e9b6f8 100644 --- a/app/common/utils/pdf/service/MpdfDriver.php +++ b/app/common/utils/pdf/service/MpdfDriver.php @@ -13,43 +13,43 @@ class MpdfDriver public function htmlToPdf(string $html, array $options = []): string { $opts = array_merge([ - 'format' => 'A4', - 'orientation' => 'L', - 'margin_top' => 12, + 'format' => 'A4', + 'orientation' => 'L', + 'margin_top' => 12, 'margin_bottom' => 12, - 'margin_left' => 10, - 'margin_right' => 10, - 'tempDir' => runtime_path('mpdf'), - 'header_html' => '', - 'footer_html' => '', - 'watermark_text'=> '', - 'css_files' => [], - 'default_font' => 'notosanssc', - 'font_dirs' => [public_path('fonts')], - 'font_data' => [ - 'notosanssc' => ['R'=>'NotoSansSC-Regular.ttf','B'=>'NotoSansSC-Bold.ttf'], + 'margin_left' => 10, + 'margin_right' => 10, + 'tempDir' => runtime_path('mpdf'), + 'header_html' => '', + 'footer_html' => '', + 'watermark_text' => '', + 'css_files' => [], + 'default_font' => 'notosanssc', + 'font_dirs' => [public_path('fonts')], + 'font_data' => [ + 'notosanssc' => ['R' => 'NotoSansSC-Regular.ttf', 'B' => 'NotoSansSC-Bold.ttf'], ], - 'asset_base' => '', + 'asset_base' => '', 'enable_html5_parser' => true, ], $options); - $defaultConfig = (new ConfigVariables())->getDefaults(); + $defaultConfig = (new ConfigVariables())->getDefaults(); $defaultFontConfig = (new FontVariables())->getDefaults(); $fontDirs = array_merge($defaultConfig['fontDir'], $opts['font_dirs']); $fontData = array_merge($defaultFontConfig['fontdata'], $opts['font_data']); $mpdf = new Mpdf([ - 'format' => $opts['format'], - 'orientation' => $opts['orientation'], - 'margin_left' => $opts['margin_left'], - 'margin_right' => $opts['margin_right'], - 'margin_top' => $opts['margin_top'], + 'format' => $opts['format'], + 'orientation' => $opts['orientation'], + 'margin_left' => $opts['margin_left'], + 'margin_right' => $opts['margin_right'], + 'margin_top' => $opts['margin_top'], 'margin_bottom' => $opts['margin_bottom'], - 'tempDir' => $opts['tempDir'], - 'fontDir' => $fontDirs, - 'fontdata' => $fontData, - 'default_font' => $opts['default_font'], + 'tempDir' => $opts['tempDir'], + 'fontDir' => $fontDirs, + 'fontdata' => $fontData, + 'default_font' => $opts['default_font'], 'enable_html5_parser' => $opts['enable_html5_parser'], ]); @@ -115,4 +115,55 @@ class MpdfDriver } return [$css, $html]; } + + public function exportUsedCarPdf($car) + { + /*$car = [ + 'title' => '奥迪Q3 2013款 35 TFSI 舒适型', + 'vin' => '', + 'price' => 450000, + 'source_city' => '北京', + 'register_city' => '随州', + 'register_date' => '2026-01-05', + 'displacement' => '2.1T', + 'mileage' => 45000, + 'power' => 350, + 'color' => '', + 'created_at' => '2026-01-05 17:23:34', + 'images' => [ + 'https://xxx.com/1.jpg', + 'https://xxx.com/2.jpg', + 'https://xxx.com/3.jpg', + ], + 'description' => '该车内饰干净整洁,车况精品...' + ];*/ + + ob_start(); + //include app_path() . '/view/pdf/car_detail_pdf.php'; + $tpl = base_path('app/common/utils/pdf/template/usedCar.stub'); + include $tpl; + $html = ob_get_clean(); + + $mpdf = new Mpdf([ + 'mode' => 'utf-8', + 'format' => 'A4', + 'margin_top' => 10, + 'margin_bottom' => 10, + 'margin_left' => 10, + 'margin_right' => 10, + 'default_font' => 'sun-exta' + ]); + + $mpdf->WriteHTML($html); + + $pdf = $mpdf->Output('车辆详情.pdf', 'S'); + $dir = runtime_path('pdf'); + if (!is_dir($dir)) mkdir($dir, 0777, true); + $pdfName = '/invoice-' . date('YmdHis').'-'.$car['id'] . '.pdf'; + $path = $dir . $pdfName; + file_put_contents($path, $pdf); + + return $path; + } + } \ No newline at end of file diff --git a/app/common/utils/pdf/template/usedCar.stub b/app/common/utils/pdf/template/usedCar.stub index 9846b7a..b20384c 100644 --- a/app/common/utils/pdf/template/usedCar.stub +++ b/app/common/utils/pdf/template/usedCar.stub @@ -66,7 +66,7 @@ -

+

@@ -75,11 +75,11 @@ - + - + @@ -95,7 +95,7 @@ - + @@ -114,7 +114,7 @@

车况介绍

- +
diff --git a/composer.json b/composer.json index acc8f75..ed05bdc 100644 --- a/composer.json +++ b/composer.json @@ -46,7 +46,8 @@ "phpoffice/phpspreadsheet": "^4.5", "phpmailer/phpmailer": "^6.10", "webman/gateway-worker": "^1.0", - "jaeger/querylist": "^4.4" + "jaeger/querylist": "^4.4", + "mpdf/mpdf": "8.2" }, "suggest": { "ext-event": "For better performance. " diff --git a/config/route.php b/config/route.php index 713416e..f0503a8 100644 --- a/config/route.php +++ b/config/route.php @@ -57,6 +57,8 @@ Route::group('/common', function () { Route::group('/usedcar', function () { Route::any('/list', [app\common\controller\UsedCarController::class, 'index']); + Route::any('/produce/pdf', [app\common\controller\UsedCarController::class, 'producePdf']); + Route::any('/download/pdf', [app\common\controller\UsedCarController::class, 'downloadPdf']); Route::any('/show', [app\common\controller\UsedCarController::class, 'show']); Route::any('/store', [app\common\controller\UsedCarController::class, 'store']); Route::any('/update', [app\common\controller\UsedCarController::class, 'update']);
车源地
上牌时间
排量
车身颜色
创建时间