File: /var/www/test/Installationlist/preview.php
<?php
// ============================================================
// preview.php ─ 申請書預覽頁
// ============================================================
session_start();
// 接收 form.php POST 資料,存入 Session(方便返回修改)
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$fields = [
'user_id','member','memberaddress','useraddress','speed','basenumber',
'pppoeid','pppoepw','fistcount',
'applicant_name','applicant_usernumber','id_type',
'applicant_phone','applicant_homenumber','applicant_email',
'info_devices','info_qty','router_devices','router_qty','use_devices',
'fee_type','fee_amount','extra_fees','total_fee','deposit_total',
'install_date','rental_start_date','rental_end_date',
'gift_months','real_end_date','enname','enphone'
];
foreach ($fields as $f) {
$_SESSION['preview'][$f] = $_POST[$f] ?? '';
}
$_SESSION['preview']['otp_verified'] = $_SESSION['otp_verified'] ?? false;
}
$d = $_SESSION['preview'] ?? [];
if (empty($d)) {
header('Location: form.php');
exit;
}
// 解碼 JSON 欄位
$infoList = json_decode($d['info_devices'] ?? '[]', true) ?: [];
$routerList = json_decode($d['router_devices'] ?? '[]', true) ?: [];
$useList = json_decode($d['use_devices'] ?? '[]', true) ?: [];
$extraList = json_decode($d['extra_fees'] ?? '[]', true) ?: [];
$giftList = json_decode($d['gift_months'] ?? '[]', true) ?: [];
// 費率中文
$feeLabel = [
'season'=>'季繳','halfyear'=>'半年繳','year'=>'一年繳','twoyear'=>'兩年繳',
'subscription'=>'定期定額月扣'
][$d['fee_type'] ?? ''] ?? $d['fee_type'] ?? '—';
// 日期格式化
function fmtDate($s) {
if (!$s) return '—';
$dt = DateTime::createFromFormat('Y-m-d', $s);
return $dt ? $dt->format('Y年m月d日') : $s;
}
?>
<!DOCTYPE html>
<html lang="zh-Hant">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>裝機申請書預覽</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@tabler/icons-webfont@3.19.0/dist/tabler-icons.min.css">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--green: #1D9E75; --green-lt: #E1F5EE; --green-dk: #0F6E56; --green-deep: #085041;
--amber: #FAEEDA; --amber-txt: #633806;
--red: #E24B4A;
--gray-bg: #F5F5F5; --gray-bd: rgba(0,0,0,.13); --gray-bd2: rgba(0,0,0,.25);
--text: #111; --text-sec: #666; --text-tert: #999;
--radius-md: 8px; --radius-lg: 12px;
}
body { font-family: "Microsoft JhengHei","PingFang TC",sans-serif; font-size:15px; background:var(--gray-bg); color:var(--text); padding-bottom:90px; }
.topbar { position:sticky;top:0;z-index:100;background:#fff;border-bottom:0.5px solid var(--gray-bd);padding:11px 16px;display:flex;align-items:center;gap:10px; }
.topbar-title { flex:1;text-align:center;font-size:16px;font-weight:500; }
.status-pill { font-size:11px;padding:3px 10px;border-radius:20px;background:var(--amber);color:var(--amber-txt); }
.content { padding:12px 16px 16px;display:flex;flex-direction:column;gap:12px; }
.card { background:#fff;border-radius:var(--radius-lg);border:0.5px solid var(--gray-bd);overflow:hidden; }
.card-hdr { display:flex;align-items:center;gap:8px;padding:10px 14px;border-bottom:0.5px solid var(--gray-bd);background:var(--gray-bg); }
.card-hdr i { font-size:16px;color:var(--green); }
.card-hdr-txt { font-size:13px;font-weight:500; }
.row { display:flex;align-items:stretch;border-bottom:0.5px solid var(--gray-bd); }
.row:last-child { border-bottom:none; }
.lbl { width:88px;flex-shrink:0;font-size:12px;color:var(--text-sec);padding:9px 10px 9px 14px;background:var(--gray-bg);display:flex;align-items:center;justify-content:center;text-align:center;line-height:1.4; }
.val { flex:1;padding:9px 14px;font-size:14px;color:var(--text);word-break:break-all; }
.val.mono { font-family:monospace;font-size:13px;color:var(--text-sec); }
.val.green { color:var(--green-dk);font-weight:500; }
.val.big { font-size:16px;font-weight:500;color:var(--green-dk); }
.device-chip { display:inline-flex;align-items:center;gap:3px;font-size:12px;background:var(--green-lt);color:var(--green-deep);padding:3px 10px;border-radius:20px;margin:3px 3px 3px 0; }
.device-chip.gray { background:var(--gray-bg);color:var(--text-sec); }
.fee-row { display:flex;align-items:center;padding:9px 14px;border-bottom:0.5px solid var(--gray-bd); }
.fee-row:last-child { border-bottom:none; }
.fee-name { font-size:13px;color:var(--text-sec);flex:1; }
.fee-amt { font-size:14px;font-weight:500;color:var(--text); }
.total-row { display:flex;align-items:center;justify-content:space-between;padding:12px 14px; }
.total-lbl { font-size:13px;color:var(--text-sec); }
.total-amt { font-size:22px;font-weight:500;color:var(--green); }
.deposit-row { display:flex;align-items:center;justify-content:space-between;padding:8px 14px;border-top:0.5px solid var(--gray-bd);font-size:13px; }
.date-row { display:flex;align-items:center;padding:9px 14px;border-bottom:0.5px solid var(--gray-bd); }
.date-row:last-child { border-bottom:none; }
.date-lbl { font-size:13px;color:var(--text-sec);flex:1; }
.date-val { font-size:14px;font-weight:500;color:var(--text); }
.date-val.accent { color:var(--green-dk); }
.date-val.highlight { font-size:16px;color:var(--green-dk); }
.gift-chip { display:inline-flex;align-items:center;gap:4px;font-size:12px;background:var(--amber);color:var(--amber-txt);padding:4px 10px;border-radius:20px;margin:3px; }
.check-card { background:#fff;border-radius:var(--radius-lg);border:0.5px solid var(--gray-bd);overflow:hidden; }
.check-item { display:flex;align-items:center;gap:10px;padding:10px 14px;border-bottom:0.5px solid var(--gray-bd);cursor:pointer; }
.check-item:last-child { border-bottom:none; }
.chk-box { width:22px;height:22px;border-radius:5px;border:1.5px solid var(--gray-bd2);display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:all .15s; }
.chk-box.on { background:var(--green);border-color:var(--green);color:#fff; }
.chk-txt { font-size:13px;color:var(--text); }
.chk-sub { font-size:11px;color:var(--text-sec);margin-top:1px; }
.warn-bar { background:var(--amber);border-radius:var(--radius-md);padding:10px 14px;display:flex;gap:8px;font-size:12px;color:var(--amber-txt);align-items:flex-start; }
.bottom-bar { position:sticky;bottom:0;background:#fff;border-top:0.5px solid var(--gray-bd);padding:12px 16px;display:flex;align-items:center;gap:10px; }
.btn-back { flex:1;padding:12px;border:0.5px solid var(--gray-bd2);border-radius:var(--radius-md);background:none;font-size:14px;cursor:pointer;color:var(--text-sec);font-family:inherit; }
.btn-next { flex:2;padding:12px;background:var(--green);color:#fff;border:none;border-radius:var(--radius-md);font-size:14px;font-weight:500;cursor:pointer;font-family:inherit;display:flex;align-items:center;justify-content:center;gap:6px;transition:opacity .2s; }
.btn-next:disabled { opacity:.35;cursor:not-allowed; }
</style>
</head>
<body>
<div class="topbar">
<i class="ti ti-file-check" style="font-size:20px;color:var(--green)"></i>
<div class="topbar-title">申請書確認</div>
<span class="status-pill" id="status-pill">待確認</span>
</div>
<div class="content">
<div class="warn-bar">
<i class="ti ti-alert-triangle"></i>
<span>請仔細核對以下所有資料後再送出,送出後將無法修改</span>
</div>
<!-- 申請人 -->
<div class="card">
<div class="card-hdr"><i class="ti ti-user"></i><span class="card-hdr-txt">申請人資料</span></div>
<div class="row"><div class="lbl">用戶編號</div><div class="val mono"><?= htmlspecialchars($d['user_id']) ?></div></div>
<div class="row"><div class="lbl">社區</div><div class="val"><?= htmlspecialchars($d['member']) ?></div></div>
<div class="row"><div class="lbl">姓名</div><div class="val"><?= htmlspecialchars($d['applicant_name']) ?></div></div>
<div class="row"><div class="lbl">證件號碼</div><div class="val mono"><?= htmlspecialchars($d['applicant_usernumber']) ?></div></div>
<div class="row"><div class="lbl">行動電話</div><div class="val"><?= htmlspecialchars($d['applicant_phone']) ?></div></div>
<div class="row"><div class="lbl">住宅電話</div><div class="val"><?= htmlspecialchars($d['applicant_homenumber'] ?: '—') ?></div></div>
<div class="row"><div class="lbl">裝機地址</div><div class="val"><?= htmlspecialchars($d['memberaddress'].$d['useraddress']) ?></div></div>
<div class="row"><div class="lbl">電子信箱</div><div class="val" style="font-size:13px"><?= htmlspecialchars($d['applicant_email']) ?></div></div>
<div class="row"><div class="lbl">申請速率</div><div class="val green"><?= htmlspecialchars($d['speed']) ?> Mbps</div></div>
<div class="row"><div class="lbl">連接據點</div><div class="val mono"><?= htmlspecialchars($d['basenumber']) ?></div></div>
<div class="row"><div class="lbl">PPPoE<br>帳號</div><div class="val mono"><?= htmlspecialchars($d['pppoeid']) ?></div></div>
<div class="row"><div class="lbl">PPPoE<br>密碼</div><div class="val mono"><?= htmlspecialchars($d['pppoepw']) ?></div></div>
<?php if (!empty($d['fistcount'])): ?>
<div class="row"><div class="lbl">首裝優惠</div><div class="val" style="font-size:12px;color:var(--text-sec)"><?= nl2br(htmlspecialchars($d['fistcount'])) ?></div></div>
<?php endif; ?>
</div>
<!-- 設備 -->
<div class="card">
<div class="card-hdr"><i class="ti ti-server"></i><span class="card-hdr-txt">設備資訊</span></div>
<div class="row">
<div class="lbl">資訊箱<br>設備</div>
<div class="val">
<?php if (empty($infoList)): ?>
<span style="color:var(--text-tert)">—</span>
<?php else: foreach ($infoList as $item): ?>
<span class="device-chip"><i class="ti ti-check" style="font-size:11px"></i><?= htmlspecialchars($item['device']) ?><?= ($item['device']==='無'||$item['device']==='UY')?'':' ×'.htmlspecialchars($item['qty']) ?></span>
<?php endforeach; endif; ?>
</div>
</div>
<div class="row">
<div class="lbl">網路<br>設備</div>
<div class="val">
<?php if (empty($routerList)): ?>
<span style="color:var(--text-tert)">—</span>
<?php else: foreach ($routerList as $item): ?>
<span class="device-chip"><?= htmlspecialchars($item['device']) ?><?= $item['device']==='單機'?'':' ×'.htmlspecialchars($item['qty']) ?><?= ($item['tvBrand']==='or'&&!empty($item['tvOther']))?' ('.htmlspecialchars($item['tvOther']).')':'' ?></span>
<?php endforeach; endif; ?>
</div>
</div>
<?php
// 只顯示真正的使用設備(use_devices 欄位),不包含 info/router
$useOnlyList = json_decode($d['use_devices'] ?? '[]', true) ?: [];
$purposeMap = ['gift'=>'贈品','borrow'=>'借用','node'=>'據點'];
if (!empty($useOnlyList)): ?>
<div class="row">
<div class="lbl">使用<br>設備</div>
<div class="val" style="padding-top:8px">
<?php foreach ($useOnlyList as $item):
$purpose = $purposeMap[$item['purpose'] ?? ''] ?? '';
$dp = (int)($item['dp'] ?? 0);
$sn = $item['sn'] ?? '';
$nodePos = $item['nodePos'] ?? '';
?>
<div style="margin-bottom:8px">
<span class="device-chip" style="background:#FAEEDA;color:#633806"><?= htmlspecialchars($purpose) ?></span>
<span class="device-chip gray"><?= htmlspecialchars($item['device']) ?></span>
<div style="font-size:11px;color:var(--text-sec);margin-top:3px;margin-left:2px">
料號:<?= htmlspecialchars($sn ?: '—') ?>
<?php if (($item['purpose']??'') === 'borrow' && $dp > 0): ?>
押金:$<?= number_format($dp) ?>
<?php endif; ?>
<?php if (($item['purpose']??'') === 'node' && $nodePos !== ''): ?>
據點編號:<?= htmlspecialchars($nodePos) ?>
<?php endif; ?>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
<?php endif; ?>
</div>
<!-- 費用 -->
<?php
$isSubsc = ($d['fee_type'] === 'subscription');
$totalFeeInt= (int)$d['total_fee'];
$showDash = $isSubsc && empty($extraList); // 定期定額且無加購項目時總計顯示 ----
?>
<div class="card">
<div class="card-hdr"><i class="ti ti-receipt"></i><span class="card-hdr-txt">收費明細</span></div>
<?php if ($isSubsc): ?>
<!-- 定期定額:顯示信用卡繳費說明,不顯示 $0 -->
<div class="fee-row">
<div class="fee-name">網路費用<span style="font-size:11px;color:var(--text-tert);margin-left:6px"><?= htmlspecialchars($feeLabel) ?></span></div>
<div class="fee-amt" style="color:var(--green-dk);font-size:13px">信用卡定期定額繳費</div>
</div>
<?php else: ?>
<div class="fee-row">
<div class="fee-name">網路費用<span style="font-size:11px;color:var(--text-tert);margin-left:6px"><?= htmlspecialchars($feeLabel) ?></span></div>
<div class="fee-amt">$<?= number_format((int)$d['fee_amount']) ?></div>
</div>
<?php endif; ?>
<?php foreach ($extraList as $ex): ?>
<div class="fee-row">
<div class="fee-name">
<?= htmlspecialchars($ex['type']) ?>
<?php if ($ex['type']==='周邊設備' && !empty($ex['sn'])): ?>
<span style="font-size:11px;color:var(--text-tert);margin-left:6px">料號 <?= htmlspecialchars($ex['sn']) ?></span>
<?php endif; ?>
</div>
<div class="fee-amt">$<?= number_format((int)$ex['amt']) ?></div>
</div>
<?php endforeach; ?>
<div style="border-top:0.5px solid var(--gray-bd)">
<div class="total-row">
<span class="total-lbl">應繳費用總計</span>
<?php if ($showDash): ?>
<span class="total-amt" style="color:var(--text-tert);font-size:20px;letter-spacing:0">—</span>
<?php else: ?>
<span class="total-amt">$<?= number_format($totalFeeInt) ?></span>
<?php endif; ?>
</div>
</div>
<?php if ((int)$d['deposit_total'] > 0): ?>
<div class="deposit-row">
<span style="color:var(--text-sec)">使用設備押金</span>
<span style="color:#BA7517;font-weight:500">$<?= number_format((int)$d['deposit_total']) ?></span>
</div>
<?php endif; ?>
</div>
<!-- 日期 -->
<div class="card">
<div class="card-hdr"><i class="ti ti-calendar"></i><span class="card-hdr-txt">日期資訊</span></div>
<div class="date-row"><span class="date-lbl">裝機日</span><span class="date-val"><?= fmtDate($d['install_date']) ?></span></div>
<div class="date-row"><span class="date-lbl">起租日</span><span class="date-val accent"><?= fmtDate($d['rental_start_date']) ?></span></div>
<div class="date-row"><span class="date-lbl">到期日</span><span class="date-val accent"><?= fmtDate($d['rental_end_date']) ?></span></div>
<?php if (!empty($giftList)): ?>
<div class="date-row" style="flex-wrap:wrap">
<div style="width:100%;font-size:13px;color:var(--text-sec);margin-bottom:4px">贈送月份</div>
<div style="width:100%">
<?php foreach ($giftList as $g):
$reason = $g['reason'] ?? '';
$extra = '';
if ($reason === '住戶介紹' && !empty($g['intro'])) {
$extra = '(介紹:'.htmlspecialchars($g['intro']).')';
} elseif ($reason === '他網轉入' && !empty($g['network'])) {
$extra = '('.htmlspecialchars($g['network']).')';
}
?>
<span class="gift-chip">
<i class="ti ti-gift" style="font-size:11px"></i>
<?= htmlspecialchars($reason) ?><?= $extra ?> <?= htmlspecialchars($g['months']) ?>月
</span>
<?php endforeach; ?>
</div>
</div>
<div class="date-row" style="background:var(--green-lt)">
<span class="date-lbl" style="font-weight:500;color:var(--green-deep)">含贈送後到期</span>
<span class="date-val highlight"><?= fmtDate($d['real_end_date'] ?: $d['rental_end_date']) ?></span>
</div>
<?php endif; ?>
</div>
<!-- 核對確認 -->
<div class="check-card">
<div class="check-item" onclick="toggleCheck(this)">
<div class="chk-box"><i class="ti ti-check" style="font-size:13px"></i></div>
<div><div class="chk-txt">申請人資料已核對正確</div><div class="chk-sub">姓名、證件、地址、聯絡方式</div></div>
</div>
<div class="check-item" onclick="toggleCheck(this)">
<div class="chk-box"><i class="ti ti-check" style="font-size:13px"></i></div>
<div><div class="chk-txt">設備資訊已核對正確</div><div class="chk-sub">資訊箱、網路設備、使用設備</div></div>
</div>
<div class="check-item" onclick="toggleCheck(this)">
<div class="chk-box"><i class="ti ti-check" style="font-size:13px"></i></div>
<div><div class="chk-txt">費用與日期已核對正確</div><div class="chk-sub">總金額、裝機日、到期日</div></div>
</div>
</div>
<!-- 工程師簽收(全部勾選後才顯示)-->
<?php
// enname 取得優先序:1. 本次 POST 2. form_enname Session 3. 空字串
$enname = '';
if (!empty($_POST['enname'])) {
$enname = trim($_POST['enname']);
} elseif (!empty($_SESSION['form_enname'])) {
$enname = $_SESSION['form_enname'];
} elseif (!empty($d['enname'])) {
$enname = $d['enname'];
}
// 存回 preview session 確保後續頁面可讀取
$_SESSION['preview']['enname'] = $enname;
// DEBUG:HTML 註解中顯示取得結果(上線後可移除)
echo '<!-- DEBUG enname=['.htmlspecialchars($enname).'] POST=['.htmlspecialchars($_POST['enname']??'').'] SESS=['.htmlspecialchars($_SESSION['form_enname']??'').'] -->';
?>
<div id="engineer-confirm-card" style="display:none">
<div class="card" style="border-color:var(--green);background:var(--green-lt)">
<div style="padding:14px 16px;display:flex;align-items:center;gap:12px">
<div style="width:40px;height:40px;border-radius:50%;background:var(--green);display:flex;align-items:center;justify-content:center;flex-shrink:0">
<i class="ti ti-user-check" style="font-size:20px;color:#fff"></i>
</div>
<div>
<div style="font-size:14px;font-weight:500;color:var(--green-deep)">工程師確認簽收</div>
<div style="font-size:13px;color:var(--green-dk);margin-top:2px">
施工工程師:<strong><?= htmlspecialchars($enname ?: '—') ?></strong>
</div>
<div style="font-size:11px;color:var(--green-dk);margin-top:2px">
已與客戶確認本日費用及收費,資料核對無誤
</div>
<div style="font-size:11px;color:var(--text-sec);margin-top:4px">
確認時間:<span id="confirm-time"></span>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="bottom-bar">
<button class="btn-back" onclick="goBack()"><i class="ti ti-arrow-left" style="font-size:14px"></i> 返回修改</button>
<button class="btn-next" id="next-btn" disabled onclick="goConfirm()">
下一步:簽名送出 <i class="ti ti-arrow-right" style="font-size:15px"></i>
</button>
</div>
<script>
function toggleCheck(row) {
const box = row.querySelector('.chk-box');
box.classList.toggle('on');
const allChecked = [...document.querySelectorAll('.chk-box')].every(b=>b.classList.contains('on'));
const btn = document.getElementById('next-btn');
const pill = document.getElementById('status-pill');
const engCard = document.getElementById('engineer-confirm-card');
btn.disabled = !allChecked;
if(allChecked){
btn.innerHTML = '下一步:簽名送出 <i class="ti ti-arrow-right" style="font-size:15px"></i>';
if(pill){ pill.textContent='已確認'; pill.style.background='var(--green-lt)'; pill.style.color='var(--green-deep)'; }
if(engCard){
engCard.style.display = 'block';
document.getElementById('confirm-time').textContent = new Date().toLocaleString('zh-TW',{hour12:false});
engCard.scrollIntoView({behavior:'smooth', block:'nearest'});
}
} else {
btn.innerHTML = '請先完成核對 <i class="ti ti-lock" style="font-size:15px"></i>';
if(pill){ pill.textContent='待確認'; pill.style.background='var(--amber)'; pill.style.color='var(--amber-txt)'; }
if(engCard) engCard.style.display = 'none';
}
}
function goBack() {
// 把 PHP Session 的贈送月份完整寫回 JS sessionStorage
const giftData = <?= json_encode($giftList) ?>;
// 無論有沒有資料都寫入(空陣列也要覆蓋,避免 SS 殘留舊值)
sessionStorage.setItem('ys_gifts', JSON.stringify(giftData || []));
// 稍微延遲確保 sessionStorage 寫入完成再跳轉
setTimeout(function(){
window.location.href = 'form.php?from_preview=1';
}, 50);
}
function goConfirm() {
window.location.href = 'confirm.php';
}
</script>
</body>
</html>