refactor: replace chromedp with browser native print for PDF export

Remove chromedp dependency, use window.print() instead. Docker image no longer needs Chromium (~200MB smaller).

- Delete services/pdf.go and templates/reports/review.html

- Remove PDF API route POST /api/repos/:id/review/pdf

- Add @media print CSS to review page

- Remove chromium from Dockerfile
This commit is contained in:
2026-06-20 22:26:46 +08:00
parent 37aa9c0a33
commit 6c60b767df
10 changed files with 88 additions and 510 deletions
+78
View File
@@ -10,6 +10,61 @@
<script src="/static/js/diff-viewer.js"></script>
<script src="/static/js/review-inline.js"></script>
<script src="/static/js/note-editor.js"></script>
<style>
@media print {
/* Hide non-content elements */
nav, footer, #review-actions, #btn-review, #btn-toggle-diff,
.note-save-indicator, select, input, #progress,
#diff-review-container, #history-select,
label[for="base-ref"], label[for="head-ref"],
label[for="top-n"], label[for="concurrency"] { display: none !important; }
/* Show results and print header even if hidden */
#results { display: block !important; }
.print-header { display: block !important; }
/* Page setup */
body { background: white !important; padding: 0 !important; font-size: 12px; }
main { max-width: 100% !important; padding: 16px !important; }
/* Cards without shadow */
.bg-white { box-shadow: none !important; border: 1px solid #e5e7eb; }
/* Avoid page breaks inside cards */
.bg-white.rounded-lg { break-inside: avoid; }
/* File review cards */
#file-reviews > div { break-inside: avoid; margin-bottom: 12px; }
/* Note editors: show content as plain text */
.note-textarea {
border: none !important;
padding: 0 !important;
resize: none !important;
height: auto !important;
overflow: visible !important;
white-space: pre-wrap;
background: #f0f9ff !important;
padding: 8px !important;
border-left: 3px solid #3b82f6 !important;
}
/* Suggestion cards: ensure colors print */
.suggestion-card { break-inside: avoid; }
* { -webkit-print-color-adjust: exact !important; print-color-adjust: exact !important; }
/* Score badge */
.rounded-full { border: 1px solid currentColor; }
/* Branch info as text */
#base-ref, #head-ref, #top-n, #concurrency {
display: inline !important;
border: none !important;
padding: 0 !important;
font-weight: 600;
}
}
</style>
</head>
<body class="bg-gray-50 min-h-screen">
{{template "nav" .}}
@@ -71,6 +126,16 @@
<!-- Results -->
<div id="results" class="hidden">
<!-- Print-only header -->
<div class="print-header hidden mb-6">
<h1 style="font-size:20px;font-weight:700;color:#111827;margin-bottom:8px;">PR-Helper 审查报告</h1>
<p style="color:#6b7280;font-size:12px;">
📦 仓库: {{.RepoURL}}
&nbsp;&nbsp;🌿 分支: <span class="print-base-ref"></span> → <span class="print-head-ref"></span>
&nbsp;&nbsp;📅 <span class="print-date"></span>
</p>
<hr style="margin-top:12px;border:none;border-top:1px solid #e5e7eb;">
</div>
<!-- Summary -->
<div id="summary" class="bg-white rounded-lg shadow-md p-6 mb-6">
<h2 class="text-lg font-semibold text-gray-900 mb-4">审查总结</h2>
@@ -357,6 +422,7 @@
document.getElementById('review-actions').classList.remove('hidden');
btn.disabled = false;
btn.textContent = '开始审查';
updatePrintHeader();
}, 500);
// Render inline suggestions if diff is available
@@ -466,6 +532,17 @@
return Markdown.render(text);
}
// Update print-only header with current branch info
function updatePrintHeader() {
const baseEl = document.getElementById('base-ref');
const headEl = document.getElementById('head-ref');
const baseText = baseEl?.options[baseEl.selectedIndex]?.text || baseEl?.value || '';
const headText = headEl?.options[headEl.selectedIndex]?.text || headEl?.value || '';
document.querySelectorAll('.print-base-ref').forEach(el => el.textContent = baseText);
document.querySelectorAll('.print-head-ref').forEach(el => el.textContent = headText);
document.querySelectorAll('.print-date').forEach(el => el.textContent = new Date().toLocaleString('zh-CN'));
}
// ── History loading ────────────────────────────────────────
async function loadHistoryList() {
@@ -539,6 +616,7 @@
// Show results
document.getElementById('results').classList.remove('hidden');
document.getElementById('review-actions').classList.remove('hidden');
updatePrintHeader();
// Load diff and render inline
const base = data.base_ref;