const form = document.querySelector('#contractForm'); const templateSelect = document.querySelector('#template'); const submitButton = document.querySelector('#submitButton'); const downloadButton = document.querySelector('#downloadButton'); const shareButton = document.querySelector('#shareButton'); const message = document.querySelector('#message'); const resultTitle = document.querySelector('#resultTitle'); const connectionStatus = document.querySelector('#connectionStatus'); let currentPdfBlob = null; let currentPdfFileName = '租屋契約.pdf'; loadTemplates(); form.addEventListener('submit', async (event) => { event.preventDefault(); setBusy(true); resetPdf(); try { const formData = new FormData(form); const response = await fetch('/api/contracts/pdf', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ template: formData.get('template'), monthlyRent: formData.get('monthlyRent'), paymentDay: formData.get('paymentDay'), deposit: formData.get('deposit'), }), }); if (!response.ok) { const errorBody = await response.json().catch(() => ({})); throw new Error(errorBody.error || 'PDF 產生失敗。'); } currentPdfBlob = await response.blob(); currentPdfFileName = getFileNameFromDisposition(response.headers.get('Content-Disposition')) || buildDefaultFileName(formData.get('template')); resultTitle.textContent = 'PDF 已產生'; message.textContent = currentPdfFileName; downloadButton.disabled = false; shareButton.disabled = !canShareCurrentPdf(); } catch (error) { resultTitle.textContent = '產生失敗'; message.textContent = error.message; } finally { setBusy(false); } }); downloadButton.addEventListener('click', () => { if (!currentPdfBlob) { return; } downloadPdf(); }); shareButton.addEventListener('click', async () => { if (!currentPdfBlob) { return; } const file = new File([currentPdfBlob], currentPdfFileName, { type: 'application/pdf' }); if (!navigator.canShare || !navigator.canShare({ files: [file] })) { downloadPdf(); return; } try { await navigator.share({ title: '租屋契約 PDF', files: [file], }); } catch (error) { if (error.name !== 'AbortError') { message.textContent = '分享失敗,已保留下載按鈕。'; } } }); async function loadTemplates() { try { const response = await fetch('/api/templates'); if (!response.ok) { throw new Error('無法讀取範本。'); } const body = await response.json(); templateSelect.replaceChildren( ...body.templates.map((name) => new Option(name, name)), ); if (body.templates.length === 0) { templateSelect.append(new Option('templates 資料夾沒有 .doc 範本', '')); templateSelect.disabled = true; submitButton.disabled = true; connectionStatus.textContent = '缺少範本'; message.textContent = '請先將 .doc 範本放進 templates 資料夾。'; return; } connectionStatus.textContent = '可使用'; } catch (error) { templateSelect.append(new Option('讀取失敗', '')); templateSelect.disabled = true; submitButton.disabled = true; connectionStatus.textContent = '離線'; message.textContent = error.message; } } function setBusy(isBusy) { submitButton.disabled = isBusy || templateSelect.disabled; submitButton.textContent = isBusy ? '產生中' : '產生 PDF'; } function resetPdf() { currentPdfBlob = null; downloadButton.disabled = true; shareButton.disabled = true; resultTitle.textContent = '產生中'; message.textContent = '正在建立 PDF。'; } function canShareCurrentPdf() { if (!currentPdfBlob || !navigator.canShare) { return false; } const file = new File([currentPdfBlob], currentPdfFileName, { type: 'application/pdf' }); return navigator.canShare({ files: [file] }); } function downloadPdf() { const url = URL.createObjectURL(currentPdfBlob); const link = document.createElement('a'); link.href = url; link.download = currentPdfFileName; document.body.append(link); link.click(); link.remove(); URL.revokeObjectURL(url); } function getFileNameFromDisposition(disposition) { if (!disposition) { return ''; } const utf8Match = disposition.match(/filename\*=UTF-8''([^;]+)/i); if (utf8Match) { return decodeURIComponent(utf8Match[1]); } const asciiMatch = disposition.match(/filename="([^"]+)"/i); return asciiMatch ? asciiMatch[1] : ''; } function buildDefaultFileName(templateName) { const baseName = String(templateName || '租屋契約').replace(/\.[^.]+$/, ''); return `${baseName}.pdf`; }