审批&PDF生成

This commit is contained in:
mzl
2025-09-08 11:34:19 +08:00
parent 8a4848bc75
commit 28368e27a7
30 changed files with 1269 additions and 980 deletions
@@ -0,0 +1,80 @@
<?php
// app/service/pdf/PdfHelper.php
namespace app\common\utils\pdf\service;
class PdfHelper
{
/** 从文件加载 HTML(支持占位符 {{key}} 简单替换) */
public static function loadTemplate(string $file, array $vars = []): string
{
if (!is_file($file)) {
throw new \RuntimeException("Template not found: {$file}");
}
$html = file_get_contents($file);
if ($vars) {
$search = [];
$replace = [];
foreach ($vars as $k => $v) {
$search[] = '{{' . $k . '}}';
$replace[] = htmlspecialchars((string)$v, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
}
$html = str_replace($search, $replace, $html);
}
return $html;
}
/**
* 把 HTML 里的相对资源路径(img/link/script href/src)改成绝对路径
* 仅处理以 ./ ../ 或非 http(s) 的相对量;base 传 public/assets/pdf 等目录
*/
public static function absolutizeAssetUrls(string $html, string $baseDir): string
{
$baseDir = rtrim($baseDir, DIRECTORY_SEPARATOR);
// img src
$html = preg_replace_callback('#(<img[^>]+src=["\'])([^"\']+)(["\'])#i', function($m) use ($baseDir){
$u = $m[2];
if (preg_match('#^https?://#i', $u) || strpos($u, 'data:') === 0) return $m[0];
$abs = realpath($baseDir . DIRECTORY_SEPARATOR . ltrim($u, '/')) ?: ($baseDir . '/' . ltrim($u, '/'));
return $m[1] . $abs . $m[3];
}, $html);
// link href(如果你在 HTML 里写了 <link>,通常建议走 css_files 方式,这里也兼容)
$html = preg_replace_callback('#(<link[^>]+href=["\'])([^"\']+)(["\'])#i', function($m) use ($baseDir){
$u = $m[2];
if (preg_match('#^https?://#i', $u)) return $m[0];
$abs = realpath($baseDir . DIRECTORY_SEPARATOR . ltrim($u, '/')) ?: ($baseDir . '/' . ltrim($u, '/'));
return $m[1] . $abs . $m[3];
}, $html);
return $html;
}
/**
* 渲染一个原生 PHP 模板为字符串
* @param string $file 模板路径(如 resource/templates/stock-order.php)
* @param array $vars 将在模板中以变量名存在(如 $data)
* @return string 完整 HTML
*/
public static function render(string $file, array $vars = []): string
{
if (!is_file($file)) {
throw new \RuntimeException("Template not found: {$file}");
}
// 将键名导出为同名变量,例如 'data' => [...] 变为 $data
extract($vars, EXTR_OVERWRITE);
// 开启缓冲,将 include 的输出抓取为字符串
ob_start();
ob_implicit_flush(false);
try {
/** @noinspection PhpIncludeInspection */
include $file;
} catch (\Throwable $e) {
// 清理缓冲并抛出更清晰的异常
ob_end_clean();
throw $e;
}
return ob_get_clean();
}
}