File: /var/www/test/Installationlist/oldphp/formold.php
<?php
// 使用 db.php 連接資料庫
$user_id = $_GET['user_id'];
require_once '../db.php';
try {
$stmt = $conn->prepare("SELECT name, user, member, speed, season, halfyear, year, twoyear, discount, email, homenumber, phone, memberaddress, useraddress, basenumber, pppoeid, pppoepw, standard, fistcount, remark FROM filemaker WHERE user = ?");
$stmt->bind_param('s', $user_id);
$stmt->execute();
$result = $stmt->get_result();
if ($result->num_rows > 0) {
$user = $result->fetch_assoc();
$name = $user['name'];
$member = $user['member'];
$speed = $user['speed'];
$season = $user['season'];
$halfyear = $user['halfyear'];
$year = $user['year'];
$twoyear = $user['twoyear'];
$discount = $user['discount'];
$email= $user['email'];
$homenumber =$user['homenumber'];
$phone = $user['phone'];
$memberaddress = $user['memberaddress'];
$useraddress = $user['useraddress'];
$basenumber = $user['basenumber'];
$pppoeid = $user['pppoeid'];
$pppoepw = $user['pppoepw'];
$standard = $user['standard'];
$fistcount = $user['fistcount'];
$remark = $user['remark'];
}
} catch (Exception $e) {
$error = "資料庫錯誤:" . $e->getMessage();
}
$standard_on =($standard !='');
$isSubscription = (strpos($speed, '定期') !== false) ? 1: 0;
//讓js可抓取變數
$plan_options = [
"season" => !empty($season) ? ["price" => $season, "barcode" => $season] : null,
"halfyear" => !empty($halfyear) ? ["price" => $halfyear, "barcode" => $halfyear] : null,
"year" => !empty($year) ? ["price" => $year, "barcode" => $year] : null,
"twoyear" => !empty($twoyear) ? ["price" => $twoyear, "barcode" => $twoyear] : null
];
$todayObj = new DateTime(); // 今天
?>
<!DOCTYPE html>
<html lang="zh-Hant">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="format-detection" content="telephone=no"> <!-- 防止手機偵測電話 -->
<title>手機版網際網路接取服務申請書</title>
<style>
body {
font-size: 18px;
margin: 10px;
}
.foldable-header {
font-size: 20px;
font-weight: bold;
background: #e0e0e0;
padding: 12px;
margin: 10px 0;
cursor: pointer;
border-radius: 6px;
}
.foldable-table {
border: 1px solid #ccc;
padding: 10px;
margin-bottom: 15px;
display: block;
}
.foldable-table.collapsed {
display: none;
}
.zero {
width: 100%;
border-collapse: collapse;
}
.one {
text-align: left;
white-space: nowrap;
font-weight: bold;
display: block;
width: 100%;
}
.two {
text-align: left;
padding: 8px 10px;
border-bottom: 2px solid #000;
border-right: 2px solid #000;
border-left: 2px solid #000;
box-sizing: border-box;
vertical-align: top;
display: block;
width: 100%;
}
.three {
text-align:center;
border: 1px solid #000;
padding: 5px;
vertical-align: top;
}
.auto-break {
white-space: pre-wrap; /* 保留空格並自動換行 */
word-break: break-word; /* 強制文字換行,避免溢出 */
text-align: left;
padding: 8px 10px;
border-bottom: 2px solid #000;
border-right: 2px solid #000;
border-left: 2px solid #000;
box-sizing: border-box;
vertical-align: top;
display: block;
width: 100%;
}
input[type="text"],
input[type="tel"],
input[type="date"],
select,
.responsive-input {
font-size: 18px;
padding: 6px 8px;
width: 100%;
box-sizing: border-box;
border: none;
background: transparent;
}
.price-align-right {
text-align: right;
}
input::placeholder {
color: red;
}
.date-display {
color: #1976d2; /* Google藍 可調整, 或用 blue */
font-weight: bold;
font-size: 22px; /* 視覺更明顯,可調整 */
letter-spacing: 1px;
text-align:center;
}
</style>
</head>
<body>
<div id="header-bar" style="position: sticky; top: 0; z-index: 10; display: flex; align-items: center; padding-bottom: 5px; border-bottom: 1px solid black; background: #fff; padding-top: 10px;">
<button id="remark-btn" type="button" style="margin-left: 16px; font-size: 22px;">備註</button>
<div style="flex: 1; text-align: center; font-size: 30px;">
<u>網際網路接取服務申請書</u>
</div>
<button id="submit-btn" type="button" style="margin-left: 16px; font-size: 22px;">送出</button>
</div>
<form id="myForm" action="preview.php" method="post">
<div class="table-section">
<div class="foldable-header" onclick="toggleTable(this)">申請人資訊</div>
<div class="foldable-table collapsed">
<table class="zero">
<tr>
<td class="one">用戶編號</td>
<td class="two" ><input type="text" name="user_id_display" value="<?php echo htmlspecialchars($user_id); ?>" class="responsive-input" style="border: none;" readonly></td>
</tr>
<tr>
<td class="one" >社區名稱</td>
<td class="two" ><input type="text" name="member_display" value="<?php echo htmlspecialchars($member); ?>" class="responsive-input" style="border: none;" readonly></td>
</tr>
<tr>
<td class="one" >申請人姓名</td>
<td class="two" ><input type="text" name="applicant_name" value="<?= htmlspecialchars($name ?? '')?>" class="responsive-input"></td>
</tr>
<tr>
<td class="one">
住宅電話
<span id="homenumber-msg" style="font-size: 14px; margin-left: 8px;"></span>
</td>
<td class="two">
<input type="tel" id="applicant_homenumber" name="applicant_homenumber"
value="<?= htmlspecialchars($homenumber ?? '')?>"
class="responsive-input"
placeholder="請輸入住宅電話"
inputmode="tel"
maxlength="12"
>
</td>
</tr>
<tr>
<td class="one">
<select id="id-type" style="font-size: 16px; width:35%;">
<option value="twid">身分證字號</option>
<option value="taxid">統一編號</option>
<option value="arc">舊式居留證(兩個字母)</option>
</select>
<span id="twid-msg" style="font-size: 14px; margin-left: 8px;"></span>
</td>
<td class="two">
<input type="text" id="applicant_usernumber" name="applicant_usernumber"
class="responsive-input"
placeholder="請輸入身分證字號或統一編號"
maxlength="10" required
inputmode="latin" pattern="[A-Za-z0-9]*"
autocomplete="off">
</td>
</tr>
<tr>
<td class="one" >行動電話</td>
<td class="two" ><input type="tel" name="applicant_phone" value="<?= htmlspecialchars($phone ?? '')?>" class="responsive-input"></td>
</tr>
<tr>
<td class="one" >裝機地址</td>
<td class="two" >
<div style="display: flex; align-items: center;">
<span style="white-space: nowrap; margin-right: 4px;"><?= htmlspecialchars($memberaddress ?? '') ?></span>
<input type="hidden" name="memberaddress" id="memberaddress" value="<?= htmlspecialchars($memberaddress ?? '') ?>">
<input type="text" name="useraddress" value="<?= htmlspecialchars($useraddress ?? '') ?>" class="responsive-input" style="flex: 1;">
</div>
</td>
</tr>
<tr>
<td class="one">
電子信箱
<span id="email-msg" style="font-size: 14px; margin-left: 8px;"></span>
</td>
<td class="two">
<input type="email" id="applicant_email" name="applicant_email"
placeholder="請輸入電子信箱"
class="responsive-input" inputmode="email" required>
</td>
</tr>
<tr>
<td class="one" >連接據點</td>
<td class="two" ><input type="text" name="basenumber" value="<?= htmlspecialchars($basenumber ?? '')?>" class="responsive-input"></td>
</tr>
<tr>
<td class="one" >申請速率</td>
<td class="two" ><div><span>最高下載速率(</span><input type="text" name="speed" id="speed" style="width:50%; text-align:center;" value="<?= htmlspecialchars($speed ?? ''); ?>" readonly><span>)Mbps</span></div></td>
</tr>
<tr>
<td class="one" >pppoe<br>連線帳號</td>
<td class="two"><input type="text" name="pppoeid" value="<?= htmlspecialchars($pppoeid ?? '') ?>" class="responsive-input" style="border: none;" readonly></td>
</tr>
<tr>
<td class="one" >pppoe<br>連線密碼</td>
<td class="two" ><input type="text" name="pppoepw" value="<?= htmlspecialchars($pppoepw ?? '') ?>" class="responsive-input" style="border: none;" readonly></td>
</tr>
<tr>
<td class="one" >首裝優惠</td>
<td class="auto-break" id="fistcount"></td>
</tr>
</table>
</div>
</div>
<div class="table-section">
<div class="foldable-header" onclick="toggleTable(this)">設備資訊</div>
<div class="foldable-table collapsed">
<table class="zero" >
<tr>
<td class="one">室內資訊箱設備</td>
<td class="two">
<div id="info-box-container"></div>
<button id="add-info-box-btn" type="button" onclick="addinfoBox()" style="font-size: 18px; padding: 4px 8px;">+</button>
</td>
</tr>
<tr>
<td class="one">室內網路設備</td>
<td class="two">
<div id="Router-box-container"></div>
<button id="add-Router-box-btn" type="button" onclick="addRouterBox()" style="font-size: 18px; padding: 4px 8px;">+</button>
</td>
</tr>
<tr>
<td class="one">借用設備料號</td>
<td class="two">
<div id="use-box-container"></div>
<button type="button" onclick="adduseBox()" style="font-size: 18px; padding: 4px 8px;">+</button>
</td>
</tr>
</table>
</div>
</div>
<div class="table-section">
<div class="foldable-header" onclick="toggleTable(this)">收費項目及金額</div>
<div class="foldable-table collapsed">
<table style="width:100%; border-collapse: collapse;" >
<tr>
<td style="width:40%; font-weight: bold;" class="three" >收費項目</td>
<td style="width:35%; font-weight: bold;" class="three" >品項/料號</td>
<td style="font-weight: bold;" class="three" >金額</td>
</tr>
<tbody id="fee-table-body">
<tr>
<td style="font-weight: bold;" class="three" >網路費用</td>
<td class="three" >
<select id="fee-select" name="fee_select" style="width:100%; font-size:16px;" onchange="togglepayInput(this)">
</select>
</td>
<td class="three"><input type="text" name="pay-container" id="pay-container" class="price-cell" style="text-align:right;" readonly></div></td>
</tr>
</tbody>
</table>
<table style="width:100%; border-collapse: collapse;">
<tr>
<td class="three" style="width:65%;" >
<div style="display: flex; justify-content: space-between; width: 100%;" >
<button type="button" onclick="addpricebox()" style="font-size: 14px;">+</button>
應繳費用總計
</div>
</td>
<td colspan="1" class="three" style="text-align:right;"><input type="text" name="total_fee" class="price-align-right" readonly></td>
</tr>
</table>
</div>
</div>
<div class="table-section">
<div class="foldable-header" onclick="toggleTable(this)">裝機啟用日及網路使用期限</div>
<div class="foldable-table collapsed">
<table class="zero" >
<tr>
<td class="one">裝機日</td>
<td class="two" style="text-align:center;">
<span id="install_date_text" class="date-display"></span>
<input type="hidden" name="install_date" id="install_date">
</td>
</tr>
<tr>
<td class="one">起租日</td>
<td class="two" style="text-align:center;">
<span id="rental_start_date_text" class="date-display"></span>
<input type="hidden" name="rental_start_date" id="rental_start_date">
</td>
</tr>
<tr>
<td class="one">到期日</td>
<td class="two" style="text-align:center;">
<span id="rental_end_date_text" class="date-display"></span>
<input type="hidden" name="rental_end_date" id="rental_end_date">
</td>
</tr>
<tr>
<td class="one" >贈送月份</td>
<td class="two">
<div id="given-months-container"></div>
<button type="button" onclick="givenmonthsBox()" style="font-size: 18px; padding: 4px 8px;">+</button>
</td>
</tr>
<tr>
<td class="one">含贈送月份到期日</td>
<td class="two" style="text-align:center;">
<span id="real_end_date_text" class="date-display"></span>
<input type="hidden" name="real_end_date" id="real_end_date">
</td>
</tr>
</table>
</div>
</div>
</form>
<script>
const phpInjectedData = {
user_id_display: <?= json_encode($user_id) ?>,
member_display: <?= json_encode($member) ?>,
applicant_name: <?= json_encode($name ?? '') ?>,
applicant_phone: <?= json_encode($phone ?? '') ?>,
applicant_homenumber: <?= json_encode($homenumber ?? '') ?>,
memberaddress: <?= json_encode($memberaddress ?? '') ?>,
useraddress: <?= json_encode($useraddress ?? '') ?>,
applicant_email: <?= json_encode($email ?? '') ?>,
basenumber: <?= json_encode($basenumber ?? '') ?>,
speed: <?= json_encode($speed ?? '') ?>,
pppoeid: <?= json_encode($pppoeid ?? '') ?>,
pppoepw: <?= json_encode($pppoepw ?? '') ?>,
fistcount: <?= json_encode($fistcount ?? '') ?>,
isSubscription: <?= $isSubscription ?>,
plan_options: <?= json_encode($plan_options) ?>,
remark: <?= json_encode($remark ?? '無備註') ?>
};
// 第一次連入時,強制執行初始化存檔
if (!sessionStorage.getItem("sessionsave_initialized")) {
for (let key in phpInjectedData) {
let val = phpInjectedData[key];
let storageValue = (typeof val === 'object' && val !== null) ? JSON.stringify(val) : val;
sessionStorage.setItem("sessionsave_" + key, storageValue);
}
sessionStorage.setItem("sessionsave_initialized", "true");
}
/**
* =========================================================
* 2. 頁面恢復流水線 (DOMContentLoaded)
* =========================================================
*/
document.addEventListener("DOMContentLoaded", function () {
// A. 恢復 ID 類型 (身分證/統編/居留證)
const idTypeSelect = document.getElementById("id-type");
const savedIdType = sessionStorage.getItem("sessionsave_id_type");
if (idTypeSelect && savedIdType) idTypeSelect.value = savedIdType;
if (idTypeSelect) {
idTypeSelect.addEventListener("change", function () {
sessionStorage.setItem("sessionsave_id_type", this.value);
if (typeof updateInputMode === "function") updateInputMode(this.value);
});
}
// B. 恢復動態 HTML 結構 (長出原本新增的設備、加購、贈送月份)
restoreDynamicStructure();
// C. 初始化網路費率選單內容
initFeeSelectOptions();
// D. 全域填值 (將 Storage 資料填回 input/select)
restoreFormValuesFromStorage();
// E. 重新計算總金額
if (typeof calculateTotal === "function") calculateTotal();
// F. 設定備註與顯示文字
setupDisplayOnlyItems();
});
/**
* =========================================================
* 3. 功能配套函式
* =========================================================
*/
function restoreDynamicStructure() {
const jobs = [
{ key: 'info_indexes', func: addinfoBox },
{ key: 'Router_indexes', func: addRouterBox },
{ key: 'use_indexes', func: adduseBox },
{ key: 'price_indexes', func: addpricebox },
{ key: 'given_indexes', func: givenmonthsBox }
];
jobs.forEach(job => {
const idxs = JSON.parse(sessionStorage.getItem('sessionsave_' + job.key) || '[]');
idxs.forEach(i => job.func(i));
});
}
function initFeeSelectOptions() {
const feeSelect = document.getElementById("fee-select");
if (!feeSelect) return;
const isSub = parseInt(sessionStorage.getItem("sessionsave_isSubscription"));
feeSelect.innerHTML = '<option value="">請選擇費率</option>';
const options = isSub ? ["定期定額月扣"] : ["季繳", "半年繳", "一年繳", "兩年繳"];
options.forEach(opt => {
let o = document.createElement("option");
o.value = opt; o.textContent = opt;
feeSelect.appendChild(o);
});
const saved = sessionStorage.getItem("sessionsave_fee_select");
if (saved) {
feeSelect.value = saved;
if (typeof togglepayInput === "function") togglepayInput(feeSelect);
}
}
function restoreFormValuesFromStorage() {
document.querySelectorAll("input, select, textarea").forEach(field => {
if (!field.name) return;
const savedValue = sessionStorage.getItem("sessionsave_" + field.name);
if (savedValue !== null) {
if (field.type === "checkbox" || field.type === "radio") {
field.checked = (savedValue === "true");
} else {
field.value = savedValue;
}
// 重要:觸發事件讓您原本寫好的格式驗證(如住宅電話加橫槓)跑起來
field.dispatchEvent(new Event('input', { bubbles: true }));
field.dispatchEvent(new Event('change', { bubbles: true }));
}
});
}
function setupDisplayOnlyItems() {
// 備註
const remarkBtn = document.getElementById("remark-btn");
if (remarkBtn) {
remarkBtn.onclick = function() {
const content = sessionStorage.getItem("sessionsave_remark") || "無備註";
document.getElementById('remark-content').textContent = content;
document.getElementById('remark-modal').style.display = 'flex';
};
}
// 首裝優惠
const fc = sessionStorage.getItem("sessionsave_fistcount");
const fistTd = document.getElementById("fistcount");
if (fc && fistTd) fistTd.innerHTML = fc.replace(/\n/g, "<br>");
}
// 全域變動監聽 (隨打隨存)
document.body.addEventListener("input", function(e) {
if (!e.target.name) return;
let val = (e.target.type === "checkbox" || e.target.type === "radio") ? e.target.checked : e.target.value;
sessionStorage.setItem("sessionsave_" + e.target.name, val);
if (e.target.name.includes("fee") || e.target.name.includes("amount")) calculateTotal();
});
// 索引更新輔助 (用於動態結構還原)
function saveIdx(type) {
const idxs = [];
const selector = `[name^="${type}_box["], [name^="use_box["], [name^="price_box["], [name^="given_box["]`;
document.querySelectorAll(selector).forEach(el => {
const match = el.name.match(/\[(\d+)\]/);
if (match) idxs.push(parseInt(match[1]));
});
sessionStorage.setItem(`sessionsave_${type}_indexes`, JSON.stringify([...new Set(idxs)]));
}
function closeRemarkModal() {
document.getElementById('remark-modal').style.display = 'none';
}
//住宅電話驗證
document.addEventListener("DOMContentLoaded", function () {
const input = document.getElementById("applicant_homenumber");
const msg = document.getElementById("homenumber-msg");
input.addEventListener("input", function () {
let raw = input.value.replace(/[^\d]/g, ""); // 移除非數字
let formatted = raw;
if (raw.length > 2) {
const areaCode = raw.slice(0, 2);
const numberPart = raw.slice(2);
formatted = areaCode + '-' + numberPart;
}
input.value = formatted;
// 驗證格式:02-1234567 或 02-12345678
const telPattern = /^0\d{1}-\d{7,8}$/;
if (formatted.length > 0) {
if (telPattern.test(formatted)) {
msg.textContent = "✔ 格式正確";
msg.style.color = "green";
} else {
msg.textContent = "✘ 格式錯誤(例:02-1234567 或 02-12345678)";
msg.style.color = "red";
}
} else {
msg.textContent = "";
}
});
});
//身分證字號驗證
function isValidTWID(id) {
return /^[A-Z][12]\d{8}$/.test(id);
}
//統一編號驗證
function isValidTaxID(id) {
if (!/^\d{8}$/.test(id)) return false;
const weights = [1, 2, 1, 2, 1, 2, 4, 1];
let sum = 0;
for (let i = 0; i < 8; i++) {
const product = parseInt(id[i], 10) * weights[i];
sum += Math.floor(product / 10) + (product % 10);
}
if (sum % 10 === 0) return true;
if (id[6] === '7' && (sum + 1) % 10 === 0) return true;
return false;
}
// 舊式居留證格式驗證(兩個英文字母 + 8數字)
function isValidARC(id) {
return /^[A-Z]{2}\d{8}$/.test(id);
}
////身分證字號&統一編號欄位&舊式居留證即時顯示驗證狀況
document.addEventListener("DOMContentLoaded", function () {
const input = document.getElementById("applicant_usernumber");
const select = document.getElementById("id-type");
const msg = document.getElementById("twid-msg");
function updateInputMode(type) {
if (type === "twid" || type === "arc") {
input.setAttribute("maxlength", "10");
input.setAttribute("inputmode", "latin");
input.setAttribute("pattern", "[A-Za-z0-9]*");
} else if (type === "taxid") {
input.setAttribute("maxlength", "8");
input.setAttribute("inputmode", "numeric");
input.setAttribute("pattern", "\\d*");
}
msg.textContent = "";
input.value = "";
}
select.addEventListener("change", function () {
updateInputMode(select.value);
});
updateInputMode(select.value);
input.addEventListener("input", function () {
const type = select.value;
let value = input.value.toUpperCase().replace(/[^A-Z0-9]/g, "");
if (type === "taxid") {
value = value.replace(/\D/g, "");
}
input.value = value;
// 驗證訊息
if (type === "twid") {
if (isValidTWID(value)) {
msg.textContent = "✔ 身分證格式正確";
msg.style.color = "green";
} else {
msg.textContent = "✘ 格式錯誤";
msg.style.color = "red";
}
} else if (type === "taxid") {
if (isValidTaxID(value)) {
msg.textContent = "✔ 統一編號格式正確";
msg.style.color = "green";
} else {
msg.textContent = "✘ 格式錯誤";
msg.style.color = "red";
}
} else if (type === "arc") {
if (isValidARC(value)) {
msg.textContent = "✔ 居留證格式正確";
msg.style.color = "green";
} else {
msg.textContent = "✘ 格式錯誤(需兩個英文字母 + 8數字)";
msg.style.color = "red";
}
}
});
});
//電子信箱驗證
document.addEventListener("DOMContentLoaded", function () {
const emailInput = document.getElementById("applicant_email");
const emailMsg = document.getElementById("email-msg");
emailInput.addEventListener("input", function () {
const val = emailInput.value.trim();
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (val.length === 0) {
emailMsg.textContent = "";
return;
}
if (emailPattern.test(val)) {
emailMsg.textContent = "✔ 格式正確";
emailMsg.style.color = "green";
} else {
emailMsg.textContent = "✘ 格式錯誤(例:example@mail.com)";
emailMsg.style.color = "red";
}
});
});
document.body.addEventListener("input", function(e) {
const el = e.target;
// 設備押金、金額欄、設備料號只允許數字
if (
el.name &&
(
el.name.startsWith("other_fee_number") ||
el.name.startsWith("other_fee_amount") ||
el.name.startsWith("use_dp") ||
el.name.startsWith("use_sn")
)
) {
el.value = el.value.replace(/[^\d]/g, '');
}
});
//開闔大項目
function toggleTable(header) {
const content = header.nextElementSibling;
content.classList.toggle('collapsed');
}
let infoBoxIndex = 0;
// 新增欄位
function addinfoBox(index = null) {
const container = document.getElementById('info-box-container');
const newGroup = document.createElement('div');
newGroup.className = 'info-box-group';
newGroup.style.marginBottom = '4px';
const currentIndex = (index !== null) ? index : infoBoxIndex++;
const selects = container.querySelectorAll('select[name^="info_box["]');
let disableWu = selects.length > 0 && selects[0].value !== "無";
newGroup.innerHTML = `
<button type="button" onclick="removeinfoBox(this)" style="font-size: 18px; padding: 4px 4px;">-</button>
<select name="info_box[${currentIndex}]" style="font-size:18px; width:60%; text-align:left; border: 2px solid #000;" onchange="updateinfoQtyInput(this, ${currentIndex})">
<option value="">選擇設備</option>
${!disableWu ? '<option value="無">無</option>' : ''}
<option value="100M有線分享器">100M有線分享器</option>
<option value="1000M有線分享器">1000M有線分享器</option>
<option value="100M無線分享器">100M無線分享器</option>
<option value="1000M無線分享器">1000M無線分享器</option>
<option value="MESH">MESH</option>
<option value="光轉B">光轉B</option>
<option value="光貓">光貓</option>
<option value="100M集線器">100M集線器</option>
<option value="1000M集線器">1000M集線器</option>
<option value="UY">UY</option>
<option value="Panel">Panel</option>
</select>
<div class="info-container" data-index="${currentIndex}" style="display:inline-block;"></div>
`;
container.appendChild(newGroup);
saveInfoBoxIndexes();
}
// 更新數量欄位
function updateinfoQtyInput(selectElem, index) {
const qtyContainer = selectElem.parentElement.querySelector('.info-container');
const addBtn = document.getElementById('add-info-box-btn');
const container = document.getElementById('info-box-container');
const value = selectElem.value;
sessionStorage.setItem(`sessionsave_info_box[${index}]`, value);
if (value === '無') {
const groups = container.querySelectorAll('.info-box-group');
groups.forEach(group => {
if (group.querySelector('select') !== selectElem) {
group.remove();
}
});
qtyContainer.innerHTML = ``;
addBtn.style.display = 'none';
return;
}
const selects = container.querySelectorAll('select[name^="info_box["]');
const hasWu = Array.from(selects).some(select => select.value === '無');
addBtn.style.display = hasWu ? 'none' : 'inline-block';
const savedQty = sessionStorage.getItem(`sessionsave_info_qty[${index}]`);
if (value === 'UY' || value === '') {
qtyContainer.innerHTML = ``;
sessionStorage.removeItem(`sessionsave_info_qty[${index}]`);
} else {
qtyContainer.innerHTML = `
<select name="info_qty[${index}]" style="font-size:18px; border: 2px solid #000;" onchange="sessionStorage.setItem('sessionsave_info_qty[${index}]', this.value)">
<option value="1"${savedQty === "1" ? " selected" : ""}>1</option>
<option value="2"${savedQty === "2" ? " selected" : ""}>2</option>
<option value="3"${savedQty === "3" ? " selected" : ""}>3</option>
<option value="4"${savedQty === "4" ? " selected" : ""}>4</option>
<option value="5"${savedQty === "5" ? " selected" : ""}>5</option>
</select>
`;
}
}
// 刪除欄位
function removeinfoBox(button) {
const group = button.closest('.info-box-group');
const select = group.querySelector('select');
const indexMatch = select.name.match(/info_box\[(\d+)\]/);
if (indexMatch) {
const idx = indexMatch[1];
sessionStorage.removeItem(`sessionsave_info_box[${idx}]`);
sessionStorage.removeItem(`sessionsave_info_qty[${idx}]`);
}
group.remove();
saveInfoBoxIndexes();
const selects = document.querySelectorAll('select[name^="info_box["]');
const hasWu = Array.from(selects).some(select => select.value === '無');
const addBtn = document.getElementById('add-info-box-btn');
if (!hasWu) {
addBtn.style.display = 'inline-block';
}
}
// 儲存目前所有 index
function saveInfoBoxIndexes() {
const indexes = [];
document.querySelectorAll('select[name^="info_box["]').forEach(select => {
const match = select.name.match(/info_box\[(\d+)\]/);
if (match) indexes.push(parseInt(match[1]));
});
sessionStorage.setItem('sessionsave_info_indexes', JSON.stringify(indexes));
}
let routerBoxIndex = 0;
function addRouterBox(index = null) {
const container = document.getElementById('Router-box-container');
const newGroup = document.createElement('div');
newGroup.className = 'Router-box-group';
newGroup.style.marginBottom = '4px';
const currentIndex = index !== null ? index : routerBoxIndex++;
const existingSelects = container.querySelectorAll('select[name^="Router_box["]');
let hasOnly = Array.from(existingSelects).some(sel => sel.value === '單機');
newGroup.innerHTML = `
<button type="button" onclick="removeRouterBox(this)" style="font-size: 18px; padding: 4px 4px;">-</button>
<select name="Router_box[${currentIndex}]" style="font-size:18px; width:60%; text-align:left; border: 2px solid #000;" onchange="updateRouterQtyInput(this, ${currentIndex})">
<option value="">選擇設備</option>
${!hasOnly && existingSelects.length === 0 ? '<option value="單機">單機</option>' : ''}
<option value="100M有線分享器">100M有線分享器</option>
<option value="1000M有線分享器">1000M有線分享器</option>
<option value="100M無線分享器">100M無線分享器</option>
<option value="1000M無線分享器">1000M無線分享器</option>
<option value="MESH">MESH</option>
<option value="電視盒">電視盒</option>
<option value="100M集線器">100M集線器</option>
<option value="1000M集線器">1000M集線器</option>
</select>
<div class="qty-container" data-index="${currentIndex}" style="display:inline-block;"></div>
`;
container.appendChild(newGroup);
saveRouterBoxIndexes();
}
function updateRouterQtyInput(selectElem, index) {
const qtyContainer = selectElem.parentElement.querySelector('.qty-container');
const container = document.getElementById('Router-box-container');
const addBtn = document.getElementById('add-Router-box-btn');
const value = selectElem.value;
sessionStorage.setItem(`sessionsave_Router_box[${index}]`, value);
if (value === '單機') {
const allGroups = container.querySelectorAll('.Router-box-group');
allGroups.forEach(group => {
if (group.querySelector('select') !== selectElem) {
group.remove();
}
});
addBtn.style.display = 'none';
qtyContainer.innerHTML = '';
return;
} else {
const hasOnly = Array.from(container.querySelectorAll('select[name^="Router_box["]')).some(sel => sel.value === '單機');
addBtn.style.display = hasOnly ? 'none' : 'inline-block';
}
if (value === '電視盒') {
const savedTvBox = sessionStorage.getItem(`sessionsave_tv_box[${index}]`) || 'cm';
const savedTvOther = sessionStorage.getItem(`sessionsave_tv_other[${index}]`) || '';
qtyContainer.innerHTML = `
<select name="tv_box[${index}]" onchange="toggleTvOtherInput(this, ${index})" style="width:80px; border: 2px solid #000;">
<option value="cm"${savedTvBox === 'cm' ? ' selected' : ''}>公司</option>
<option value="or"${savedTvBox === 'or' ? ' selected' : ''}>其他</option>
</select>
<input type="text" name="tv_other[${index}]" value="${savedTvOther}" style="${savedTvBox === 'or' ? '' : 'display:none;'}width:180px;height:30px; border: 2px solid #000;" placeholder="請輸入廠牌" oninput="sessionStorage.setItem('sessionsave_tv_other[${index}]', this.value)">
`;
} else if (value === "") {
qtyContainer.innerHTML = ``;
sessionStorage.removeItem(`sessionsave_Router_qty[${index}]`);
} else {
const savedQty = sessionStorage.getItem(`sessionsave_Router_qty[${index}]`) || "1";
qtyContainer.innerHTML = `
<select name="Router_qty[${index}]" style="font-size:18px; border: 2px solid #000;" onchange="sessionStorage.setItem('sessionsave_Router_qty[${index}]', this.value)">
<option value="1"${savedQty === "1" ? " selected" : ""}>1</option>
<option value="2"${savedQty === "2" ? " selected" : ""}>2</option>
<option value="3"${savedQty === "3" ? " selected" : ""}>3</option>
<option value="4"${savedQty === "4" ? " selected" : ""}>4</option>
<option value="5"${savedQty === "5" ? " selected" : ""}>5</option>
</select>
`;
}
}
function toggleTvOtherInput(selectElem, index) {
const input = selectElem.parentElement.querySelector(`input[name="tv_other[${index}]"]`);
input.style.display = selectElem.value === 'or' ? 'inline-block' : 'none';
sessionStorage.setItem(`sessionsave_tv_box[${index}]`, selectElem.value);
}
function removeRouterBox(button) {
const group = button.closest('.Router-box-group');
const select = group.querySelector('select');
const match = select.name.match(/Router_box\[(\d+)\]/);
if (match) {
const index = match[1];
sessionStorage.removeItem(`sessionsave_Router_box[${index}]`);
sessionStorage.removeItem(`sessionsave_Router_qty[${index}]`);
sessionStorage.removeItem(`sessionsave_tv_box[${index}]`);
sessionStorage.removeItem(`sessionsave_tv_other[${index}]`);
}
group.remove();
saveRouterBoxIndexes();
const remainingSelects = document.querySelectorAll('select[name^="Router_box["]');
const hasOnly = Array.from(remainingSelects).some(sel => sel.value === '單機');
const addBtn = document.getElementById('add-Router-box-btn');
if (!hasOnly) {
addBtn.style.display = 'inline-block';
}
}
function saveRouterBoxIndexes() {
const indexes = [];
document.querySelectorAll('select[name^="Router_box["]').forEach(select => {
const match = select.name.match(/Router_box\[(\d+)\]/);
if (match) indexes.push(parseInt(match[1]));
});
sessionStorage.setItem('sessionsave_Router_indexes', JSON.stringify(indexes));
}
let useBoxIndex = 0;
function adduseBox(index = null) {
const container = document.getElementById('use-box-container');
const currentIndex = index !== null ? index : useBoxIndex++;
const newGroup = document.createElement('div');
newGroup.className = 'use-box-group';
newGroup.style.marginBottom = '4px';
const existingSelects = container.querySelectorAll('select[name^="use_box["]');
const hasWu = Array.from(existingSelects).some(sel => sel.value === '無');
const savedSelect = sessionStorage.getItem(`sessionsave_use_box[${currentIndex}]`) || '';
const savedSn = sessionStorage.getItem(`sessionsave_use_sn[${currentIndex}]`) || '';
const savedDp = sessionStorage.getItem(`sessionsave_use_dp[${currentIndex}]`) || '';
newGroup.innerHTML = `
<div style="display: flex; align-items: center; gap: 8px;">
<button type="button" onclick="removeuseBox(this)" style="font-size: 18px; padding: 4px 4px;">-</button>
<select name="use_box[${currentIndex}]" onchange="toggleQtyInput(this, ${currentIndex})" style="font-size:18px; width:60%; border: 2px solid #000;">
<option value="">選擇設備</option>
${!hasWu && existingSelects.length === 0 ? '<option value="無">無</option>' : ''}
<option value="100M無線分享器"${savedSelect === '100M無線分享器' ? ' selected' : ''}>100M無線分享器</option>
<option value="1000M無線分享器"${savedSelect === '1000M無線分享器' ? ' selected' : ''}>1000M無線分享器</option>
<option value="光轉"${savedSelect === '光轉' ? ' selected' : ''}>光轉</option>
<option value="光貓"${savedSelect === '光貓' ? ' selected' : ''}>光貓</option>
<option value="電視盒"${savedSelect === '電視盒' ? ' selected' : ''}>電視盒</option>
${savedSelect === '無' ? '<option value="無" selected>無</option>' : ''}
</select>
</div>
<div class="qty-wrapper" data-index="${currentIndex}" style="display:none; margin-top: 4px; border: 2px solid #000;">
料號:<input type="text" name="use_sn[${currentIndex}]" maxlength="20" style="width: 150px;" value="${savedSn}" placeholder="請輸入設備料號" inputmode="numeric" pattern="\d*" oninput="sessionStorage.setItem('sessionsave_use_sn[${currentIndex}]', this.value)"><br>
押金:<input type="text" name="use_dp[${currentIndex}]" maxlength="20" style="width: 150px;" value="${savedDp}" placeholder="請輸入設備押金" inputmode="numeric" pattern="\d*" oninput="sessionStorage.setItem('sessionsave_use_dp[${currentIndex}]', this.value)">
</div>
`;
container.appendChild(newGroup);
toggleQtyInput(newGroup.querySelector('select'), currentIndex);
saveUseBoxIndexes();
}
function toggleQtyInput(selectElem, index) {
const parentGroup = selectElem.closest('.use-box-group');
const wrapper = parentGroup.querySelector('.qty-wrapper');
const container = document.getElementById('use-box-container');
const addBtn = document.querySelector('#use-box-container + button');
const value = selectElem.value;
sessionStorage.setItem(`sessionsave_use_box[${index}]`, value);
if (value === '無') {
const allGroups = container.querySelectorAll('.use-box-group');
allGroups.forEach(group => {
if (group.querySelector('select') !== selectElem) {
group.remove();
}
});
wrapper.style.display = 'none';
addBtn.style.display = 'none';
} else if (value === "") {
wrapper.style.display = 'none';
} else {
wrapper.style.display = 'inline-block';
const selects = container.querySelectorAll('select[name^="use_box["]');
const hasWu = Array.from(selects).some(sel => sel.value === '無');
addBtn.style.display = hasWu ? 'none' : 'inline-block';
}
}
function removeuseBox(button) {
const group = button.closest('.use-box-group');
const select = group.querySelector('select');
const match = select.name.match(/use_box\[(\d+)\]/);
if (match) {
const idx = match[1];
sessionStorage.removeItem(`sessionsave_use_box[${idx}]`);
sessionStorage.removeItem(`sessionsave_use_sn[${idx}]`);
sessionStorage.removeItem(`sessionsave_use_dp[${idx}]`);
}
group.remove();
const selects = document.querySelectorAll('select[name^="use_box["]');
const hasWu = Array.from(selects).some(sel => sel.value === '無');
const addBtn = document.querySelector('#use-box-container + button');
if (!hasWu) {
addBtn.style.display = 'inline-block';
}
saveUseBoxIndexes();
}
function saveUseBoxIndexes() {
const indexes = [];
document.querySelectorAll('select[name^="use_box["]').forEach(select => {
const match = select.name.match(/use_box\[(\d+)\]/);
if (match) indexes.push(parseInt(match[1]));
});
sessionStorage.setItem('sessionsave_use_indexes', JSON.stringify(indexes));
}
const planOptions = JSON.parse(sessionStorage.getItem("sessionsave_plan_options") || 'null') || <?= json_encode($plan_options) ?>;
const isSubscription = parseInt(sessionStorage.getItem("sessionsave_isSubscription") ?? <?= $isSubscription ?>);
document.addEventListener("DOMContentLoaded", function () {
const selectElem = document.getElementById("fee-select");
// 建立選項
selectElem.innerHTML = "";
const defaultOption = document.createElement("option");
defaultOption.value = "";
defaultOption.textContent = "請選擇費率";
selectElem.appendChild(defaultOption);
if (isSubscription) {
const option = document.createElement("option");
option.value = "定期定額月扣";
option.textContent = "定期定額月扣";
selectElem.appendChild(option);
} else {
const options = ["季繳", "半年繳", "一年繳", "兩年繳"];
options.forEach(function (label) {
const option = document.createElement("option");
option.value = label;
option.textContent = label;
selectElem.appendChild(option);
});
}
// ✅ 放這裡才會在 options 都準備好且 planOptions 已定義後執行
const saved = sessionStorage.getItem("sessionsave_fee_select");
if (saved) {
selectElem.value = saved;
togglepayInput(selectElem); // ⭐️ 保證能正確帶入金額
}
// 綁定變更監聽
selectElem.addEventListener('change', function () {
sessionStorage.setItem('sessionsave_fee_select', this.value);
});
});
function togglepayInput(selectElem) {
const payInput = document.getElementById('pay-container');
let selected = selectElem.value;
let key = '';
switch (selected) {
case '季繳': key = 'season'; break;
case '半年繳': key = 'halfyear'; break;
case '一年繳': key = 'year'; break;
case '兩年繳': key = 'twoyear'; break;
case '定期定額月扣':
payInput.value = '信用卡扣款';
sessionStorage.setItem("sessionsave_net_fee_only", '信用卡扣款');
calculateTotal(); // ✅ 自動帶入總金額 0
return;
default:
payInput.value = '';
calculateTotal();
return;
}
if (planOptions[key]) {
payInput.value = `${planOptions[key].price}`;
sessionStorage.setItem("sessionsave_net_fee_only", planOptions[key].price);
} else {
payInput.value = '此選項無對應金額';
sessionStorage.setItem("sessionsave_net_fee_only", '0');
}
calculateTotal();
}
function addpricebox(index = null) {
const tbody = document.getElementById('fee-table-body');
// 現有所有 index
const exists = Array.from(document.querySelectorAll('.price-box-row')).map(row => parseInt(row.getAttribute('data-index')));
if (index === null) {
index = exists.length ? Math.max(...exists) + 1 : 0;
// 避免重複
while (exists.includes(index)) index++;
}
const newRow = document.createElement('tr');
newRow.className = 'price-box-row';
newRow.setAttribute('data-index', index);
newRow.innerHTML = `
<td class="three" style="display: flex; align-items: center; gap: 4px;">
<button type="button" onclick="removepriceBox(this)" style="font-size: 10px;">-</button>
<select name="price_box[${index}]" onchange="toggleNumberInput(this)">
<option value="">選擇項目</option>
<option value="周邊設備">周邊設備</option>
<option value="配線費用">配線費用</option>
<option value="裝機費用">裝機費用</option>
</select>
</td>
<td class="three price-or-number-cell"></td>
<td class="three amount-cell" style="text-align:right;"></td>
`;
tbody.appendChild(newRow);
// 更新 index 陣列
const updated = Array.from(document.querySelectorAll('.price-box-row')).map(row => parseInt(row.getAttribute('data-index')));
sessionStorage.setItem("sessionsave_price_indexes", JSON.stringify(updated));
}
function calculateTotal() {
let total = 0;
const payDiv = document.getElementById('pay-container');
const netFeeText = payDiv.value;
const netFee = (netFeeText === '信用卡扣款') ? 0 : parseFloat(netFeeText);
if (!isNaN(netFee)) total += netFee;
const otherAmounts = document.querySelectorAll('input[name^="other_fee_amount"]');
otherAmounts.forEach(input => {
const value = parseFloat(input.value);
if (!isNaN(value)) total += value;
});
const totalField = document.querySelector('input[name="total_fee"]');
totalField.value = total.toFixed(0);
sessionStorage.setItem("sessionsave_total_fee", total.toFixed(0));
}
function formatDateToChinese(isoStr) {
if (!isoStr) return '';
const d = new Date(isoStr);
if (isNaN(d.getTime())) return '';
const year = d.getFullYear();
const month = (d.getMonth() + 1).toString().padStart(2, '0');
const day = d.getDate().toString().padStart(2, '0');
return `${year}年${month}月${day}日`;
}
// 切換「設備料號」欄位顯示
function toggleNumberInput(selectElement) {
const row = selectElement.closest('tr');
const index = row.getAttribute('data-index');
const numberCell = row.querySelector('.price-or-number-cell');
const amountCell = row.querySelector('.amount-cell');
const selectedValue = selectElement.value;
// 清空
numberCell.innerHTML = '';
amountCell.innerHTML = '';
// 幫助還原時即刻填值的小工具
function restoreInput(name) {
const key = "sessionsave_" + name;
const input = row.querySelector(`[name="${name}"]`);
const value = sessionStorage.getItem(key);
if (input && value !== null) input.value = value;
}
if (selectedValue === '周邊設備') {
numberCell.innerHTML = `<input type="text" name="other_fee_number[${index}]" placeholder="輸入料號" inputmode="numeric" pattern="\d*" style="flex: 1; min-width: 0;">`;
amountCell.innerHTML = `<input type="text" name="other_fee_amount[${index}]" class="price-align-right" placeholder="輸入金額" inputmode="numeric" pattern="\d*" oninput="calculateTotal()">`;
// 立刻還原
restoreInput(`other_fee_number[${index}]`);
restoreInput(`other_fee_amount[${index}]`);
} else if (selectedValue === '配線費用' || selectedValue === '裝機費用') {
amountCell.innerHTML = `<input type="text" name="other_fee_amount[${index}]" class="price-align-right" placeholder="輸入金額" inputmode="numeric" pattern="\d*" oninput="calculateTotal()">`;
// 立刻還原
restoreInput(`other_fee_amount[${index}]`);
}
}
// 刪除欄位時清理 sessionStorage
function removepriceBox(button) {
const row = button.closest('tr');
const index = row.getAttribute('data-index');
sessionStorage.removeItem(`sessionsave_price_box[${index}]`);
sessionStorage.removeItem(`sessionsave_other_fee_number[${index}]`);
sessionStorage.removeItem(`sessionsave_other_fee_amount[${index}]`);
row.remove();
// 更新 price_indexes
const indexes = Array.from(document.querySelectorAll('.price-box-row')).map(row => parseInt(row.getAttribute('data-index')));
sessionStorage.setItem("sessionsave_price_indexes", JSON.stringify(indexes));
calculateTotal();
}
function setDateField(idBase, dateStr) {
document.getElementById(idBase + "_text").textContent = formatDateToChinese(dateStr || "");
document.getElementById(idBase).value = dateStr || "";
sessionStorage.setItem("sessionsave_" + idBase, dateStr || "");
}
const today = "<?= (new DateTime())->format('Y-m-d') ?>";
setDateField('install_date', today);
setDateField('rental_start_date', ''); // 你的計算結果
setDateField('rental_end_date', ''); // 你的計算結果
setDateField('real_end_date', ''); // 你的計算結果
document.addEventListener("DOMContentLoaded", function () {
const installInput = document.querySelector('input[name="install_date"]');
const rentalStartInput = document.querySelector('input[name="rental_start_date"]');
const rentalEndInput = document.querySelector('input[name="rental_end_date"]');
const realEndInput = document.querySelector('input[name="real_end_date"]');
const feeSelect = document.getElementById("fee-select");
const today = "<?= (new DateTime())->format('Y-m-d') ?>";
installInput.value = today;
updateRentalStartDate(today);
updateRentalEndDate();
installInput.addEventListener("change", function () {
updateRentalStartDate(installInput.value);
updateRentalEndDate();
});
feeSelect.addEventListener("change", function () {
updateRentalEndDate();
});
rentalEndInput.addEventListener("change", updateRealEndDate);
function updateRentalStartDate(installDateStr) {
if (!installDateStr) {
setDateField('rental_start_date', '');
return;
}
const date = new Date(installDateStr);
date.setDate(date.getDate() + 1);
setDateField('rental_start_date', date.toISOString().split("T")[0]);
}
function isEndOfMonth(date) {
const next = new Date(date);
next.setDate(date.getDate() + 1);
return next.getDate() === 1;
}
function calculateEndDateByInstallDate(installDateStr, monthsToAdd) {
const start = new Date(installDateStr);
const result = new Date(start);
result.setDate(1);
result.setMonth(result.getMonth() + monthsToAdd);
if (isEndOfMonth(start)) {
result.setMonth(result.getMonth() + 1);
result.setDate(0);
} else {
const targetDay = start.getDate();
const lastDay = new Date(result.getFullYear(), result.getMonth() + 1, 0).getDate();
result.setDate(Math.min(targetDay, lastDay));
}
return result.toISOString().split("T")[0];
}
function updateRentalEndDate() {
const selected = feeSelect.value;
const installDate = installInput.value;
let monthsToAdd = 0;
switch (selected) {
case "季繳": monthsToAdd = 3; break;
case "半年繳": monthsToAdd = 6; break;
case "一年繳": monthsToAdd = 12; break;
case "兩年繳": monthsToAdd = 24; break;
default:
setDateField('rental_end_date', '');
updateRealEndDate();
return;
}
const endDateStr = calculateEndDateByInstallDate(installDate, monthsToAdd);
setDateField('rental_end_date', endDateStr);
updateRealEndDate();
}
window.givenmonthsBox = function(index = null) {
const container = document.getElementById('given-months-container');
// 取得現有 index
const exists = Array.from(container.querySelectorAll('.given-months-group'))
.map(group => parseInt(group.getAttribute('data-index')))
.filter(x => !isNaN(x));
if (index === null) {
index = exists.length ? Math.max(...exists) + 1 : 0;
while (exists.includes(index)) index++;
}
const newGroup = document.createElement('div');
newGroup.className = 'given-months-group';
newGroup.setAttribute('data-index', index);
newGroup.style.marginBottom = '4px';
newGroup.innerHTML = `
<button type="button" onclick="removegivenBox(this)" style="font-size: 18px; padding: 4px 4px;">-</button>
<select name="given_box[${index}]" style="font-size:18px; width:45%; border: 2px solid #000;">
<option value="">請選擇</option>
<option value="首裝優惠">首裝優惠</option>
<option value="他網轉入">他網轉入</option>
<option value="總幹事介紹">總幹事介紹</option>
<option value="業務贈送">業務贈送</option>
<option value="主管贈送">主管贈送</option>
<option value="LINE推廣">LINE推廣</option>
<option value="住戶介紹">住戶介紹</option>
<option value="團購優惠">團購優惠</option>
</select>
<span class="give-qty-wrapper"></span>
`;
container.appendChild(newGroup);
// 還原 select 值
const givenKey = `sessionsave_given_box[${index}]`;
const qtyKey = `sessionsave_give_qty[${index}]`;
const s1 = newGroup.querySelector(`select[name="given_box[${index}]"]`);
const qtyWrapper = newGroup.querySelector('.give-qty-wrapper');
// 寫一個數量 select 產生器
function createQtySelect(selected) {
let select = document.createElement('select');
select.name = `give_qty[${index}]`;
select.style = "font-size:18px; width:15%; border: 2px solid #000; margin-left:8px;";
for (let i = 1; i <= 12; i++) {
let option = document.createElement('option');
option.value = i;
option.text = i;
if ((selected && parseInt(selected,10) === i) || (!selected && i === 1)) {
option.selected = true;
}
select.appendChild(option);
}
// ✅ 加這段:一建立時就寫入預設值(若沒選過)
const sessionKey = "sessionsave_" + select.name;
if (sessionStorage.getItem(sessionKey) === null) {
sessionStorage.setItem(sessionKey, selected || "1");
}
// 綁定事件
select.addEventListener("change", function () {
sessionStorage.setItem(sessionKey, this.value);
updateRealEndDate();
});
return select;
}
// 監聽原因 select
s1.addEventListener("change", function () {
qtyWrapper.innerHTML = '';
// 有選到才顯示數量
if (this.value !== "") {
// 還原
const saved = sessionStorage.getItem(qtyKey);
qtyWrapper.appendChild(createQtySelect(saved));
}
// 介紹人
let extraInput = newGroup.querySelector('.introducer-input');
if (this.value === "住戶介紹") {
if (!extraInput) {
const input = document.createElement("input");
input.type = "text";
input.name = `introducer_name[${index}]`;
input.placeholder = "請輸入介紹人資訊";
input.className = "introducer-input";
input.style = "font-size:18px;width:80%;margin-left:5px;border:2px solid #000;";
qtyWrapper.appendChild(input);
// 還原介紹人
const introKey = `sessionsave_introducer_name[${index}]`;
if(sessionStorage.getItem(introKey)) input.value = sessionStorage.getItem(introKey);
}
}
updateRealEndDate();
});
// 還原原因值並觸發事件
if(sessionStorage.getItem(givenKey)) s1.value = sessionStorage.getItem(givenKey);
s1.dispatchEvent(new Event("change"));
// 更新索引
const updated = Array.from(container.querySelectorAll('.given-months-group')).map(g => parseInt(g.getAttribute('data-index')));
sessionStorage.setItem("sessionsave_given_indexes", JSON.stringify(updated));
}
// 刪除時記得也更新索引
window.removegivenBox = function (button) {
const group = button.closest('.given-months-group');
const index = group.getAttribute('data-index');
sessionStorage.removeItem(`sessionsave_given_box[${index}]`);
sessionStorage.removeItem(`sessionsave_give_qty[${index}]`);
sessionStorage.removeItem(`sessionsave_introducer_name[${index}]`);
group.remove();
const container = document.getElementById('given-months-container');
const indexes = Array.from(container.querySelectorAll('.given-months-group')).map(g => parseInt(g.getAttribute('data-index')));
sessionStorage.setItem("sessionsave_given_indexes", JSON.stringify(indexes));
updateRealEndDate();
};
});
function updateRealEndDate() {
const rentalEndDateInput = document.querySelector('input[name="rental_end_date"]');
if (!rentalEndDateInput.value) {
setDateField('real_end_date', '');
return;
}
const baseDate = new Date(rentalEndDateInput.value);
const baseDay = baseDate.getDate();
const monthSelects = document.querySelectorAll('select[name^="give_qty["]');
let totalGivenMonths = 0;
monthSelects.forEach(select => {
totalGivenMonths += parseInt(select.value, 10);
});
const isEndOfMonth = (date) => {
const test = new Date(date);
test.setDate(test.getDate() + 1);
return test.getDate() === 1;
};
const realEndDate = new Date(baseDate);
realEndDate.setDate(1);
realEndDate.setMonth(realEndDate.getMonth() + totalGivenMonths);
if (isEndOfMonth(baseDate)) {
realEndDate.setMonth(realEndDate.getMonth() + 1);
realEndDate.setDate(0);
} else {
const lastDay = new Date(realEndDate.getFullYear(), realEndDate.getMonth() + 1, 0).getDate();
realEndDate.setDate(Math.min(baseDay, lastDay));
}
setDateField('real_end_date', realEndDate.toISOString().split("T")[0]);
}
document.addEventListener("DOMContentLoaded", function () {
// 還原 info_box[] 欄位數量
const infoIndexes = JSON.parse(sessionStorage.getItem('sessionsave_info_indexes') || '[]');
infoBoxIndex = Math.max(...infoIndexes, -1) + 1;
infoIndexes.forEach(index => {
if (!document.querySelector(`select[name="info_box[${index}]"]`)) {
addinfoBox(index); // 只有 DOM 中沒有該 index 才新增
}
});
// 還原 Router_box[] 動態欄位
const routerIndexes = JSON.parse(sessionStorage.getItem('sessionsave_Router_indexes') || '[]');
routerBoxIndex = Math.max(...routerIndexes, -1) + 1;
routerIndexes.forEach(index => {
addRouterBox(index);
});
// 還原 use_box[] 動態欄位
const useIndexes = JSON.parse(sessionStorage.getItem('sessionsave_use_indexes') || '[]');
useBoxIndex = Math.max(...useIndexes, -1) + 1;
useIndexes.forEach(index => {
adduseBox(index);
});
// 事件代理:動態儲存 input/select/textarea 的值
document.body.addEventListener("input", function (e) {
const el = e.target;
if (!el.name) return;
const key = "sessionsave_" + el.name;
if (el.type === "checkbox" || el.type === "radio") {
sessionStorage.setItem(key, el.checked);
} else {
sessionStorage.setItem(key, el.value);
}
});
//
document.body.addEventListener("change", function (e) {
const el = e.target;
if (!el.name) return;
const key = "sessionsave_" + el.name;
if (el.type === "checkbox" || el.type === "radio") {
sessionStorage.setItem(key, el.checked);
} else {
sessionStorage.setItem(key, el.value);
}
});
// 還原 fee-select 的選擇
const feeSelect = document.getElementById("fee-select");
const savedFeeSelect = sessionStorage.getItem("sessionsave_fee_select");
if (feeSelect && savedFeeSelect) {
feeSelect.value = savedFeeSelect;
feeSelect.dispatchEvent(new Event("change"));
}
// 監控 fee-select 的變化並寫入 sessionStorage
feeSelect.addEventListener('change', function() {
sessionStorage.setItem('sessionsave_fee_select', this.value);
});
// 先產生所有 price_box[]
const priceIndexes = JSON.parse(sessionStorage.getItem('sessionsave_price_indexes') || '[]');
priceIndexes.forEach(index => {
addpricebox(index);
});
// 先將 select 設值並觸發動態欄位產生
document.querySelectorAll('select[name^="price_box["]').forEach(select => {
const name = select.name;
const saved = sessionStorage.getItem('sessionsave_' + name);
if (saved) {
select.value = saved;
toggleNumberInput(select); // <<-- 這個是關鍵
}
});
// 動態還原贈送月份欄位
const givenIndexes = JSON.parse(sessionStorage.getItem('sessionsave_given_indexes') || '[]');
givenIndexes.forEach(index => {
window.givenmonthsBox(index);
});
// 還原各個動態 price_box 欄位的資料
const allFields = document.querySelectorAll("input, select, textarea");
allFields.forEach(field => {
const name = field.name;
if (!name) return;
const key = "sessionsave_" + name;
const value = sessionStorage.getItem(key);
if (value !== null) {
if (field.type === "checkbox" || field.type === "radio") {
field.checked = value === "true";
} else {
field.value = value;
}
field.dispatchEvent(new Event("input"));
field.dispatchEvent(new Event("change"));
}
});
// 還原總金額
const totalValue = sessionStorage.getItem("sessionsave_total_fee");
if (totalValue !== null) {
document.querySelector('input[name="total_fee"]').value = totalValue;
}
// 儲存事件(延伸)
document.body.addEventListener("input", function (e) {
const el = e.target;
if (!el.name) return;
const key = "sessionsave_" + el.name;
sessionStorage.setItem(key, el.type === "checkbox" || el.type === "radio" ? el.checked : el.value);
if (el.name === "total_fee") return; // 避免總計被即時覆蓋
});
document.body.addEventListener("change", function (e) {
const el = e.target;
if (!el.name) return;
const key = "sessionsave_" + el.name;
sessionStorage.setItem(key, el.type === "checkbox" || el.type === "radio" ? el.checked : el.value);
});
// 監控動態欄位並補還原資料
const observer = new MutationObserver(function (mutationsList) {
mutationsList.forEach(mutation => {
mutation.addedNodes.forEach(node => {
if (node.nodeType === 1) {
const newFields = node.querySelectorAll?.("input, select, textarea") || [];
newFields.forEach(field => {
const name = field.name;
if (!name) return;
const key = "sessionsave_" + name;
const value = sessionStorage.getItem(key);
if (value !== null) {
if (field.type === "checkbox" || field.type === "radio") {
field.checked = value === "true";
} else {
field.value = value;
}
field.dispatchEvent(new Event("input"));
field.dispatchEvent(new Event("change"));
}
});
}
});
});
setTimeout(() => calculateTotal(), 200); // 延遲重新計算
});
observer.observe(document.body, { childList: true, subtree: true });
setTimeout(() => {
const feeSelect = document.getElementById("fee-select");
if (feeSelect) {
feeSelect.dispatchEvent(new Event("change")); // 觸發 togglepayInput
}
calculateTotal(); // 確保總金額正確顯示
}, 200);
document.getElementById("submit-btn").addEventListener("click", function () {
let missing = [];
// 1. 身分證字號/統編 必填
const idType = document.getElementById("id-type").value;
const idValue = document.getElementById("applicant_usernumber").value.trim();
if (!idValue) {
missing.push("請輸入身分證字號或統一編號");
} else {
if (idType === "twid" && !/^[A-Z][12]\d{8}$/.test(idValue)) {
missing.push("身分證字號格式錯誤");
}
if (idType === "taxid" && !/^\d{8}$/.test(idValue)) {
missing.push("統一編號格式錯誤");
}
}
// 2. 電子信箱 必填且格式正確
const emailValue = document.getElementById("applicant_email").value.trim();
if (!emailValue) {
missing.push("請輸入電子信箱");
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(emailValue)) {
missing.push("電子信箱格式錯誤");
}
// 3. 設備三區(只要各一個有選)
function hasSelectedValue(selector, fieldName) {
let selects = document.querySelectorAll(selector + ' select');
return Array.from(selects).some(sel => sel.value && sel.value !== "");
}
if (!hasSelectedValue('#info-box-container')) {
missing.push("請選擇至少一個『室內資訊箱設備』");
}
if (!hasSelectedValue('#Router-box-container')) {
missing.push("請選擇至少一個『室內網路設備』");
}
if (!hasSelectedValue('#use-box-container')) {
missing.push("請選擇至少一個『借用設備料號』");
}
// 4. 網路費用 必選
const feeSelect = document.getElementById("fee-select").value;
if (!feeSelect) {
missing.push("請選擇『網路費用』方案");
}
// ======= 統一檢查與顯示 =======
if (missing.length > 0) {
alert(missing.join('\n'));
// 可依需要 focus 第一個未填欄位
// ex: document.getElementById("applicant_usernumber").focus();
return;
}
//sessionStorage.clear();
document.getElementById("myForm").submit();
});
});
// 一、任何 input/select/textarea(有 name)都即時寫入 sessionStorage
document.body.addEventListener("input", function(e) {
const el = e.target;
if (!el.name) return;
sessionStorage.setItem("sessionsave_" + el.name, el.value);
});
document.body.addEventListener("change", function(e) {
const el = e.target;
if (!el.name) return;
sessionStorage.setItem("sessionsave_" + el.name, el.value);
});
// 二、頁面一載入就還原所有欄位(靜態、動態欄位都吃得到)
document.addEventListener("DOMContentLoaded", function () {
document.querySelectorAll("input, select, textarea").forEach(function(field) {
if (!field.name) return;
var value = sessionStorage.getItem("sessionsave_" + field.name);
if (value !== null) field.value = value;
});
});
document.addEventListener("DOMContentLoaded", function () {
const feeSelect = document.getElementById("fee-select");
if (feeSelect) {
const saved = sessionStorage.getItem("sessionsave_fee_select");
if (saved) {
feeSelect.value = saved;
togglepayInput(feeSelect); // 這一行很重要!強制更新金額
}
}
});
document.addEventListener("DOMContentLoaded", function () {
const feeInput = document.querySelector('input[name="total_fee"]');
if (feeInput && feeInput.value) {
sessionStorage.setItem("sessionsave_total_fee", feeInput.value);
}
// ✅ 這裡是 fistcount 寫入時機點
var phpFistcount = <?= json_encode($fistcount ?? '') ?>;
const key = "sessionsave_fistcount";
// 寫入 sessionStorage(僅在沒資料時)
if (!sessionStorage.getItem(key) && phpFistcount) {
sessionStorage.setItem(key, phpFistcount);
}
const storedFist = sessionStorage.getItem(key) || '';
const fistTd = document.getElementById("fistcount");
const hiddenFist = document.getElementById("fistcount_hidden");
if (fistTd) {
const formatted = storedFist
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/ /g, " ")
.replace(/\n/g, "<br>");
fistTd.innerHTML = formatted;
}
if (hiddenFist) hiddenFist.value = storedFist;
});
</script>
<div id="remark-modal" style="display:none; position:fixed; top:0; left:0; width:100vw; height:100vh; background:rgba(0,0,0,0.2); z-index:10000; justify-content:center; align-items:center;">
<div style="background:#fff; min-width:300px; max-width:80vw; padding:24px 20px 20px 20px; border-radius:14px; box-shadow:0 4px 24px rgba(0,0,0,0.15); position:relative;">
<button onclick="closeRemarkModal()" style="position:absolute; top:8px; right:10px; font-size:22px; background:none; border:none; cursor:pointer;">×</button>
<div id="remark-content" style="white-space:pre-line; font-size:18px;"></div>
</div>
</div>
</body>
</html>