first
This commit is contained in:
172
server-api/app/support/ReportPdfGenerator.php
Normal file
172
server-api/app/support/ReportPdfGenerator.php
Normal file
@@ -0,0 +1,172 @@
|
||||
<?php
|
||||
|
||||
namespace app\support;
|
||||
|
||||
class ReportPdfGenerator
|
||||
{
|
||||
public function generate(array $payload): string
|
||||
{
|
||||
$content = $this->buildContentStream($payload);
|
||||
|
||||
$objects = [
|
||||
1 => '<< /Type /Catalog /Pages 2 0 R >>',
|
||||
2 => '<< /Type /Pages /Kids [3 0 R] /Count 1 >>',
|
||||
3 => '<< /Type /Page /Parent 2 0 R /MediaBox [0 0 595 842] /Resources << /Font << /F1 5 0 R >> >> /Contents 4 0 R >>',
|
||||
4 => sprintf("<< /Length %d >>\nstream\n%s\nendstream", strlen($content), $content),
|
||||
5 => '<< /Type /Font /Subtype /Type0 /BaseFont /STSong-Light /Encoding /UniGB-UCS2-H /DescendantFonts [6 0 R] >>',
|
||||
6 => '<< /Type /Font /Subtype /CIDFontType0 /BaseFont /STSong-Light /CIDSystemInfo << /Registry (Adobe) /Ordering (GB1) /Supplement 4 >> /DW 1000 >>',
|
||||
];
|
||||
|
||||
return $this->renderPdf($objects);
|
||||
}
|
||||
|
||||
private function buildContentStream(array $payload): string
|
||||
{
|
||||
$title = $this->normalizeText((string)($payload['report_title'] ?? '鉴定报告'));
|
||||
$serviceProviderText = $this->normalizeText((string)($payload['service_provider_text'] ?? '-'));
|
||||
$institutionName = $this->normalizeText((string)($payload['institution_name'] ?? '-'));
|
||||
$reportNo = $this->normalizeText((string)($payload['report_no'] ?? '-'));
|
||||
$publishTime = $this->normalizeText((string)($payload['publish_time'] ?? '-'));
|
||||
$resultText = $this->normalizeText((string)($payload['result_text'] ?? '-'));
|
||||
$resultDesc = $this->normalizeText((string)($payload['result_desc'] ?? '-'));
|
||||
$productName = $this->normalizeText((string)($payload['product_name'] ?? '-'));
|
||||
$categoryBrand = $this->normalizeText((string)($payload['category_brand'] ?? '-'));
|
||||
$specInfo = $this->normalizeText((string)($payload['spec_info'] ?? '-'));
|
||||
$appraisers = $this->normalizeText((string)($payload['appraisers'] ?? '-'));
|
||||
$conditionGrade = $this->normalizeText((string)($payload['condition_grade'] ?? '-'));
|
||||
$valuationRange = $this->normalizeText((string)($payload['valuation_range'] ?? '-'));
|
||||
$verifyInfo = $this->normalizeText((string)($payload['verify_info'] ?? '-'));
|
||||
$riskNotice = $this->normalizeText((string)($payload['risk_notice_text'] ?? '-'));
|
||||
|
||||
$blocks = [];
|
||||
$y = 790;
|
||||
|
||||
$blocks[] = $this->textBlock($title, 52, $y, 20);
|
||||
$y -= 32;
|
||||
$blocks[] = $this->textBlock('正式报告凭证,请以编号验真结果为准。', 52, $y, 10);
|
||||
$y -= 30;
|
||||
|
||||
foreach ([
|
||||
sprintf('报告编号:%s', $reportNo),
|
||||
sprintf('出具机构:%s', $institutionName),
|
||||
sprintf('出具时间:%s', $publishTime),
|
||||
sprintf('服务类型:%s', $serviceProviderText),
|
||||
] as $line) {
|
||||
$blocks[] = $this->textBlock($line, 52, $y, 12);
|
||||
$y -= 22;
|
||||
}
|
||||
|
||||
$y -= 8;
|
||||
$blocks[] = $this->textBlock(sprintf('鉴定结论:%s', $resultText), 52, $y, 16);
|
||||
$y -= 26;
|
||||
|
||||
foreach ($this->wrapText('结果说明:' . $resultDesc, 30) as $line) {
|
||||
$blocks[] = $this->textBlock($line, 52, $y, 11);
|
||||
$y -= 18;
|
||||
}
|
||||
|
||||
$y -= 8;
|
||||
foreach ([
|
||||
sprintf('商品名称:%s', $productName),
|
||||
sprintf('品类 / 品牌:%s', $categoryBrand),
|
||||
sprintf('颜色 / 规格:%s', $specInfo),
|
||||
sprintf('鉴定师:%s', $appraisers),
|
||||
sprintf('成色评级:%s', $conditionGrade),
|
||||
sprintf('估值区间:%s', $valuationRange),
|
||||
sprintf('验真信息:%s', $verifyInfo),
|
||||
] as $line) {
|
||||
$blocks[] = $this->textBlock($line, 52, $y, 11);
|
||||
$y -= 20;
|
||||
}
|
||||
|
||||
$y -= 8;
|
||||
foreach ($this->wrapText('风险说明:' . $riskNotice, 30) as $line) {
|
||||
$blocks[] = $this->textBlock($line, 52, $y, 10);
|
||||
$y -= 17;
|
||||
}
|
||||
|
||||
if ($y > 48) {
|
||||
$blocks[] = $this->textBlock('安心验鉴定平台', 52, 42, 9);
|
||||
}
|
||||
|
||||
return implode("\n", array_filter($blocks));
|
||||
}
|
||||
|
||||
private function wrapText(string $text, int $maxUnits): array
|
||||
{
|
||||
$normalized = $this->normalizeText($text);
|
||||
if ($normalized === '') {
|
||||
return ['-'];
|
||||
}
|
||||
|
||||
$chars = preg_split('//u', $normalized, -1, PREG_SPLIT_NO_EMPTY) ?: [];
|
||||
$lines = [];
|
||||
$current = '';
|
||||
$width = 0.0;
|
||||
|
||||
foreach ($chars as $char) {
|
||||
$charWidth = strlen($char) === 1 && ord($char) < 128 ? 0.5 : 1.0;
|
||||
if ($current !== '' && $width + $charWidth > $maxUnits) {
|
||||
$lines[] = $current;
|
||||
$current = '';
|
||||
$width = 0.0;
|
||||
}
|
||||
$current .= $char;
|
||||
$width += $charWidth;
|
||||
}
|
||||
|
||||
if ($current !== '') {
|
||||
$lines[] = $current;
|
||||
}
|
||||
|
||||
return $lines ?: ['-'];
|
||||
}
|
||||
|
||||
private function textBlock(string $text, int $x, int $y, int $fontSize): string
|
||||
{
|
||||
if ($text === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
return sprintf(
|
||||
"BT\n/F1 %d Tf\n1 0 0 1 %d %d Tm\n<%s> Tj\nET",
|
||||
$fontSize,
|
||||
$x,
|
||||
$y,
|
||||
strtoupper(bin2hex(mb_convert_encoding($text, 'UCS-2BE', 'UTF-8')))
|
||||
);
|
||||
}
|
||||
|
||||
private function normalizeText(string $text): string
|
||||
{
|
||||
$text = trim(str_replace(["\r\n", "\r", "\n", "\t"], [' ', ' ', ' ', ' '], $text));
|
||||
return preg_replace('/\s+/u', ' ', $text) ?: '';
|
||||
}
|
||||
|
||||
private function renderPdf(array $objects): string
|
||||
{
|
||||
$pdf = "%PDF-1.4\n%\xE2\xE3\xCF\xD3\n";
|
||||
$offsets = [];
|
||||
|
||||
foreach ($objects as $id => $body) {
|
||||
$offsets[$id] = strlen($pdf);
|
||||
$pdf .= sprintf("%d 0 obj\n%s\nendobj\n", $id, $body);
|
||||
}
|
||||
|
||||
$xrefPosition = strlen($pdf);
|
||||
$pdf .= sprintf("xref\n0 %d\n", count($objects) + 1);
|
||||
$pdf .= "0000000000 65535 f \n";
|
||||
|
||||
foreach ($objects as $id => $_body) {
|
||||
$pdf .= sprintf("%010d 00000 n \n", $offsets[$id]);
|
||||
}
|
||||
|
||||
$pdf .= sprintf(
|
||||
"trailer\n<< /Size %d /Root 1 0 R >>\nstartxref\n%d\n%%%%EOF",
|
||||
count($objects) + 1,
|
||||
$xrefPosition
|
||||
);
|
||||
|
||||
return $pdf;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user