2026-04-29 10:00:40 +00:00
<!DOCTYPE html>
< html lang = "zh-TW" >
< head >
< meta charset = "UTF-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1.0" >
< title > Harmonic CMTS Manager< / title >
< link rel = "stylesheet" href = "https://cdn.jsdelivr.net/npm/xterm@5.3.0/css/xterm.css" / >
< script src = "https://cdn.jsdelivr.net/npm/xterm@5.3.0/lib/xterm.js" > < / script >
< script src = "https://cdn.jsdelivr.net/npm/xterm-addon-fit@0.8.0/lib/xterm-addon-fit.js" > < / script >
<!-- 引入我們剛剛獨立出來的 CSS 樣式表 -->
< link rel = "stylesheet" href = "/static/style.css" / >
< / head >
< body >
< h1 > 🎙️ Harmonic CMTS Admin< / h1 >
< div class = "global-settings" >
< label > < strong > 🌐 目標設備:< / strong > < / label >
< input type = "text" id = "cmtsHost" placeholder = "IP 地址" value = "10.14.110.4" style = "width: 130px;" >
< input type = "text" id = "cmtsUser" placeholder = "帳號" value = "admin" style = "width: 100px;" >
< input type = "password" id = "cmtsPass" placeholder = "密碼" value = "nsgadmin" style = "width: 100px;" >
< div style = "margin-left: 15px; display: flex; align-items: center; gap: 10px;" >
< button onclick = "connectWebSocket()" id = "btnConnect" style = "background-color: #27ae60;" > 連線至 CMTS< / button >
< button onclick = "disconnectWebSocket()" id = "btnDisconnect" style = "background-color: #c0392b; display: none;" > 斷開連線< / button >
< span id = "wsStatus" style = "color: #7f8c8d; font-size: 14px; font-weight: bold;" > 狀態:未連線< / span >
< / div >
< / div >
< div class = "tabs" >
< button class = "tab-btn active" onclick = "switchTab('cli-tab', this)" > 💻 True SSH Terminal< / button >
< button class = "tab-btn" onclick = "switchTab('query-tab', this)" > 🔍 CMTS 狀態查詢< / button >
< button class = "tab-btn" onclick = "switchTab('config-tab', this)" > ⚙️ CMTS 設備配置< / button >
< / div >
<!-- Tab 1: True SSH Terminal -->
< div id = "cli-tab" class = "tab-content active" >
< div class = "control-group" >
< label > < strong > 快捷指令:< / strong > < / label >
< select id = "fixedCmd" >
< option value = "show cable modem" > 數據機狀態 (show cable modem)< / option >
< option value = "show cable rpd" > RPD 狀態 (show cable rpd)< / option >
< option value = "show running-config | nomore" > 系統實時設定檔 (show running-config | nomore)< / option >
< / select >
< button onclick = "injectCommand()" style = "background-color: #8e44ad;" > 送出指令< / button >
< div style = "margin-left: auto; display: flex; gap: 8px;" >
< button onclick = "downloadTerminal()" style = "background-color: #7f8c8d;" > 💾 下載紀錄< / button >
< / div >
< / div >
< div id = "terminal-container" > < / div >
< / div >
<!-- Tab 2: CMTS 狀態查詢 -->
< div id = "query-tab" class = "tab-content" style = "overflow-y: auto; background-color: #f5f7fa;" >
< div class = "manager-container" >
< div class = "control-group" style = "background: #ffffff; padding: 15px 25px; border-radius: 8px; margin-bottom: 0; box-shadow: 0 2px 4px rgba(0,0,0,0.02); border: 1px solid #e2e8f0;" >
< label style = "font-weight: bold; color: #2c3e50; font-size: 16px; margin-right: 10px;" > 📌 選擇查詢任務:< / label >
< select id = "queryTask" onchange = "switchQueryTask()" style = "width: 400px; max-width: 100%; font-weight: bold; font-size: 15px; padding: 8px; background-color: #f8f9fa;" >
< option value = "form-cm-query" > 🔎 Cable 狀態綜合查詢< / option >
< option value = "form-rpd-query" > 📡 RPD 狀態綜合查詢< / option >
< / select >
< / div >
<!-- 表單 1: Cable 狀態綜合查詢 -->
< div id = "form-cm-query" class = "task-form active" >
< h3 style = "margin-top: 0; font-size: 18px; color: #2980b9; border-bottom: 2px solid #ecf0f1; padding-bottom: 10px; margin-bottom: 20px;" > Cable 狀態綜合查詢 (show cable modem...)< / h3 >
< div class = "form-grid" >
< div class = "form-row" >
< label > 目標設備 (Cable Modem MAC)< / label >
< input type = "text" id = "queryTargetCm" placeholder = "例: 6467.7240.4076 (留白則查詢全體)" >
< / div >
< div class = "form-row" >
< label > 查詢動作 (Action)< / label >
< select id = "queryTypeCm" onchange = "toggleQueryInputs('Cm')" >
< optgroup label = "Cable Modem 查詢 (支援特定目標或全體)" >
< option value = "base" > 基本狀態 (show cable modem)< / option >
< option value = "cpe" > CPE 資訊 (cpe)< / option >
< option value = "cpe_dhcp" > CPE DHCP (cpe dhcp)< / option >
< option value = "cpe_ipv6" > CPE IPv6 (cpe ipv6)< / option >
< option value = "bonding" > 綁定摘要 (bonding)< / option >
< option value = "bonding_ds" > 下行綁定 (bonding downstream)< / option >
< option value = "bonding_us" > 上行綁定 (bonding upstream)< / option >
< option value = "phy" > 實體層狀態 (phy)< / option >
< option value = "verbose" > 詳細資訊 (verbose)< / option >
< option value = "ofdm_profile" > OFDM Profile (ofdm-profile)< / option >
< option value = "ofdma_profile" > OFDMA Profile (ofdma-profile)< / option >
< option value = "dhcp_verbose" > DHCP 詳細資訊 (dhcp verbose)< / option >
< option value = "service_flow" > Service Flow (service-flow)< / option >
< option value = "service_flow_verbose" > Service Flow 詳細 (service-flow verbose)< / option >
< option value = "qos" > QoS 資訊 (qos)< / option >
< option value = "uptime" > 運行時間 (uptime)< / option >
< option value = "ugs" > UGS 資訊 (ugs)< / option >
< option value = "cm_status" > CM 狀態 (cm-status)< / option >
< / optgroup >
< optgroup label = "全域狀態查詢 (不分特定目標)" >
< option value = "partial_mode" > Partial Mode (partial-mode)< / option >
< option value = "hop" > Cable Hop (show cable hop)< / option >
< option value = "flap_list" > Flap List (show cable flap-list)< / option >
< option value = "flap_sum" > Flap Summary (show cable flap-sum)< / option >
< / optgroup >
< / select >
< / div >
< / div >
< div class = "form-actions" >
< button onclick = "executeQuery('Cm')" > 執行查詢< / button >
< div style = "display: flex; align-items: center;" >
< input type = "checkbox" id = "debugQueryCm" style = "width: 18px; height: 18px; margin: 0; cursor: pointer;" >
< label for = "debugQueryCm" style = "cursor: pointer; color: #7f8c8d; margin-left: 8px; font-size: 14px;" > 🐞 顯示底層指令 (Debug)< / label >
< / div >
< / div >
< / div >
<!-- 表單 2: RPD 狀態綜合查詢 -->
< div id = "form-rpd-query" class = "task-form" >
< h3 style = "margin-top: 0; font-size: 18px; color: #e67e22; border-bottom: 2px solid #ecf0f1; padding-bottom: 10px; margin-bottom: 20px;" > RPD 狀態綜合查詢 (show cable rpd...)< / h3 >
< div class = "form-grid" >
< div class = "form-row" >
< label > 目標設備 (RPD VC:VS)< / label >
< input type = "text" id = "queryTargetRpd" placeholder = "例: 13:0 (留白則查詢全體)" >
< / div >
< div class = "form-row" >
< label > 查詢動作 (Action)< / label >
< select id = "queryTypeRpd" onchange = "toggleQueryInputs('Rpd')" >
< option value = "rpd_base" > 基本狀態 (show cable rpd)< / option >
< option value = "rpd_verbose" > 詳細資訊 (verbose)< / option >
< option value = "rpd_ptp_time" > PTP Time Property (ptp time-property)< / option >
< option value = "rpd_ptp_verbose" > PTP 詳細資訊 (ptp verbose)< / option >
< option value = "rpd_counters_map" > Counters Map (counters map)< / option >
< option value = "rpd_capabilities" > 能力資訊 (capabilities)< / option >
< option value = "rpd_video_counters" > Video Counters (video-channel counters)< / option >
< option value = "rpd_env_temp" > 環境溫度 (environment temperature)< / option >
< option value = "rpd_env_volt" > 環境電壓 (environment voltage)< / option >
< option value = "rpd_session" > Session (session)< / option >
< option value = "rpd_reset_history" > 重啟歷史 (reset-history)< / option >
< option value = "rpd_port_transceiver" > 光模組資訊 (port-transceiver)< / option >
< / select >
< / div >
< / div >
< div class = "form-actions" >
< button onclick = "executeQuery('Rpd')" style = "background-color: #e67e22;" > 執行查詢< / button >
< div style = "display: flex; align-items: center;" >
< input type = "checkbox" id = "debugQueryRpd" style = "width: 18px; height: 18px; margin: 0; cursor: pointer;" >
< label for = "debugQueryRpd" style = "cursor: pointer; color: #7f8c8d; margin-left: 8px; font-size: 14px;" > 🐞 顯示底層指令 (Debug)< / label >
< / div >
< / div >
< / div >
< / div > <!-- 💡 補上這個:關閉 query - tab 裡的 manager - container -->
< / div > <!-- 💡 補上這個:關閉 query - tab 本身 -->
<!-- Tab 3: CMTS 設備配置 -->
< div id = "config-tab" class = "tab-content" style = "overflow-y: auto; background-color: #fdfefe;" >
< div class = "manager-container" >
< div class = "control-group" style = "background: #ffffff; padding: 15px 25px; border-radius: 8px; margin-bottom: 0; box-shadow: 0 2px 4px rgba(0,0,0,0.02); border: 1px solid #e2e8f0;" >
< label style = "font-weight: bold; color: #c0392b; font-size: 16px; margin-right: 10px;" > 🛠️ 選擇配置任務:< / label >
<!-- 💡 移除了 onchange, 改由右側按鈕手動觸發 -->
< select id = "configTask" style = "width: 400px; max-width: 100%; font-weight: bold; font-size: 15px; padding: 8px; background-color: #fcf3f2; border-color: #fadbd8;" >
< option value = "form-bonding-config" > ⚠️ MAC Domain 狀態感知配置精靈< / option >
<!-- 未來可以在這裡新增 modulation - profile, rpd 等選項 -->
< / select >
<!-- 💡 新增的手動觸發按鈕 -->
2026-04-30 02:36:02 +00:00
< button id = "btn-load-task" onclick = "startConfigTask()" style = "background-color: #95a5a6; color: white; margin-left: 10px; cursor: not-allowed;" disabled > 🚀 載入任務< / button >
2026-04-29 10:00:40 +00:00
< / div >
<!-- 💡 表單 3: MAC Domain 配置精靈 -->
< div id = "form-bonding-config" class = "task-form" >
< h3 style = "margin-top: 0; font-size: 18px; color: #c0392b; border-bottom: 2px solid #ecf0f1; padding-bottom: 10px; margin-bottom: 20px;" > ⚠️ MAC Domain 狀態感知配置精靈< / h3 >
< div class = "control-group" style = "background: #fdf2e9; padding: 15px; border-radius: 6px; border: 1px solid #fadbd8;" >
< label style = "font-weight: bold; color: #d35400;" > 1. 目標 MAC Domain: < / label >
< select id = "cfgMacDomain" style = "width: 150px; padding: 6px; font-weight: bold; border: 1px solid #fadbd8; border-radius: 4px; background-color: #fff;" >
< option value = "" > 請先點擊上方載入任務...< / option >
< / select >
< button onclick = "fetchMacDomainConfig()" style = "background-color: #d35400;" > 🔍 讀取現有配置< / button >
< span id = "fetchStatus" style = "margin-left: 10px; font-size: 14px; color: #7f8c8d;" > 請先讀取設備狀態...< / span >
< / div >
< div id = "macDomainConfigArea" style = "display: none; margin-top: 20px;" >
<!-- Common Settings -->
< h4 style = "color: #2980b9; border-left: 4px solid #2980b9; padding-left: 8px;" > Common Settings< / h4 >
< div class = "form-grid" >
< div class = "form-row" > < label > IP Provisioning Mode< / label > < select id = "g_ip_prov" > < option value = "alternate" > alternate< / option > < option value = "dual-stack" > dual-stack< / option > < option value = "ipv4-only" > ipv4-only< / option > < option value = "ipv6-only" > ipv6-only< / option > < / select > < / div >
< div class = "form-row" > < label > Diplexer Band Edge Control< / label > < select id = "g_diplexer" > < option value = "enabled" > enabled< / option > < option value = "disabled" > disabled< / option > < / select > < / div >
< div class = "form-row" > < label > CM Battery Mode 3.1< / label > < select id = "g_bat31" > < option value = "enabled" > enabled< / option > < option value = "disabled" > disabled< / option > < / select > < / div >
< div class = "form-row" > < label > CM Battery Mode 3.0< / label > < select id = "g_bat30" > < option value = "enabled" > enabled< / option > < option value = "disabled" > disabled< / option > < / select > < / div >
< div class = "form-row" > < label > DOCSIS 4.0< / label > < select id = "g_docsis40" > < option value = "enabled" > enabled< / option > < option value = "disabled" > disabled< / option > < / select > < / div >
< div class = "form-row" > < label > DS Dynamic Bonding Group< / label > < select id = "g_ds_dyn" onchange = "toggleGroupVisibility()" > < option value = "enabled" > enabled< / option > < option value = "disabled" > disabled< / option > < / select > < / div >
< div class = "form-row" > < label > US Dynamic Bonding Group< / label > < select id = "g_us_dyn" onchange = "toggleGroupVisibility()" > < option value = "enabled" > enabled< / option > < option value = "disabled" > disabled< / option > < / select > < / div >
< / div >
<!-- [Basic] DS/US Channel Sets -->
< h4 style = "color: #27ae60; border-left: 4px solid #27ae60; padding-left: 8px; margin-top: 30px;" > [Basic] DS/US Channel Sets< / h4 >
< div class = "form-grid" >
< div class = "form-row" > < label > Admin State< / label > < select id = "b_admin" > < option value = "up" > up< / option > < option value = "down" > down< / option > < / select > < / div >
< div class = "form-row" > < label > DS Primary Set (0..157)< / label > < input type = "text" id = "b_ds_pri" placeholder = "例: 0-2" > < / div >
< div class = "form-row" > < label > DS Non-Primary Set (0..157)< / label > < input type = "text" id = "b_ds_non_pri" placeholder = "例: 3-4" > < / div >
< div class = "form-row" > < label > US PHY Channel Set (0..255)< / label > < input type = "text" id = "b_us_phy" placeholder = "例: 0-3" > < / div >
< div class = "form-row" > < label > DS OFDM Set (0..7)< / label > < input type = "text" id = "b_ds_ofdm" placeholder = "例: 0" > < / div >
< div class = "form-row" > < label > US OFDMA Set (0..1)< / label > < input type = "text" id = "b_us_ofdma" placeholder = "例: 0" > < / div >
< / div >
<!-- [Static] Downstream Bonding Groups -->
< div id = "section_group_ds" style = "margin-top: 30px;" >
< h4 style = "color: #8e44ad; border-left: 4px solid #8e44ad; padding-left: 8px;" > [Static] Downstream Bonding Groups< / h4 >
< div class = "control-group" style = "background: #f4f6f7; padding: 10px; border-radius: 4px;" >
< label > 選擇要編輯的 DS Group: < / label >
< select id = "select_ds_group" onchange = "loadDsGroupData()" style = "width: 200px;" > < / select >
< input type = "text" id = "input_new_ds_group" placeholder = "輸入新 Group 名稱 (例: D4A)" style = "display: none; width: 200px;" >
< / div >
< div class = "form-grid" >
< div class = "form-row" > < label > Admin State< / label > < select id = "ds_g_admin" > < option value = "up" > up< / option > < option value = "down" > down< / option > < / select > < / div >
< div class = "form-row" > < label > Down Channel Set (0..157)< / label > < input type = "text" id = "ds_g_down" placeholder = "例: 0-4" > < / div >
< div class = "form-row" > < label > OFDM Channel Set (0..7)< / label > < input type = "text" id = "ds_g_ofdm" placeholder = "例: 0-1" > < / div >
< div class = "form-row" > < label > FDX OFDM Channel Set (0..7)< / label > < input type = "text" id = "ds_g_fdx" placeholder = "例: 0-2" > < / div >
< / div >
< / div >
<!-- [Static] Upstream Bonding Groups -->
< div id = "section_group_us" style = "margin-top: 30px;" >
< h4 style = "color: #f39c12; border-left: 4px solid #f39c12; padding-left: 8px;" > [Static] Upstream Bonding Groups< / h4 >
< div class = "control-group" style = "background: #f4f6f7; padding: 10px; border-radius: 4px;" >
< label > 選擇要編輯的 US Group: < / label >
< select id = "select_us_group" onchange = "loadUsGroupData()" style = "width: 200px;" > < / select >
< input type = "text" id = "input_new_us_group" placeholder = "輸入新 Group 名稱 (例: U4A)" style = "display: none; width: 200px;" >
< / div >
< div class = "form-grid" >
< div class = "form-row" > < label > Admin State< / label > < select id = "us_g_admin" > < option value = "up" > up< / option > < option value = "down" > down< / option > < / select > < / div >
< div class = "form-row" > < label > US Channel Set< / label > < input type = "text" id = "us_g_us" placeholder = "例: 0-3.0" > < / div >
< div class = "form-row" > < label > OFDMA Channel Set (0..1)< / label > < input type = "text" id = "us_g_ofdma" placeholder = "例: 0" > < / div >
< div class = "form-row" > < label > FDX OFDMA Channel Set (0..5)< / label > < input type = "text" id = "us_g_fdx" placeholder = "例: 0-5" > < / div >
< / div >
< / div >
<!-- CLI 預覽區塊 -->
< div id = "cliPreviewContainer" style = "display: none; background: #2c3e50; color: #ecf0f1; padding: 15px; border-radius: 6px; margin-top: 30px; margin-bottom: 20px; font-family: monospace; white-space: pre-wrap;" > < / div >
< div class = "form-actions" >
<!-- 💡 新增的復原按鈕 (使用灰色系,避免與主要動作搶視覺焦點) -->
< button id = "btnRevert" onclick = "revertFormChanges()" style = "background-color: #7f8c8d; color: white; margin-right: 15px;" >
🔄 復原重填
< / button >
< button onclick = "generateMacDomainCLI()" style = "background-color: #f39c12; color: white;" > ⚙️ 產生絕對路徑指令預覽< / button >
< button id = "btnDeployConfig" onclick = "executeBondingConfig()" style = "background-color: #c0392b; color: white; display: none;" disabled > 🚀 正式套用設定< / button >
< / div >
< / div >
< / div >
< / div >
< / div >
<!-- 獨立的彈出式輸出視窗 (Modal) -->
< div id = "outputModal" class = "modal-overlay" onclick = "closeModal(event)" >
< div class = "modal-container" onclick = "event.stopPropagation()" >
< div class = "modal-header" >
< div class = "modal-title" >
< span > 📄 執行結果< / span >
< span id = "modalTargetInfo" style = "font-size: 13px; color: #bdc3c7; font-weight: normal;" > < / span >
< / div >
< button class = "modal-close" onclick = "closeModal()" > × < / button >
< / div >
< div class = "modal-body" >
< pre id = "modalOutput" class = "readonly-terminal" > 等待執行中...< / pre >
< / div >
< / div >
< / div >
<!-- 引入我們剛剛獨立出來的 JavaScript 邏輯 -->
< script src = "/static/app.js" > < / script >
< / body >
< / html >