新增租屋契約工具與 HTML 版本備份
This commit is contained in:
317
html_backup_versions_20260514/v1_contract_template_tool.html
Normal file
317
html_backup_versions_20260514/v1_contract_template_tool.html
Normal file
@@ -0,0 +1,317 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-Hant">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>租屋契約 Placeholder 工具</title>
|
||||
<style>
|
||||
:root {
|
||||
--bg: #f4efe6;
|
||||
--panel: rgba(255, 252, 246, 0.92);
|
||||
--panel-strong: #fffaf1;
|
||||
--text: #2b2118;
|
||||
--muted: #746657;
|
||||
--line: #d8c9b5;
|
||||
--accent: #a34b2a;
|
||||
--accent-strong: #7f3519;
|
||||
--shadow: 0 18px 45px rgba(82, 51, 28, 0.12);
|
||||
}
|
||||
|
||||
* { box-sizing: border-box; }
|
||||
body {
|
||||
margin: 0;
|
||||
min-height: 100vh;
|
||||
font-family: "Segoe UI", "Noto Sans TC", sans-serif;
|
||||
color: var(--text);
|
||||
background:
|
||||
radial-gradient(circle at top left, rgba(163, 75, 42, 0.12), transparent 32%),
|
||||
radial-gradient(circle at right 20%, rgba(123, 85, 48, 0.15), transparent 28%),
|
||||
linear-gradient(135deg, #f8f3eb 0%, #efe3d1 100%);
|
||||
}
|
||||
.shell {
|
||||
width: min(1280px, calc(100% - 32px));
|
||||
margin: 24px auto;
|
||||
padding: 24px;
|
||||
border: 1px solid rgba(216, 201, 181, 0.8);
|
||||
border-radius: 24px;
|
||||
background: rgba(255, 248, 238, 0.78);
|
||||
backdrop-filter: blur(12px);
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
.hero {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: end;
|
||||
gap: 16px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
h1 {
|
||||
margin: 0;
|
||||
font-size: clamp(28px, 4vw, 42px);
|
||||
line-height: 1.05;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
.subtitle {
|
||||
margin: 8px 0 0;
|
||||
color: var(--muted);
|
||||
font-size: 15px;
|
||||
}
|
||||
.meta {
|
||||
color: var(--muted);
|
||||
font-size: 13px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.layout {
|
||||
display: grid;
|
||||
grid-template-columns: 1.1fr 0.9fr;
|
||||
gap: 20px;
|
||||
}
|
||||
.panel {
|
||||
background: var(--panel);
|
||||
border: 1px solid rgba(216, 201, 181, 0.9);
|
||||
border-radius: 20px;
|
||||
padding: 18px;
|
||||
}
|
||||
.panel h2 {
|
||||
margin: 0 0 12px;
|
||||
font-size: 18px;
|
||||
}
|
||||
.toolbar {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
button {
|
||||
border: 0;
|
||||
border-radius: 999px;
|
||||
padding: 11px 16px;
|
||||
font: inherit;
|
||||
cursor: pointer;
|
||||
transition: transform 0.18s ease, opacity 0.18s ease, background 0.18s ease;
|
||||
}
|
||||
button:hover { transform: translateY(-1px); }
|
||||
.primary {
|
||||
color: #fff9f3;
|
||||
background: linear-gradient(135deg, var(--accent), var(--accent-strong));
|
||||
}
|
||||
.secondary {
|
||||
color: var(--text);
|
||||
background: #eadcc9;
|
||||
}
|
||||
textarea, input {
|
||||
width: 100%;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 14px;
|
||||
background: var(--panel-strong);
|
||||
color: var(--text);
|
||||
font: inherit;
|
||||
}
|
||||
textarea {
|
||||
min-height: 460px;
|
||||
padding: 16px;
|
||||
resize: vertical;
|
||||
line-height: 1.65;
|
||||
}
|
||||
.fields {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||||
gap: 12px;
|
||||
margin-top: 14px;
|
||||
}
|
||||
label {
|
||||
display: block;
|
||||
font-size: 13px;
|
||||
color: var(--muted);
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.field-card {
|
||||
padding: 12px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 16px;
|
||||
background: rgba(255, 251, 245, 0.94);
|
||||
}
|
||||
input { padding: 10px 12px; }
|
||||
.output {
|
||||
white-space: pre-wrap;
|
||||
min-height: 640px;
|
||||
padding: 16px;
|
||||
border-radius: 16px;
|
||||
border: 1px dashed var(--line);
|
||||
background: linear-gradient(180deg, rgba(255, 252, 246, 0.95), rgba(248, 239, 226, 0.95));
|
||||
line-height: 1.75;
|
||||
}
|
||||
.hint {
|
||||
margin-top: 12px;
|
||||
color: var(--muted);
|
||||
font-size: 13px;
|
||||
}
|
||||
.empty { color: #9a856f; }
|
||||
@media (max-width: 900px) {
|
||||
.layout { grid-template-columns: 1fr; }
|
||||
.hero { flex-direction: column; align-items: start; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="shell">
|
||||
<div class="hero">
|
||||
<div>
|
||||
<h1>租屋契約 Placeholder 工具</h1>
|
||||
<p class="subtitle">編輯模板後,系統會自動抓出 `{{placeholder}}` 欄位,填完就能複製一份套入好的契約內容。</p>
|
||||
</div>
|
||||
<div class="meta" id="timeLabel">台北時間:載入中</div>
|
||||
</div>
|
||||
<div class="layout">
|
||||
<section class="panel">
|
||||
<h2>契約模板</h2>
|
||||
<div class="toolbar">
|
||||
<button class="secondary" id="resetTemplate">還原預設模板</button>
|
||||
<button class="secondary" id="refreshFields">重新抓 placeholder</button>
|
||||
</div>
|
||||
<textarea id="templateInput"></textarea>
|
||||
<div class="fields" id="fields"></div>
|
||||
</section>
|
||||
<section class="panel">
|
||||
<h2>帶入後內容</h2>
|
||||
<div class="toolbar">
|
||||
<button class="primary" id="copyOutput">複製契約內容</button>
|
||||
<button class="secondary" id="copyHtml">複製為 HTML 換行格式</button>
|
||||
</div>
|
||||
<div class="output empty" id="output">尚未產生內容</div>
|
||||
<div class="hint">提示:如果你之後想新增欄位,只要在左邊模板加上 `{{欄位名稱}}`,下方就會自動出現可填欄位。</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
const defaultTemplate = `房屋租賃契約
|
||||
立契約書人 出租人 廖雅惠 (以下簡稱為甲方)
|
||||
承租人 {{承租人}} (以下簡稱為乙方)
|
||||
因房屋租賃事件,訂立本契約,雙方同意之條件如左:
|
||||
房屋所在地及使用範圍:台中市西屯區西平里文華路 217-5 號 2 樓 A 室
|
||||
第二條 租賃期限:自民國 {{租賃開始年}} 年 {{租賃開始月}} 月 {{租賃開始日}} 日至 {{租賃結束年}} 年 {{租賃結束月}} 月 {{租賃結束日}} 日止計 {{租期年數}} 年。
|
||||
第三條 租金:
|
||||
1. 每月租金新台幣 {{每月租金}} 元,每月 {{繳款日期}} 日以前繳納。
|
||||
2. 保證金新台幣 {{保證金}} 元,於租賃期滿交還。
|
||||
3. 包(管理費、網路、安博盒子)
|
||||
4. 附(電視、冷氣、冰箱、洗衣機、雙人床、書桌、衣櫃、椅子)
|
||||
第四條 使用租賃物之限制:
|
||||
1. 本房屋係供住家之用。
|
||||
2. 未經甲方同意,乙方不得將房屋全部或一部轉租、出借、頂讓,或以其他變相方法由他人使用房屋。
|
||||
3. 乙方於租賃期滿應即將房屋遷讓交還,不得向甲方請求遷移費或任何費用。
|
||||
4. 房屋不得供非法使用,或存放危險物品影響公共安全。
|
||||
5. 房屋有改裝設施之必要,乙方取得甲方之同意後得自行裝設,但不得損害原有建築,乙方於交還房屋時應負責回復原狀,不可以在牆上張貼任何物品如海報、公佈欄。
|
||||
第五條 危險負擔:乙方應以善良管理人之注意使用房屋,除因天災地變等不可抗拒之情形外,因乙方之過失致房屋毀損,應負損害賠償之責。房屋因自然之損壞有修繕必要時,由甲方負責修理。
|
||||
第六條 違約處罰:
|
||||
1. 乙方違反約定方法使用房屋,或拖欠租金,經甲方催告限期繳納仍不支付時,甲方得終止租約。
|
||||
2. 乙方於終止租約或租賃期滿不交還房屋,自終止租約或租賃期滿之歷日起,乙方應支付按房租壹倍計算之違約金。
|
||||
第七條 其他特約事項:
|
||||
1. 乙方遷出時,如遺留傢俱雜物不搬者,視為放棄,應由甲方處理及留存最後一期水電單以便結水電及退押金。
|
||||
2. 本契約租賃期限未滿,住滿半年需扣一個月押金,但需提前一個月告知及配合看屋。及一個月房租沒付房東可請房客遷出。
|
||||
3. 退租時必須將房屋打掃乾淨,否則收 800 元清潔費,不得養寵物,房間禁菸,被發現強制退租及扣 2 個月押金。
|
||||
4. 合約到期前一個月如不續租,須告知房東,並配合給其他房客看屋。
|
||||
5. 牆壁上不可張貼紙張或釘任何物品例如公佈欄。
|
||||
6. 如惡意輕生必須賠償甲方當初購屋款及裝潢費用新台幣 150 萬元整。
|
||||
7. 電費 1 度 5 元,每月與房租計算。
|
||||
第八條 應受強制執行之事項:承租人給付租金或期限屆滿交還租賃物,出租人返還保證金,如不履行應逕送強制執行。
|
||||
|
||||
出租人:廖雅惠
|
||||
地址:台中市西屯區西平里文華路 217-5 號 2 樓 A 室
|
||||
電話:0918298185
|
||||
|
||||
承租人:{{承租人}}
|
||||
簽章:{{承租人簽章}}
|
||||
身份證號:{{身份證號}}
|
||||
緊急聯絡人:{{緊急聯絡人}}
|
||||
地址:{{承租人地址}}
|
||||
電話:{{承租人電話}}
|
||||
匯款帳號:{{匯款帳號}}
|
||||
|
||||
中華民國 {{簽約年}} 年 {{簽約月}} 月 {{簽約日}} 日`;
|
||||
const templateInput = document.getElementById("templateInput");
|
||||
const fieldsContainer = document.getElementById("fields");
|
||||
const output = document.getElementById("output");
|
||||
const timeLabel = document.getElementById("timeLabel");
|
||||
const values = {};
|
||||
function updateTaipeiTime() {
|
||||
const formatter = new Intl.DateTimeFormat("zh-TW", {
|
||||
timeZone: "Asia/Taipei", year: "numeric", month: "2-digit", day: "2-digit",
|
||||
hour: "2-digit", minute: "2-digit", second: "2-digit", hour12: false
|
||||
});
|
||||
timeLabel.textContent = `台北時間:${formatter.format(new Date())}`;
|
||||
}
|
||||
function getPlaceholders(template) {
|
||||
const matches = template.match(/{{\s*[^{}]+\s*}}/g) || [];
|
||||
const names = matches.map(item => item.replace(/[{}]/g, "").trim());
|
||||
return [...new Set(names)];
|
||||
}
|
||||
function renderFields() {
|
||||
const placeholders = getPlaceholders(templateInput.value);
|
||||
fieldsContainer.innerHTML = "";
|
||||
placeholders.forEach(name => {
|
||||
const card = document.createElement("div");
|
||||
card.className = "field-card";
|
||||
const label = document.createElement("label");
|
||||
label.setAttribute("for", `field-${name}`);
|
||||
label.textContent = name;
|
||||
const input = document.createElement("input");
|
||||
input.id = `field-${name}`;
|
||||
input.type = "text";
|
||||
input.value = values[name] || "";
|
||||
input.placeholder = `請輸入 ${name}`;
|
||||
input.addEventListener("input", () => {
|
||||
values[name] = input.value;
|
||||
renderOutput();
|
||||
});
|
||||
card.append(label, input);
|
||||
fieldsContainer.appendChild(card);
|
||||
});
|
||||
if (placeholders.length === 0) {
|
||||
fieldsContainer.innerHTML = '<div class="field-card">目前模板裡沒有偵測到 `{{placeholder}}`。</div>';
|
||||
}
|
||||
}
|
||||
function renderOutput() {
|
||||
const compiled = templateInput.value.replace(/{{\s*([^{}]+)\s*}}/g, (_, key) => values[key.trim()] ?? "");
|
||||
if (compiled.trim()) {
|
||||
output.textContent = compiled;
|
||||
output.classList.remove("empty");
|
||||
} else {
|
||||
output.textContent = "尚未產生內容";
|
||||
output.classList.add("empty");
|
||||
}
|
||||
}
|
||||
async function copyText(text) { await navigator.clipboard.writeText(text); }
|
||||
document.getElementById("resetTemplate").addEventListener("click", () => {
|
||||
templateInput.value = defaultTemplate;
|
||||
renderFields();
|
||||
renderOutput();
|
||||
});
|
||||
document.getElementById("refreshFields").addEventListener("click", () => {
|
||||
renderFields();
|
||||
renderOutput();
|
||||
});
|
||||
templateInput.addEventListener("input", () => {
|
||||
renderFields();
|
||||
renderOutput();
|
||||
});
|
||||
document.getElementById("copyOutput").addEventListener("click", async () => {
|
||||
try { await copyText(output.textContent); alert("已複製契約內容"); }
|
||||
catch { alert("複製失敗,請確認瀏覽器是否允許剪貼簿權限。"); }
|
||||
});
|
||||
document.getElementById("copyHtml").addEventListener("click", async () => {
|
||||
try {
|
||||
const htmlText = output.textContent.replace(/\n/g, "<br>\n");
|
||||
await copyText(htmlText);
|
||||
alert("已複製 HTML 換行格式");
|
||||
} catch {
|
||||
alert("複製失敗,請確認瀏覽器是否允許剪貼簿權限。");
|
||||
}
|
||||
});
|
||||
templateInput.value = defaultTemplate;
|
||||
renderFields();
|
||||
renderOutput();
|
||||
updateTaipeiTime();
|
||||
setInterval(updateTaipeiTime, 1000);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
299
html_backup_versions_20260514/v2_contract_template_tool.html
Normal file
299
html_backup_versions_20260514/v2_contract_template_tool.html
Normal file
@@ -0,0 +1,299 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-Hant">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>租屋契約 Placeholder 工具</title>
|
||||
<style>
|
||||
:root {
|
||||
--bg: #f4efe6;
|
||||
--panel: rgba(255, 252, 246, 0.92);
|
||||
--panel-strong: #fffaf1;
|
||||
--text: #2b2118;
|
||||
--muted: #746657;
|
||||
--line: #d8c9b5;
|
||||
--accent: #a34b2a;
|
||||
--accent-strong: #7f3519;
|
||||
--shadow: 0 18px 45px rgba(82, 51, 28, 0.12);
|
||||
}
|
||||
* { box-sizing: border-box; }
|
||||
body {
|
||||
margin: 0;
|
||||
min-height: 100vh;
|
||||
font-family: "Segoe UI", "Noto Sans TC", sans-serif;
|
||||
color: var(--text);
|
||||
background:
|
||||
radial-gradient(circle at top left, rgba(163, 75, 42, 0.12), transparent 32%),
|
||||
radial-gradient(circle at right 20%, rgba(123, 85, 48, 0.15), transparent 28%),
|
||||
linear-gradient(135deg, #f8f3eb 0%, #efe3d1 100%);
|
||||
}
|
||||
.shell {
|
||||
width: min(1280px, calc(100% - 32px));
|
||||
margin: 24px auto;
|
||||
padding: 24px;
|
||||
border: 1px solid rgba(216, 201, 181, 0.8);
|
||||
border-radius: 24px;
|
||||
background: rgba(255, 248, 238, 0.78);
|
||||
backdrop-filter: blur(12px);
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
.hero {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: end;
|
||||
gap: 16px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
h1 {
|
||||
margin: 0;
|
||||
font-size: clamp(28px, 4vw, 42px);
|
||||
line-height: 1.05;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
.subtitle {
|
||||
margin: 8px 0 0;
|
||||
color: var(--muted);
|
||||
font-size: 15px;
|
||||
}
|
||||
.meta {
|
||||
color: var(--muted);
|
||||
font-size: 13px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.layout {
|
||||
display: grid;
|
||||
grid-template-columns: 1.1fr 0.9fr;
|
||||
gap: 20px;
|
||||
}
|
||||
.panel {
|
||||
background: var(--panel);
|
||||
border: 1px solid rgba(216, 201, 181, 0.9);
|
||||
border-radius: 20px;
|
||||
padding: 18px;
|
||||
}
|
||||
.panel h2 {
|
||||
margin: 0 0 12px;
|
||||
font-size: 18px;
|
||||
}
|
||||
.toolbar {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
button {
|
||||
border: 0;
|
||||
border-radius: 999px;
|
||||
padding: 11px 16px;
|
||||
font: inherit;
|
||||
cursor: pointer;
|
||||
transition: transform 0.18s ease, opacity 0.18s ease, background 0.18s ease;
|
||||
}
|
||||
button:hover { transform: translateY(-1px); }
|
||||
.primary {
|
||||
color: #fff9f3;
|
||||
background: linear-gradient(135deg, var(--accent), var(--accent-strong));
|
||||
}
|
||||
.secondary {
|
||||
color: var(--text);
|
||||
background: #eadcc9;
|
||||
}
|
||||
textarea, input {
|
||||
width: 100%;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 14px;
|
||||
background: var(--panel-strong);
|
||||
color: var(--text);
|
||||
font: inherit;
|
||||
}
|
||||
textarea {
|
||||
min-height: 460px;
|
||||
padding: 16px;
|
||||
resize: vertical;
|
||||
line-height: 1.65;
|
||||
}
|
||||
.fields {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||||
gap: 12px;
|
||||
margin-top: 14px;
|
||||
}
|
||||
label {
|
||||
display: block;
|
||||
font-size: 13px;
|
||||
color: var(--muted);
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.field-card {
|
||||
padding: 12px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 16px;
|
||||
background: rgba(255, 251, 245, 0.94);
|
||||
}
|
||||
input { padding: 10px 12px; }
|
||||
.output {
|
||||
white-space: pre-wrap;
|
||||
min-height: 640px;
|
||||
padding: 16px;
|
||||
border-radius: 16px;
|
||||
border: 1px dashed var(--line);
|
||||
background: linear-gradient(180deg, rgba(255, 252, 246, 0.95), rgba(248, 239, 226, 0.95));
|
||||
line-height: 1.75;
|
||||
}
|
||||
.hint {
|
||||
margin-top: 12px;
|
||||
color: var(--muted);
|
||||
font-size: 13px;
|
||||
}
|
||||
.empty { color: #9a856f; }
|
||||
@media (max-width: 900px) {
|
||||
.layout { grid-template-columns: 1fr; }
|
||||
.hero { flex-direction: column; align-items: start; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="shell">
|
||||
<div class="hero">
|
||||
<div>
|
||||
<h1>租屋契約 Placeholder 工具</h1>
|
||||
<p class="subtitle">只要填入 `每月租金`、`繳款日期`、`保證金`,右邊就會自動產生可複製的契約內容。</p>
|
||||
</div>
|
||||
<div class="meta" id="timeLabel">台北時間:載入中</div>
|
||||
</div>
|
||||
<div class="layout">
|
||||
<section class="panel">
|
||||
<h2>契約模板</h2>
|
||||
<div class="toolbar">
|
||||
<button class="secondary" id="resetTemplate">還原預設內容</button>
|
||||
</div>
|
||||
<textarea id="templateInput" readonly></textarea>
|
||||
<div class="fields" id="fields"></div>
|
||||
</section>
|
||||
<section class="panel">
|
||||
<h2>帶入後內容</h2>
|
||||
<div class="toolbar">
|
||||
<button class="primary" id="copyOutput">複製契約內容</button>
|
||||
<button class="secondary" id="copyHtml">複製為 HTML 換行格式</button>
|
||||
</div>
|
||||
<div class="output empty" id="output">尚未產生內容</div>
|
||||
<div class="hint">提示:這個版本固定只提供 3 個欄位,適合你現在直接快速填資料用。</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
const defaultTemplate = `房屋租賃契約
|
||||
立契約書人 出租人 廖雅惠 (以下簡稱為甲方)
|
||||
承租人 (以下簡稱為乙方)
|
||||
因房屋租賃事件,訂立本契約,雙方同意之條件如左:
|
||||
房屋所在地及使用範圍:台中市西屯區西平里文華路 217-5 號 2 樓 A 室
|
||||
第二條 租賃期限:自民國 114 年 6 月 18 日至 115 年 6 月 17 日止計 1 年。
|
||||
第三條 租金:
|
||||
1. 每月租金新台幣 {{每月租金}} 元,每月 {{繳款日期}} 日以前繳納。
|
||||
2. 保證金新台幣 {{保證金}} 元,於租賃期滿交還。
|
||||
3. 包(管理費、網路、安博盒子)
|
||||
4. 附(電視、冷氣、冰箱、洗衣機、雙人床、書桌、衣櫃、椅子)
|
||||
第四條 使用租賃物之限制:
|
||||
1. 本房屋係供住家之用。
|
||||
2. 未經甲方同意,乙方不得將房屋全部或一部轉租、出借、頂讓,或以其他變相方法由他人使用房屋。
|
||||
3. 乙方於租賃期滿應即將房屋遷讓交還,不得向甲方請求遷移費或任何費用。
|
||||
4. 房屋不得供非法使用,或存放危險物品影響公共安全。
|
||||
5. 房屋有改裝設施之必要,乙方取得甲方之同意後得自行裝設,但不得損害原有建築,乙方於交還房屋時應負責回復原狀,不可以在牆上張貼任何物品如海報、公佈欄。
|
||||
第五條 危險負擔:乙方應以善良管理人之注意使用房屋,除因天災地變等不可抗拒之情形外,因乙方之過失致房屋毀損,應負損害賠償之責。房屋因自然之損壞有修繕必要時,由甲方負責修理。
|
||||
第六條 違約處罰:
|
||||
1. 乙方違反約定方法使用房屋,或拖欠租金,經甲方催告限期繳納仍不支付時,甲方得終止租約。
|
||||
2. 乙方於終止租約或租賃期滿不交還房屋,自終止租約或租賃期滿之歷日起,乙方應支付按房租壹倍計算之違約金。
|
||||
第七條 其他特約事項:
|
||||
1. 乙方遷出時,如遺留傢俱雜物不搬者,視為放棄,應由甲方處理及留存最後一期水電單以便結水電及退押金。
|
||||
2. 本契約租賃期限未滿,住滿半年需扣一個月押金,但需提前一個月告知及配合看屋。及一個月房租沒付房東可請房客遷出。
|
||||
3. 退租時必須將房屋打掃乾淨,否則收 800 元清潔費,不得養寵物,房間禁菸,被發現強制退租及扣 2 個月押金。
|
||||
4. 合約到期前一個月如不續租,須告知房東,並配合給其他房客看屋。
|
||||
5. 牆壁上不可張貼紙張或釘任何物品例如公佈欄。
|
||||
6. 如惡意輕生必須賠償甲方當初購屋款及裝潢費用新台幣 150 萬元整。
|
||||
7. 電費 1 度 5 元,每月與房租計算。
|
||||
第八條 應受強制執行之事項:承租人給付租金或期限屆滿交還租賃物,出租人返還保證金,如不履行應逕送強制執行。
|
||||
|
||||
出租人:廖雅惠
|
||||
地址:台中市西屯區西平里文華路 217-5 號 2 樓 A 室
|
||||
電話:0918298185
|
||||
|
||||
承租人:
|
||||
簽章:
|
||||
身份證號:
|
||||
緊急聯絡人:
|
||||
地址:
|
||||
電話:
|
||||
匯款帳號:
|
||||
|
||||
中華民國 年 月 日`;
|
||||
const templateInput = document.getElementById("templateInput");
|
||||
const fieldsContainer = document.getElementById("fields");
|
||||
const output = document.getElementById("output");
|
||||
const timeLabel = document.getElementById("timeLabel");
|
||||
const values = { "每月租金": "", "繳款日期": "", "保證金": "" };
|
||||
const allowedFields = ["每月租金", "繳款日期", "保證金"];
|
||||
function updateTaipeiTime() {
|
||||
const formatter = new Intl.DateTimeFormat("zh-TW", {
|
||||
timeZone: "Asia/Taipei", year: "numeric", month: "2-digit", day: "2-digit",
|
||||
hour: "2-digit", minute: "2-digit", second: "2-digit", hour12: false
|
||||
});
|
||||
timeLabel.textContent = `台北時間:${formatter.format(new Date())}`;
|
||||
}
|
||||
function renderFields() {
|
||||
fieldsContainer.innerHTML = "";
|
||||
allowedFields.forEach(name => {
|
||||
const card = document.createElement("div");
|
||||
card.className = "field-card";
|
||||
const label = document.createElement("label");
|
||||
label.setAttribute("for", `field-${name}`);
|
||||
label.textContent = name;
|
||||
const input = document.createElement("input");
|
||||
input.id = `field-${name}`;
|
||||
input.type = "text";
|
||||
input.value = values[name] || "";
|
||||
input.placeholder = `請輸入 ${name}`;
|
||||
input.addEventListener("input", () => {
|
||||
values[name] = input.value;
|
||||
renderOutput();
|
||||
});
|
||||
card.append(label, input);
|
||||
fieldsContainer.appendChild(card);
|
||||
});
|
||||
}
|
||||
function renderOutput() {
|
||||
const compiled = templateInput.value.replace(/{{\s*([^{}]+)\s*}}/g, (_, key) => values[key.trim()] ?? "");
|
||||
if (compiled.trim()) {
|
||||
output.textContent = compiled;
|
||||
output.classList.remove("empty");
|
||||
} else {
|
||||
output.textContent = "尚未產生內容";
|
||||
output.classList.add("empty");
|
||||
}
|
||||
}
|
||||
async function copyText(text) { await navigator.clipboard.writeText(text); }
|
||||
document.getElementById("resetTemplate").addEventListener("click", () => {
|
||||
templateInput.value = defaultTemplate;
|
||||
renderFields();
|
||||
renderOutput();
|
||||
});
|
||||
document.getElementById("copyOutput").addEventListener("click", async () => {
|
||||
try { await copyText(output.textContent); alert("已複製契約內容"); }
|
||||
catch { alert("複製失敗,請確認瀏覽器是否允許剪貼簿權限。"); }
|
||||
});
|
||||
document.getElementById("copyHtml").addEventListener("click", async () => {
|
||||
try {
|
||||
const htmlText = output.textContent.replace(/\n/g, "<br>\n");
|
||||
await copyText(htmlText);
|
||||
alert("已複製 HTML 換行格式");
|
||||
} catch {
|
||||
alert("複製失敗,請確認瀏覽器是否允許剪貼簿權限。");
|
||||
}
|
||||
});
|
||||
templateInput.value = defaultTemplate;
|
||||
renderFields();
|
||||
renderOutput();
|
||||
updateTaipeiTime();
|
||||
setInterval(updateTaipeiTime, 1000);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
386
html_backup_versions_20260514/v3_contract_template_tool.html
Normal file
386
html_backup_versions_20260514/v3_contract_template_tool.html
Normal file
@@ -0,0 +1,386 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-Hant">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>租屋契約 PDF 工具</title>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.10.1/html2pdf.bundle.min.js"></script>
|
||||
<style>
|
||||
:root {
|
||||
--bg: #eee4d6;
|
||||
--paper: #ffffff;
|
||||
--ink: #222222;
|
||||
--muted: #6c6258;
|
||||
--line: #d4c7b8;
|
||||
--accent: #8a4a27;
|
||||
--accent-2: #6f3517;
|
||||
--panel: rgba(255, 250, 244, 0.9);
|
||||
--shadow: 0 18px 45px rgba(67, 43, 24, 0.12);
|
||||
}
|
||||
* { box-sizing: border-box; }
|
||||
body {
|
||||
margin: 0;
|
||||
color: var(--ink);
|
||||
font-family: "PMingLiU", "MingLiU", "Noto Serif TC", serif;
|
||||
background:
|
||||
radial-gradient(circle at top left, rgba(138, 74, 39, 0.1), transparent 26%),
|
||||
linear-gradient(135deg, #f7f1e8, var(--bg));
|
||||
}
|
||||
.page {
|
||||
width: min(1380px, calc(100% - 32px));
|
||||
margin: 24px auto;
|
||||
padding: 24px;
|
||||
border: 1px solid rgba(212, 199, 184, 0.9);
|
||||
border-radius: 24px;
|
||||
background: rgba(255, 247, 239, 0.78);
|
||||
backdrop-filter: blur(10px);
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
.hero {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: end;
|
||||
gap: 16px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
h1 {
|
||||
margin: 0;
|
||||
font-family: "Microsoft JhengHei", "Noto Sans TC", sans-serif;
|
||||
font-size: clamp(28px, 4vw, 40px);
|
||||
line-height: 1.05;
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
.subtitle {
|
||||
margin: 8px 0 0;
|
||||
color: var(--muted);
|
||||
font-family: "Microsoft JhengHei", "Noto Sans TC", sans-serif;
|
||||
font-size: 15px;
|
||||
}
|
||||
.meta {
|
||||
color: var(--muted);
|
||||
font-family: "Microsoft JhengHei", "Noto Sans TC", sans-serif;
|
||||
font-size: 13px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.layout {
|
||||
display: grid;
|
||||
grid-template-columns: 330px 1fr;
|
||||
gap: 22px;
|
||||
align-items: start;
|
||||
}
|
||||
.controls {
|
||||
position: sticky;
|
||||
top: 20px;
|
||||
padding: 18px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 20px;
|
||||
background: var(--panel);
|
||||
box-shadow: var(--shadow);
|
||||
font-family: "Microsoft JhengHei", "Noto Sans TC", sans-serif;
|
||||
}
|
||||
.controls h2 {
|
||||
margin: 0 0 10px;
|
||||
font-size: 18px;
|
||||
}
|
||||
.controls p {
|
||||
margin: 0 0 16px;
|
||||
color: var(--muted);
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
.field { margin-bottom: 14px; }
|
||||
.field label {
|
||||
display: block;
|
||||
margin-bottom: 6px;
|
||||
font-size: 14px;
|
||||
color: var(--muted);
|
||||
}
|
||||
.field input {
|
||||
width: 100%;
|
||||
padding: 12px 14px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 14px;
|
||||
background: #fffdfa;
|
||||
font: inherit;
|
||||
font-size: 16px;
|
||||
color: var(--ink);
|
||||
}
|
||||
.toolbar {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
margin-top: 18px;
|
||||
}
|
||||
button {
|
||||
border: 0;
|
||||
border-radius: 999px;
|
||||
padding: 12px 16px;
|
||||
font: inherit;
|
||||
cursor: pointer;
|
||||
transition: transform 0.18s ease, opacity 0.18s ease;
|
||||
}
|
||||
button:hover { transform: translateY(-1px); }
|
||||
.primary {
|
||||
color: #fffaf5;
|
||||
background: linear-gradient(135deg, var(--accent), var(--accent-2));
|
||||
}
|
||||
.secondary {
|
||||
color: var(--ink);
|
||||
background: #eadcc9;
|
||||
}
|
||||
.preview-wrap {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.paper {
|
||||
width: 210mm;
|
||||
min-height: 297mm;
|
||||
padding: 22mm 18mm 20mm;
|
||||
border: 1px solid #d7d1c8;
|
||||
background: var(--paper);
|
||||
box-shadow: 0 24px 60px rgba(38, 25, 14, 0.12);
|
||||
color: #111111;
|
||||
line-height: 1.72;
|
||||
font-size: 18px;
|
||||
}
|
||||
.contract-title {
|
||||
margin: 0 0 14px;
|
||||
text-align: center;
|
||||
font-size: 24px;
|
||||
letter-spacing: 0.2em;
|
||||
font-weight: 700;
|
||||
}
|
||||
.contract-line {
|
||||
white-space: pre-wrap;
|
||||
min-height: 1.75em;
|
||||
}
|
||||
.indent {
|
||||
padding-left: 2em;
|
||||
text-indent: -2em;
|
||||
}
|
||||
.signature-block { margin-top: 18px; }
|
||||
.signature-row { white-space: pre-wrap; }
|
||||
.fill {
|
||||
display: inline-block;
|
||||
min-width: 3em;
|
||||
padding: 0 0.15em;
|
||||
}
|
||||
.hint {
|
||||
margin-top: 14px;
|
||||
color: var(--muted);
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
.status {
|
||||
min-height: 22px;
|
||||
margin-top: 10px;
|
||||
color: var(--accent-2);
|
||||
font-size: 13px;
|
||||
}
|
||||
@media (max-width: 1100px) {
|
||||
.layout { grid-template-columns: 1fr; }
|
||||
.controls { position: static; }
|
||||
.preview-wrap { overflow: auto; justify-content: start; }
|
||||
}
|
||||
@media print {
|
||||
body { background: #ffffff; }
|
||||
.page {
|
||||
width: auto;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
background: #ffffff;
|
||||
box-shadow: none;
|
||||
}
|
||||
.hero, .controls { display: none !important; }
|
||||
.layout { display: block; }
|
||||
.preview-wrap { display: block; }
|
||||
.paper {
|
||||
width: 210mm;
|
||||
min-height: auto;
|
||||
margin: 0;
|
||||
padding: 18mm 16mm;
|
||||
border: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="page">
|
||||
<div class="hero">
|
||||
<div>
|
||||
<h1>租屋契約 PDF 工具</h1>
|
||||
<p class="subtitle">只改 `每月租金`、`繳款日期`、`保證金`,右邊維持接近原始 `.doc` 的契約排版,並可匯出或分享 PDF。</p>
|
||||
</div>
|
||||
<div class="meta" id="timeLabel">台北時間:載入中</div>
|
||||
</div>
|
||||
<div class="layout">
|
||||
<aside class="controls">
|
||||
<h2>填寫欄位</h2>
|
||||
<p>這版固定只改 3 個地方,其他條文、地址、設備、租期都照原本文件排版顯示。</p>
|
||||
<div class="field">
|
||||
<label for="rentInput">每月租金</label>
|
||||
<input id="rentInput" type="text" placeholder="例如:6500">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="payDayInput">繳款日期</label>
|
||||
<input id="payDayInput" type="text" placeholder="例如:5">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="depositInput">保證金</label>
|
||||
<input id="depositInput" type="text" placeholder="例如:12000">
|
||||
</div>
|
||||
<div class="toolbar">
|
||||
<button class="primary" id="exportPdfBtn">匯出 PDF</button>
|
||||
<button class="secondary" id="sharePdfBtn">分享 PDF</button>
|
||||
<button class="secondary" id="printBtn">列印 / 另存 PDF</button>
|
||||
<button class="secondary" id="copyTextBtn">複製契約文字</button>
|
||||
</div>
|
||||
<div class="hint">如果瀏覽器不支援直接分享檔案,還是可以先按「匯出 PDF」存檔,再用 Line、Email 或其他方式傳出去。</div>
|
||||
<div class="status" id="status"></div>
|
||||
</aside>
|
||||
<section class="preview-wrap">
|
||||
<article class="paper" id="contractPaper">
|
||||
<h2 class="contract-title">房屋租賃契約</h2>
|
||||
<div class="contract-line"> 立契約書人 出租人 廖雅惠 (以下簡稱為甲方)</div>
|
||||
<div class="contract-line">承租人 (以下簡稱為乙方)</div>
|
||||
<div class="contract-line">因房屋租賃事件,訂立本契約,雙方同意之條件如左:</div>
|
||||
<div class="contract-line">房屋所在地及使用範圍:台中市西屯區西平里文華路 217-5 號 2 樓 A 室</div>
|
||||
<div class="contract-line">第二條 租賃期限:自民國 114 年 6 月 18 日至 115 年 6 月 17 日止計 1 年。</div>
|
||||
<div class="contract-line">第三條 租金:1. 每月租金新台幣 <span class="fill" id="rentValue"></span> 元,每月 <span class="fill" id="payDayValue"></span> 日以前繳納。</div>
|
||||
<div class="contract-line"> 2. 保證金新台幣 <span class="fill" id="depositValue"></span> 元,於租賃期滿交還</div>
|
||||
<div class="contract-line"> 3. 包 (管理費 網路 安博盒子 )</div>
|
||||
<div class="contract-line"> 4. 附( 電視 冷氣 冰箱 洗衣機 雙人床 書桌 衣櫃 椅子 )</div>
|
||||
<div class="contract-line">第四條 使用租賃物之限制:</div>
|
||||
<div class="contract-line indent">1. 本房屋係供住家之用</div>
|
||||
<div class="contract-line indent">2. 未經甲方同意,乙方不得將房屋全部或一部轉租、出借、頂讓,或以其他變相方法由他人使用房屋。</div>
|
||||
<div class="contract-line indent">3. 乙方於租賃期滿應即將房屋遷讓交還,不得向甲方請求遷移費或任何費用。</div>
|
||||
<div class="contract-line indent">4. 房屋不得供非法使用,或存放危險物品影響公共安全。</div>
|
||||
<div class="contract-line indent">5. 房屋有改裝設施之必要,乙方取得甲方之同意後得自行裝設,但不得損害原有建築,乙方於交還房屋時應負責回復原狀不可以在牆上張貼任何物品如海報公佈欄</div>
|
||||
<div class="contract-line">第五條 危險負擔:乙方應以善良管理人之注意使用房屋,除因天災地變等不可抗拒之情形外,因乙方之過失致房屋毀損,應負損害賠償之責。房屋因自然之損壞有修繕必要時,由甲方負責修理。</div>
|
||||
<div class="contract-line">第六條 違約處罰:</div>
|
||||
<div class="contract-line indent">1. 乙方違反約定方法使用房屋,或拖欠租金,經甲方催告限期繳納仍不支付時,甲方得終止租約。</div>
|
||||
<div class="contract-line indent">2. 乙方於終止租約或租賃期滿不交還房屋,自終止租約或租賃期滿之歷日起,乙方應支付按房租壹倍計算之違約金。</div>
|
||||
<div class="contract-line">第七條 其他特約事項:</div>
|
||||
<div class="contract-line indent">1. 乙方遷出時,如遺留傢俱雜物不搬者,視為放棄,應由甲方處理及留存最後一期水電單以便結水電及退押金。</div>
|
||||
<div class="contract-line indent">2. 本契約租賃期限未滿,住滿半年需扣一個月押金但需提前一個月告知及配合看屋。及一個月房租沒付房東可請房客遷出。</div>
|
||||
<div class="contract-line indent">3. 退租時必須將房屋打掃乾淨,否收 800 元清潔費,不得養寵物 房間禁菸被發現強制退租及扣 2 個月押金。</div>
|
||||
<div class="contract-line indent">4. 合約到期前一個月如不續租,須告知房東,並配合給其他房客看屋</div>
|
||||
<div class="contract-line indent">5. 牆壁上不可張貼紙張或釘任何物品例如公佈欄</div>
|
||||
<div class="contract-line indent">6. 如惡意輕生必須賠償甲方當初購屋款及裝潢費用新台幣 150 萬元整.</div>
|
||||
<div class="contract-line indent">7. 電費 1 度 5 元,每月與房租計算</div>
|
||||
<div class="contract-line">第八條 應受強制執行之事項:承租人給付租金或期限屆滿交還租賃物出租人返還保證金,如不履行應逕送強制執行。</div>
|
||||
<div class="signature-block">
|
||||
<div class="signature-row"> 出租人: 廖雅惠 簽章:</div>
|
||||
<div class="signature-row">地 址:台中市西屯區西平里文華路 217-5 號 2 樓 A 室</div>
|
||||
<div class="signature-row">電 話:0918298185</div>
|
||||
<div class="signature-row">承租人: 簽章:</div>
|
||||
<div class="signature-row">身份證號: 緊急聯絡人:</div>
|
||||
<div class="signature-row">地 址:</div>
|
||||
<div class="signature-row">電 話:</div>
|
||||
<div class="signature-row">匯款帳號:</div>
|
||||
<div class="signature-row">中 華 民 國 年 月 日</div>
|
||||
</div>
|
||||
</article>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
const timeLabel = document.getElementById("timeLabel");
|
||||
const status = document.getElementById("status");
|
||||
const rentInput = document.getElementById("rentInput");
|
||||
const payDayInput = document.getElementById("payDayInput");
|
||||
const depositInput = document.getElementById("depositInput");
|
||||
const rentValue = document.getElementById("rentValue");
|
||||
const payDayValue = document.getElementById("payDayValue");
|
||||
const depositValue = document.getElementById("depositValue");
|
||||
const contractPaper = document.getElementById("contractPaper");
|
||||
function updateTaipeiTime() {
|
||||
const formatter = new Intl.DateTimeFormat("zh-TW", {
|
||||
timeZone: "Asia/Taipei", year: "numeric", month: "2-digit", day: "2-digit",
|
||||
hour: "2-digit", minute: "2-digit", second: "2-digit", hour12: false
|
||||
});
|
||||
timeLabel.textContent = `台北時間:${formatter.format(new Date())}`;
|
||||
}
|
||||
function setStatus(message) { status.textContent = message; }
|
||||
function syncValues() {
|
||||
rentValue.textContent = rentInput.value || " ";
|
||||
payDayValue.textContent = payDayInput.value || " ";
|
||||
depositValue.textContent = depositInput.value || " ";
|
||||
}
|
||||
function buildFileName() {
|
||||
const rent = (rentInput.value || "未填租金").replace(/[\\/:*?"<>|]/g, "_");
|
||||
const payDay = (payDayInput.value || "未填日期").replace(/[\\/:*?"<>|]/g, "_");
|
||||
return `租屋契約_逢甲A_租金${rent}_繳款日${payDay}.pdf`;
|
||||
}
|
||||
async function exportPdfFile() {
|
||||
const options = {
|
||||
margin: 0,
|
||||
filename: buildFileName(),
|
||||
image: { type: "jpeg", quality: 0.98 },
|
||||
html2canvas: { scale: 2, useCORS: true, backgroundColor: "#ffffff" },
|
||||
jsPDF: { unit: "mm", format: "a4", orientation: "portrait" },
|
||||
pagebreak: { mode: ["css", "legacy"] }
|
||||
};
|
||||
return window.html2pdf().set(options).from(contractPaper).save();
|
||||
}
|
||||
async function createPdfBlob() {
|
||||
const worker = window.html2pdf().set({
|
||||
margin: 0,
|
||||
filename: buildFileName(),
|
||||
image: { type: "jpeg", quality: 0.98 },
|
||||
html2canvas: { scale: 2, useCORS: true, backgroundColor: "#ffffff" },
|
||||
jsPDF: { unit: "mm", format: "a4", orientation: "portrait" }
|
||||
}).from(contractPaper).toPdf();
|
||||
const pdf = await worker.get("pdf");
|
||||
return pdf.output("blob");
|
||||
}
|
||||
function buildContractText() {
|
||||
return [
|
||||
"房屋租賃契約",
|
||||
" 立契約書人 出租人 廖雅惠 (以下簡稱為甲方)",
|
||||
"承租人 (以下簡稱為乙方)",
|
||||
"因房屋租賃事件,訂立本契約,雙方同意之條件如左:",
|
||||
"房屋所在地及使用範圍:台中市西屯區西平里文華路 217-5 號 2 樓 A 室",
|
||||
"第二條 租賃期限:自民國 114 年 6 月 18 日至 115 年 6 月 17 日止計 1 年。",
|
||||
`第三條 租金:1. 每月租金新台幣 ${rentInput.value || ""} 元,每月 ${payDayInput.value || ""} 日以前繳納。`,
|
||||
` 2. 保證金新台幣 ${depositInput.value || ""} 元,於租賃期滿交還`,
|
||||
" 3. 包 (管理費 網路 安博盒子 )",
|
||||
" 4. 附( 電視 冷氣 冰箱 洗衣機 雙人床 書桌 衣櫃 椅子 )"
|
||||
].join("\n");
|
||||
}
|
||||
rentInput.addEventListener("input", syncValues);
|
||||
payDayInput.addEventListener("input", syncValues);
|
||||
depositInput.addEventListener("input", syncValues);
|
||||
document.getElementById("copyTextBtn").addEventListener("click", async () => {
|
||||
try { await navigator.clipboard.writeText(buildContractText()); setStatus("已複製契約文字。"); }
|
||||
catch { setStatus("複製失敗,請檢查瀏覽器剪貼簿權限。"); }
|
||||
});
|
||||
document.getElementById("printBtn").addEventListener("click", () => {
|
||||
setStatus("已開啟列印視窗,可選擇另存為 PDF。");
|
||||
window.print();
|
||||
});
|
||||
document.getElementById("exportPdfBtn").addEventListener("click", async () => {
|
||||
try { setStatus("正在匯出 PDF..."); await exportPdfFile(); setStatus(`PDF 已匯出:${buildFileName()}`); }
|
||||
catch { setStatus("匯出失敗,改用列印另存 PDF 也可以。"); }
|
||||
});
|
||||
document.getElementById("sharePdfBtn").addEventListener("click", async () => {
|
||||
try {
|
||||
if (!navigator.share || !navigator.canShare) throw new Error("目前瀏覽器不支援檔案分享");
|
||||
setStatus("正在產生分享用 PDF...");
|
||||
const blob = await createPdfBlob();
|
||||
const file = new File([blob], buildFileName(), { type: "application/pdf" });
|
||||
if (!navigator.canShare({ files: [file] })) throw new Error("這個裝置不支援分享 PDF 檔");
|
||||
await navigator.share({ title: "租屋契約 PDF", text: "這是已帶入租金資料的租屋契約。", files: [file] });
|
||||
setStatus("PDF 已開啟分享視窗。");
|
||||
} catch {
|
||||
setStatus("分享失敗或瀏覽器不支援,請先匯出 PDF 後再傳送。");
|
||||
}
|
||||
});
|
||||
updateTaipeiTime();
|
||||
syncValues();
|
||||
setInterval(updateTaipeiTime, 1000);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user