HEX
Server: Apache/2.4.37 (CentOS Stream) OpenSSL/1.1.1k
System: Linux ysnet.com.tw 4.18.0-553.5.1.el8.x86_64 #1 SMP Tue May 21 05:46:01 UTC 2024 x86_64
User: test (521)
PHP: 7.4.33
Disabled: NONE
Upload Files
File: //proc/self/cwd/Installationlist/confirm.php
<?php
// ============================================================
// confirm.php  ─  確認與簽名頁
// ============================================================
ob_start();
session_start();

// 只接受從 preview.php 過來的合法 session
$d = $_SESSION['preview'] ?? [];
if (empty($d)) {
    header('Location: form.php');
    exit;
}

$userId    = $d['user_id']       ?? '';
$userEmail = $d['applicant_email'] ?? '';
$userName  = $d['applicant_name']  ?? '';

$todayStr  = (new DateTime())->format('Y-m-d');
?>
<!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;--red-lt:#FCEBEB;
            --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}
        .step-badge{font-size:11px;padding:3px 10px;border-radius:20px;background:var(--gray-bg);color:var(--text-sec)}

        .prog-bar{height:3px;background:var(--gray-bd);width:100%}
        .prog-fill{height:3px;background:var(--green);width:0%;transition:width .4s}

        .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}
        .card-hdr-badge{margin-left:auto;font-size:11px;padding:2px 8px;border-radius:20px}
        .badge-req{background:var(--amber);color:var(--amber-txt)}
        .badge-ok{background:var(--green-lt);color:var(--green-deep)}

        /* 條款 */
        .terms-scroll{max-height:160px;overflow-y:auto;padding:12px 14px;font-size:12px;color:var(--text-sec);line-height:1.9;border-bottom:0.5px solid var(--gray-bd)}
        .terms-scroll::-webkit-scrollbar{width:3px}
        .terms-scroll::-webkit-scrollbar-thumb{background:var(--gray-bd2);border-radius:2px}
        .scroll-tip{font-size:11px;color:var(--amber-txt);padding:7px 14px;display:flex;align-items:center;gap:4px;border-bottom:0.5px solid var(--gray-bd);background:var(--amber)}
        .agree-row{display:flex;align-items:center;gap:10px;padding:11px 14px;cursor:pointer;user-select:none}
        .agree-row.disabled{opacity:.4;pointer-events: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;color:transparent}
        .chk-box.on{background:var(--green);border-color:var(--green);color:#fff}
        .agree-txt{font-size:13px;color:var(--text)}

        /* 測速 */
        .speed-grid{display:grid;grid-template-columns:1fr 1fr;gap:1px;background:var(--gray-bd)}
        .speed-cell{background:#fff;padding:12px 14px}
        .speed-lbl{font-size:11px;color:var(--text-sec);margin-bottom:4px;display:flex;align-items:center;gap:4px}
        .speed-input{font-size:22px;font-weight:500;color:var(--text);background:transparent;border:none;outline:none;width:100%;border-bottom:1.5px solid var(--gray-bd2)}
        .speed-input::placeholder{font-size:16px;color:var(--text-tert);font-weight:400}
        .speed-unit{font-size:11px;color:var(--text-sec);margin-top:3px}

        /* 簽名 */
        .sig-area{padding:14px}
        .sig-type-row{display:flex;gap:8px;margin-bottom:10px}
        .sig-type-btn{flex:1;padding:8px;border-radius:var(--radius-md);border:0.5px solid var(--gray-bd2);font-size:13px;cursor:pointer;background:none;color:var(--text-sec);font-family:inherit;transition:all .15s}
        .sig-type-btn.sel{background:var(--green-lt);border-color:var(--green);color:var(--green-dk);font-weight:500}
        .proxy-input{width:100%;font-size:14px;padding:8px 10px;border:0.5px solid var(--gray-bd2);border-radius:var(--radius-md);background:#fff;color:var(--text);font-family:monospace;margin-bottom:10px;outline:none}
        .sig-canvas-wrap{border:1.5px dashed var(--gray-bd2);border-radius:var(--radius-md);background:var(--gray-bg);height:120px;position:relative;overflow:hidden;cursor:crosshair;touch-action:none}
        .sig-canvas-wrap canvas{position:absolute;top:0;left:0;width:100%;height:100%}
        .sig-placeholder{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;pointer-events:none;color:var(--text-tert);font-size:13px}
        .sig-placeholder i{font-size:22px}
        .sig-actions{display:flex;gap:8px;margin-top:8px}
        .sig-btn{flex:1;padding:7px;border-radius:var(--radius-md);border:0.5px solid var(--gray-bd2);font-size:12px;cursor:pointer;background:none;color:var(--text-sec);font-family:inherit}
        .sig-btn.primary{background:var(--green);border-color:var(--green);color:#fff}

        /* 證件上傳 */
        .photo-list{padding:12px 14px;display:flex;flex-direction:column;gap:10px}
        .photo-item{display:flex;align-items:center;gap:10px}
        .photo-thumb{width:56px;height:40px;border-radius:var(--radius-md);border:0.5px solid var(--gray-bd);background:var(--gray-bg);display:flex;align-items:center;justify-content:center;overflow:hidden;flex-shrink:0}
        .photo-thumb img{width:100%;height:100%;object-fit:cover}
        .photo-thumb i{font-size:18px;color:var(--text-tert)}
        .photo-info{flex:1}
        .photo-name{font-size:13px;color:var(--text)}
        .photo-sub{font-size:11px;color:var(--text-sec);margin-top:2px}
        .photo-upload-btn{font-size:12px;padding:5px 12px;border:0.5px solid var(--gray-bd2);border-radius:20px;background:none;cursor:pointer;color:var(--text-sec);font-family:inherit;white-space:nowrap}
        .photo-upload-btn.done{border-color:var(--green);color:var(--green-dk);background:var(--green-lt)}
        .watermark-note{font-size:11px;color:var(--text-tert);padding:8px 14px;border-top:0.5px solid var(--gray-bd);display:flex;align-items:center;gap:4px}

        /* 底部進度列 */
        .mini-check{display:flex;align-items:center;gap:3px;font-size:11px}
        .mini-check.ok{color:var(--green)}
        .mini-check.no{color:var(--amber-txt)}

        .bottom-bar{position:sticky;bottom:0;background:#fff;border-top:0.5px solid var(--gray-bd);padding:12px 16px}
        .checklist-mini{display:flex;gap:10px;margin-bottom:8px;flex-wrap:wrap}
        .submit-btn{width:100%;padding:14px;background:var(--green);color:#fff;border:none;border-radius:var(--radius-md);font-size:15px;font-weight:500;cursor:pointer;font-family:inherit;display:flex;align-items:center;justify-content:center;gap:6px;transition:opacity .2s}
        .submit-btn:disabled{opacity:.35;cursor:not-allowed}

        /* 完成畫面 */
        .success-card{background:var(--green-lt);border:0.5px solid #9FE1CB;border-radius:var(--radius-lg);padding:24px 16px;text-align:center;display:none;flex-direction:column;align-items:center;gap:10px}
        .success-icon{width:52px;height:52px;border-radius:50%;background:var(--green);display:flex;align-items:center;justify-content:center;margin:0 auto}
        .success-title{font-size:17px;font-weight:500;color:var(--green-deep)}
        .success-sub{font-size:13px;color:var(--green-dk);line-height:1.6}
        .success-actions{display:flex;gap:8px;width:100%;margin-top:6px}
        .success-btn{flex:1;padding:11px;border-radius:var(--radius-md);font-size:13px;cursor:pointer;font-family:inherit;font-weight:500}
        .success-btn.outline{background:none;border:1px solid var(--green);color:var(--green-dk)}
        .success-btn.solid{background:var(--green);border:none;color:#fff}

        .otp-box{border:0.5px solid var(--gray-bd2);border-radius:var(--radius-md);padding:12px;margin-top:10px;background:#F9FFF9}
        .otp-input{width:100%;font-size:22px;letter-spacing:10px;text-align:center;padding:10px;border:1.5px solid var(--gray-bd2);border-radius:var(--radius-md);margin:8px 0;font-family:monospace}
        .otp-btn{width:100%;padding:10px;background:var(--green);color:#fff;border:none;border-radius:var(--radius-md);font-size:14px;cursor:pointer;font-family:inherit}
    </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="step-badge">最後一步</span>
</div>
<div class="prog-bar"><div class="prog-fill" id="prog-fill"></div></div>

<div class="content">

    <!-- 服務條款 -->
    <div class="card">
        <div class="card-hdr">
            <i class="ti ti-file-text"></i>
            <span class="card-hdr-txt">服務條款</span>
            <span class="card-hdr-badge badge-req" id="terms-badge">請閱讀後同意</span>
        </div>
        <div class="terms-scroll" id="terms-box" onscroll="onTermsScroll()">
            <strong>第一條</strong><br>Internet係開放性網路,各種資源之正確性與完整性,本公司無法保證,倘客戶因截取使用網路資料而導致損失時,本公司亦不負損害賠償責任。<br><br>
            <strong>第二條</strong><br>用戶租用本業務應繳各項費用及收費標準如價目表;資費如有調整時,按新費率計收,用戶如不同意繳付新費率,可隨時終止契約,並辦理退費。申請加值服務者,以網頁上公告費用計收各項費用。<br><br>
            <strong>第三條</strong><br>本公司因技術上需要,得將用戶號碼、用戶識別碼、IP ADDRESS、連接方式、用戶解面、傳輸型態等予以變更,用戶不得異議或提出其他要求。<br><br>
            <strong>第四條</strong><br>本公司使用網路位址轉換技術共享真實IP,少數需要真實IP的連線服務會受此限制,用戶應確認有無此需求。<br><br>
            <strong>第五條</strong><br>本公司基於保障消費者權益,給予您一個月滿意鑑賞期,期間若不滿意,本公司保證全額退費。<br><br>
            <strong>第六條</strong><br>本公司配發每一個用戶一組帳號密碼,每組帳號密碼可供一台電腦使用,若家中為兩台以上電腦上網,則需請用戶使用IP分享器。<br><br>
            <strong>第七條</strong><br>本公司以戶為單位,用戶不得私自接線提供他戶使用。<br><br>
            <strong>第八條</strong><br>用戶端如有無線網路路由設備,應設加密,以防止第三人竊取頻寬或是進行違法情形。<br><br>
            <strong>第九條</strong><br>本公司應維持本業務系統設備之正常運作,遇有障礙應盡速修復。但用戶自備設備者,應自行檢修,用戶使用本業務,如因本公司系統設備障礙、阻斷,以致發生錯誤、遲滯、中斷或不能傳遞而造成損害時,其所發生之損害,除按本契約條款第十條之規定給予補償外,本公司不負損害賠責任。<br><br>
            <strong>第十條</strong><br>用戶租用本業務,因不可歸責於用戶之原因,致系統障礙不能通信時:本公司應扣減網路租費。通信連續阻斷二十四小時以上者,每二十四小時扣減全月租費三十分一,但不滿二十四小時部分,不予減扣。由於天然災害之不可抗力致不能通信者,自連續阻日起至修復日止,不收租費。前項阻斷開始之時間,以本公司查覺或接到用戶通知之時間為準。但有事實足以證明實際開始阻斷之時間者,依實際開始阻斷之時間為準。<br><br>
            <strong>第十一條(退租說明)</strong><br>辦理退租時,須請申請人或其代理人攜帶各自的有效身份證明文件正本、雙證件正本,至本公司桃園市桃園區大興西路二段61號16樓辦理退費,相關注意事項如下:<br>
            1. 使用登記人為退費的權益人,退費需攜帶雙證件正本辦理,倘委託代理人辦理,則代理人需攜帶使用登記人之雙證件正本及代理人的雙證件正本,方可辦理。<br>
            2. 用戶至門市填妥退租申請書,完成折讓程序並經身份確認後,方可退費。<br>
            3. 使用月份不足一個月者,依使用天數等比例結算,贈送月份不計入退費月份。<br>
            4. 倘有加購之優惠,於計算已使用月份之費用時,先依標準資費計算,之後的月份再依加購資費計算。<br>
            5. 特定資費方案有聲明不得退費者,不享有以上退費措施。<br>
            6. 申裝優惠方案,倘使用未滿優惠期限內退費,則喪失優惠資格,必需補繳優惠之裝機費用新台幣500元,若有贈品則需補繳裝機時提供贈品之費用。<br>
            7. 光纖安裝用戶,若不續用網路需自行歸還光纖設備,包含光纖盒、變壓器及光纖線,則無息退還押金。<br>
            8. 影音方案須綁約乙年,期間無法退租退費。(方案中電視盒、Litv收視壹年及分享器為贈品)<br><br>
            <strong>第十二條</strong><br>用戶租用本業務應繳之費用應在本公司通知繳費之期限內繳清,逾期未繳費者,本公司得註銷其申請並暫停其使用。經限期催繳仍未繳納者,得終止其使用,用戶積欠之費用仍需繳納。用戶對各項應繳費用有異議並申訴者,在未查明責任歸屬前,本公司暫緩催費。<br><br>
            <strong>第十三條</strong><br>
            1. 有竊取、更改、破壞他人資訊情事者。<br>
            2. 有擅自複製他人資訊轉售、轉載情事者。<br>
            3. 未經對方同意、擅自寄發垃圾、炸彈郵包或廣告郵件至對方信箱者。<br>
            4. 於論壇區張貼與主題無關之訊息者。<br>
            5. 蓄意破壞他人信箱或其通信設備者。<br>
            6. 散播電腦病毒者。<br>
            7. 所為言論違背公序良俗者。<br>
            8. 擷取非經所有正式開放或授權之資源者。<br>
            9. 不當使用續傳軟體者。<br>
            10. 其他有危通信或網路品質穩定之情事者。<br>
            11. 提供妨害公共秩序及善良風俗之電信內容為營業者。<br><br>
            <strong>第十四條</strong><br>本公司於P2P相關軟體上(如:BT、迅雷等)下載與上傳皆無問題;為維護社區網路之連線品質,對於影響該社區其他用戶上網品質之情形,得限制其頻寬,若有大量P2P傳輸需求的使用者,請謹慎評估。<br><br>
            <strong>第十五條</strong><br>申請電信業務所需之相關證件,依據主管機關通訊傳播委員會相關要求辦理;針對個人資料收集及各項告知義務,則依據個人資料保護法相關細則實行。<br><br>
            <strong>第十六條</strong><br>本契約條款未規定事項,用戶同意遵守相關法令規定及本公司各項業務營業規章之規定。<br><br>
            <strong>第十七條</strong><br>因本契約涉訟時,雙方合意以桃園地方法院為第一審管轄法院。
        </div>
        <div class="scroll-tip" id="scroll-tip">
            <i class="ti ti-arrow-down" style="font-size:13px"></i>
            請捲動閱讀完整條款後才能同意
        </div>
        <div class="agree-row disabled" id="agree-row" onclick="toggleAgree()">
            <div class="chk-box" id="agree-box"><i class="ti ti-check" style="font-size:14px"></i></div>
            <span class="agree-txt">我已閱讀並同意上述服務條款</span>
        </div>
    </div>

    <!-- 完工測速 -->
    <div class="card">
        <div class="card-hdr">
            <i class="ti ti-gauge"></i>
            <span class="card-hdr-txt">完工有線測速</span>
            <span class="card-hdr-badge badge-req" id="speed-badge">必填</span>
        </div>
        <div class="speed-grid">
            <div class="speed-cell">
                <div class="speed-lbl"><i class="ti ti-arrow-down" style="font-size:12px"></i>下載速率</div>
                <input class="speed-input" type="number" id="dl-speed" min="1" placeholder="—" oninput="updateProgress()">
                <div class="speed-unit">Mbps</div>
            </div>
            <div class="speed-cell">
                <div class="speed-lbl"><i class="ti ti-arrow-up" style="font-size:12px"></i>上傳速率</div>
                <input class="speed-input" type="number" id="ul-speed" min="1" placeholder="—" oninput="updateProgress()">
                <div class="speed-unit">Mbps</div>
            </div>
        </div>
    </div>

    <!-- 簽名 -->
    <div class="card">
        <div class="card-hdr">
            <i class="ti ti-pencil"></i>
            <span class="card-hdr-txt">申請人簽名</span>
            <span class="card-hdr-badge badge-req" id="sig-badge">未簽名</span>
        </div>
        <div class="sig-area">
            <div class="sig-type-row">
                <button class="sig-type-btn sel" onclick="setSigType('本人',this)">本人簽名</button>
                <button class="sig-type-btn" onclick="setSigType('代簽',this)">代簽</button>
            </div>
            <input class="proxy-input" id="proxy-input" type="text" placeholder="代簽人身分證字號"
                maxlength="10" style="display:none;font-family:monospace" oninput="updateProgress()">
            <!-- 點此開啟全螢幕簽名板 -->
            <div id="sig-trigger" onclick="openSigModal()"
                style="border:1.5px dashed var(--gray-bd2);border-radius:var(--radius-md);background:var(--gray-bg);height:80px;display:flex;align-items:center;justify-content:center;cursor:pointer;gap:8px;color:var(--text-sec);font-size:14px">
                <i class="ti ti-pencil" style="font-size:20px;color:var(--green)"></i>
                點此開啟簽名板
            </div>
            <!-- 確認後顯示的簽名預覽 -->
            <div id="sig-preview-wrap" style="display:none;margin-top:8px">
                <img id="sig-preview-img" style="width:100%;border:0.5px solid var(--gray-bd);border-radius:var(--radius-md);background:#fff">
                <button type="button" onclick="openSigModal()"
                    style="margin-top:8px;width:100%;padding:8px;border:0.5px solid var(--gray-bd2);border-radius:var(--radius-md);background:none;cursor:pointer;font-size:13px;color:var(--text-sec);font-family:inherit">
                    <i class="ti ti-pencil" style="font-size:13px"></i> 重新簽名
                </button>
            </div>
        </div>
    </div>

    <!-- 上傳雙證件 -->
    <div class="card">
        <div class="card-hdr">
            <i class="ti ti-id"></i>
            <span class="card-hdr-txt">上傳雙證件</span>
            <span class="card-hdr-badge badge-req" id="photo-badge">0 / 3</span>
        </div>
        <div class="photo-list">
            <div class="photo-item">
                <div class="photo-thumb" id="thumb-0"><i class="ti ti-id"></i></div>
                <div class="photo-info">
                    <div class="photo-name">身分證正面</div>
                    <div class="photo-sub" id="photo-sub-0">尚未上傳</div>
                </div>
                <label>
                    <input type="file" accept="image/*" capture="environment" style="display:none" onchange="handlePhoto(this,0)">
                    <span class="photo-upload-btn" id="photo-btn-0">上傳</span>
                </label>
            </div>
            <div class="photo-item">
                <div class="photo-thumb" id="thumb-1"><i class="ti ti-id"></i></div>
                <div class="photo-info">
                    <div class="photo-name">身分證反面</div>
                    <div class="photo-sub" id="photo-sub-1">尚未上傳</div>
                </div>
                <label>
                    <input type="file" accept="image/*" capture="environment" style="display:none" onchange="handlePhoto(this,1)">
                    <span class="photo-upload-btn" id="photo-btn-1">上傳</span>
                </label>
            </div>
            <div class="photo-item">
                <div class="photo-thumb" id="thumb-2"><i class="ti ti-credit-card"></i></div>
                <div class="photo-info">
                    <div class="photo-name">第二證件正面</div>
                    <div class="photo-sub" id="photo-sub-2">尚未上傳</div>
                </div>
                <label>
                    <input type="file" accept="image/*" capture="environment" style="display:none" onchange="handlePhoto(this,2)">
                    <span class="photo-upload-btn" id="photo-btn-2">上傳</span>
                </label>
            </div>
        </div>
        <div class="watermark-note">
            <i class="ti ti-shield-check" style="font-size:13px"></i>
            上傳後將自動加上「限申辦亞訊專用」浮水印
        </div>
    </div>

    <!-- 送出中提示(送出後顯示,防止重複操作) -->
    <div id="submitting-overlay" style="display:none;position:fixed;inset:0;background:rgba(255,255,255,0.95);z-index:9998;flex-direction:column;align-items:center;justify-content:center;gap:16px">
        <div style="width:52px;height:52px;border-radius:50%;background:var(--green-lt);display:flex;align-items:center;justify-content:center">
            <i class="ti ti-loader" style="font-size:26px;color:var(--green)"></i>
        </div>
        <div style="font-size:16px;font-weight:500;color:var(--green-deep)">正在送出申請書…</div>
        <div style="font-size:13px;color:var(--text-sec)">請稍候,正在產生 PDF 並寄送 Email</div>
    </div>
        </div>

</div><!-- /content -->

<!-- ── 全螢幕簽名 Modal ── -->
<div id="sig-modal" style="display:none;position:fixed;inset:0;z-index:9999;background:#fff;flex-direction:column">
    <div style="display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:0.5px solid var(--gray-bd);flex-shrink:0;background:#fff">
        <span style="font-size:16px;font-weight:500;color:var(--text)">申請人簽名</span>
        <div style="display:flex;gap:10px">
            <button onclick="clearSig()" style="padding:8px 16px;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">
                <i class="ti ti-eraser" style="font-size:13px"></i> 清除
            </button>
            <button onclick="confirmSig()" style="padding:8px 20px;background:var(--green);color:#fff;border:none;border-radius:var(--radius-md);font-size:14px;font-weight:500;cursor:pointer;font-family:inherit">
                <i class="ti ti-check" style="font-size:13px"></i> 確認
            </button>
        </div>
    </div>
    <div class="sig-modal-area" style="flex:1;position:relative;overflow:hidden;background:#fafafa">
        <canvas id="sig-canvas" style="position:absolute;inset:0;touch-action:none;cursor:crosshair;display:block"></canvas>
        <div id="sig-placeholder" style="position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;pointer-events:none;color:var(--text-tert)">
            <i class="ti ti-pencil" style="font-size:36px"></i>
            <span style="font-size:15px">請在此區域簽名</span>
        </div>
    </div>
    <div style="padding:10px 16px;border-top:0.5px solid var(--gray-bd);flex-shrink:0;text-align:center;font-size:12px;color:var(--text-tert);background:#fff">
        橫向簽名效果較佳,可旋轉手機後簽名
    </div>
</div>

<div class="bottom-bar">
    <div class="checklist-mini" id="checklist-mini">
        <span class="mini-check no" id="chk-terms"><i class="ti ti-circle-x"></i> 條款</span>
        <span class="mini-check no" id="chk-speed"><i class="ti ti-circle-x"></i> 測速</span>
        <span class="mini-check no" id="chk-sig"><i class="ti ti-circle-x"></i> 簽名</span>
        <span class="mini-check no" id="chk-photo"><i class="ti ti-circle-x"></i> 證件</span>
    </div>
    <button class="submit-btn" id="submit-btn" disabled onclick="doSubmit()">
        <i class="ti ti-send" style="font-size:16px"></i>
        送出申請並寄送 PDF
    </button>
</div>

<script>
// ── 狀態 ──────────────────────────────
const STATE = { agreed:false, dl:false, ul:false, signed:false, photos:[false,false,false], sigType:'本人', proxyOk:true };

// ── 條款捲動 ──────────────────────────
function onTermsScroll() {
    const el = document.getElementById('terms-box');
    if(el.scrollTop + el.clientHeight >= el.scrollHeight - 6) {
        const row = document.getElementById('agree-row');
        row.classList.remove('disabled');
        document.getElementById('scroll-tip').style.display = 'none';
    }
}

function toggleAgree() {
    STATE.agreed = !STATE.agreed;
    const box = document.getElementById('agree-box');
    box.classList.toggle('on', STATE.agreed);
    const badge = document.getElementById('terms-badge');
    badge.textContent = STATE.agreed ? '已同意' : '請閱讀後同意';
    badge.className = 'card-hdr-badge ' + (STATE.agreed ? 'badge-ok' : 'badge-req');
    updateProgress();
}

// ── 測速 ─────────────────────────────
document.getElementById('dl-speed').addEventListener('input', function(){
    STATE.dl = parseFloat(this.value) > 0;
    updateProgress();
});
document.getElementById('ul-speed').addEventListener('input', function(){
    STATE.ul = parseFloat(this.value) > 0;
    updateProgress();
});

// ── 簽名(全螢幕 Modal)────────────────
let sigType     = '本人';
let hasStrokes  = false;
let drawing     = false;
let sigDataURL  = null;

const canvas   = document.getElementById('sig-canvas');
const ctx      = canvas.getContext('2d');
const sigModal = document.getElementById('sig-modal');

function initCanvas() {
    const area = sigModal.querySelector('.sig-modal-area');
    canvas.width  = area ? area.offsetWidth  : window.innerWidth;
    canvas.height = area ? area.offsetHeight : (window.innerHeight - 110);
    ctx.strokeStyle = '#111';
    ctx.lineWidth   = 2.5;
    ctx.lineCap     = 'round';
    ctx.lineJoin    = 'round';
}

function openSigModal() {
    sigModal.style.display = 'flex';
    document.body.style.overflow = 'hidden';
    setTimeout(function() {
        initCanvas();
        hasStrokes = false;
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        document.getElementById('sig-placeholder').style.display = 'flex';
    }, 60);
}

function setSigType(type, btn) {
    sigType = type;
    STATE.sigType = type;
    document.querySelectorAll('.sig-type-btn').forEach(function(b){ b.classList.remove('sel'); });
    btn.classList.add('sel');
    const proxy = document.getElementById('proxy-input');
    proxy.style.display = type === '代簽' ? 'block' : 'none';
    STATE.proxyOk = (type === '本人');
    updateProgress();
}

function getPos(e) {
    const rect = canvas.getBoundingClientRect();
    const src  = e.touches ? e.touches[0] : e;
    return {
        x: (src.clientX - rect.left) * (canvas.width  / rect.width),
        y: (src.clientY - rect.top)  * (canvas.height / rect.height)
    };
}

canvas.addEventListener('mousedown',  startDraw);
canvas.addEventListener('touchstart', startDraw, { passive: false });

function startDraw(e) {
    e.preventDefault();
    drawing = true;
    const p = getPos(e);
    ctx.beginPath();
    ctx.moveTo(p.x, p.y);
    document.getElementById('sig-placeholder').style.display = 'none';
    document.addEventListener('mousemove',  onDraw);
    document.addEventListener('mouseup',    stopDraw);
    document.addEventListener('touchmove',  onDraw,   { passive: false });
    document.addEventListener('touchend',   stopDraw);
}
function onDraw(e) {
    if(!drawing) return;
    e.preventDefault();
    const p = getPos(e);
    ctx.lineTo(p.x, p.y);
    ctx.stroke();
    hasStrokes = true;
}
function stopDraw() {
    drawing = false;
    document.removeEventListener('mousemove',  onDraw);
    document.removeEventListener('mouseup',    stopDraw);
    document.removeEventListener('touchmove',  onDraw);
    document.removeEventListener('touchend',   stopDraw);
}

function clearSig() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    hasStrokes = false;
    document.getElementById('sig-placeholder').style.display = 'flex';
}

function confirmSig() {
    if(!hasStrokes) { alert('請先在方框內簽名'); return; }
    sigDataURL = canvas.toDataURL('image/png');
    sigModal.style.display = 'none';
    document.body.style.overflow = '';
    document.getElementById('sig-preview-img').src = sigDataURL;
    document.getElementById('sig-preview-wrap').style.display = 'block';
    document.getElementById('sig-trigger').style.display = 'none';
    STATE.signed = true;
    const badge = document.getElementById('sig-badge');
    badge.textContent = '已簽名';
    badge.className   = 'card-hdr-badge badge-ok';
    updateProgress();
}

window.addEventListener('orientationchange', function() {
    if(sigModal.style.display !== 'none') { setTimeout(initCanvas, 300); }
});

// ── 代簽人身分證驗證 ─────────────────
document.getElementById('proxy-input').addEventListener('input', function(){
    const v = this.value.toUpperCase().replace(/[^A-Z0-9]/g, '');
    this.value = v;
    STATE.proxyOk = /^[A-Z][12]\d{8}$/.test(v) || /^[A-Z]{2}\d{8}$/.test(v);
    updateProgress();
});

// ── 證件上傳 ─────────────────────────
let photoDone = [false, false, false];

function handlePhoto(input, idx) {
    const file = input.files[0];
    if(!file) return;
    const reader = new FileReader();
    reader.onload = function(e) {
        const img = new Image();
        img.onload = function() {
            const c = document.createElement('canvas');
            c.width = img.width; c.height = img.height;
            const cx = c.getContext('2d');
            cx.drawImage(img, 0, 0);
            // 加浮水印
            cx.font = `bold ${Math.floor(img.width/14)}px Microsoft JhengHei`;
            cx.fillStyle = 'rgba(255,0,0,0.55)';
            cx.textAlign = 'center';
            cx.textBaseline = 'middle';
            cx.fillText('限申辦亞訊寬頻網路專用', img.width/2, img.height/2);
            const result = c.toDataURL('image/jpeg', 0.92);

            // 更新縮圖
            const thumb = document.getElementById('thumb-'+idx);
            thumb.innerHTML = `<img src="${result}">`;
            document.getElementById('photo-sub-'+idx).textContent = '已上傳(含浮水印)';
            const btn = document.getElementById('photo-btn-'+idx);
            btn.textContent = '重新上傳'; btn.className = 'photo-upload-btn done';

            photoDone[idx] = result;
            STATE.photos = photoDone.slice();
            const cnt = photoDone.filter(Boolean).length;
            const badge = document.getElementById('photo-badge');
            badge.textContent = cnt + ' / 3';
            badge.className = 'card-hdr-badge ' + (cnt===3 ? 'badge-ok' : 'badge-req');
            updateProgress();
        };
        img.src = e.target.result;
    };
    reader.readAsDataURL(file);
}

// ── 進度更新 ─────────────────────────
function updateProgress() {
    const speedOk = STATE.dl && STATE.ul;
    const proxyVal = document.getElementById('proxy-input').value.trim();
    STATE.proxyOk = STATE.sigType === '本人' ||
        /^[A-Z][12]\d{8}$/.test(proxyVal) || /^[A-Z]{2}\d{8}$/.test(proxyVal);
    const photoOk = STATE.photos.every(Boolean);

    const checks = [
        { id:'chk-terms', ok:STATE.agreed,                    label:'條款' },
        { id:'chk-speed', ok:speedOk,                         label:'測速' },
        { id:'chk-sig',   ok:STATE.signed && STATE.proxyOk,   label:'簽名' },
        { id:'chk-photo', ok:photoOk,                         label:'證件' },
    ];
    let done = 0;
    checks.forEach(c => {
        const el = document.getElementById(c.id);
        el.className = 'mini-check ' + (c.ok ? 'ok' : 'no');
        el.innerHTML = `<i class="ti ${c.ok?'ti-circle-check':'ti-circle-x'}"></i> ${c.label}`;
        if(c.ok) done++;
    });

    const pct = Math.round(done / checks.length * 100);
    document.getElementById('prog-fill').style.width = pct + '%';

    const allOk = checks.every(c=>c.ok);
    const btn = document.getElementById('submit-btn');
    btn.disabled = !allOk;
    btn.innerHTML = allOk
        ? '<i class="ti ti-send" style="font-size:16px"></i> 送出申請並寄送 PDF'
        : `<i class="ti ti-lock" style="font-size:16px"></i> 尚有 ${checks.length-done} 項未完成`;
}

// ── 送出 ─────────────────────────────
function doSubmit() {
    if(!sigDataURL){ alert('請先完成簽名'); return; }

    // 顯示送出中遮罩,防止重複點擊
    const overlay = document.getElementById('submitting-overlay');
    overlay.style.display = 'flex';
    document.querySelector('.bottom-bar').style.display = 'none';

    const fd = new FormData();
    fd.append('user_id',     '<?= htmlspecialchars($userId) ?>');
    fd.append('sig_type',    STATE.sigType);
    fd.append('proxy_id',    document.getElementById('proxy-input').value.trim());
    fd.append('dl_speed',    document.getElementById('dl-speed').value);
    fd.append('ul_speed',    document.getElementById('ul-speed').value);
    fd.append('install_date','<?= $todayStr ?>');

    // 簽名圖(Blob)
    (function(){
        const arr=sigDataURL.split(','), mime=arr[0].match(/:(.*?);/)[1], bstr=atob(arr[1]);
        const ia=new Uint8Array(bstr.length); for(let i=0;i<bstr.length;i++) ia[i]=bstr.charCodeAt(i);
        fd.append('signature', new Blob([ia],{type:mime}), 'signature.png');
    })();

    // 三張證件(Blob)
    STATE.photos.forEach(function(dataUrl, i){
        if(!dataUrl) return;
        const arr=dataUrl.split(','), bstr=atob(arr[1]);
        const ia=new Uint8Array(bstr.length); for(let j=0;j<bstr.length;j++) ia[j]=bstr.charCodeAt(j);
        fd.append('photo_'+i, new Blob([ia],{type:'image/jpeg'}), 'photo_'+i+'.jpg');
    });

    fetch('submit.php', {method:'POST', body:fd})
        .then(function(r){ if(!r.ok) throw new Error('伺服器錯誤 '+r.status); return r.json(); })
        .then(function(data){
            if(data.success){
                console.log('[submit] debug:', JSON.stringify(data.debug||{}, null, 2));
                window.location.replace('done.php?token=' + encodeURIComponent(data.pdf_token || ''));
            } else {
                overlay.style.display = 'none';
                document.querySelector('.bottom-bar').style.display = '';
                alert('送出失敗:'+(data.message||'請聯繫客服'));
            }
        })
        .catch(function(err){
            overlay.style.display = 'none';
            document.querySelector('.bottom-bar').style.display = '';
            alert('網路錯誤:'+err.message);
        });
}

// 初始化
updateProgress();
</script>
</body>
</html>