scm-harmonic-cmts-admin/static/mac-domain.js

280 lines
14 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// --- static/mac-domain.js ---
import { apiGetMacDomainList, apiGetMacDomainConfig, apiExecuteConfig } from './api.js';
import { getGlobalConnectionInfo } from './utils.js';
// 🌟 將原本在 app.js 的全域變數移到這裡封裝
let currentMacDomainData = null;
export function hasMacDomainData() {
return currentMacDomainData !== null;
}
export function resetMacDomainData() {
currentMacDomainData = null;
}
export async function loadMacDomainList() {
const connInfo = getGlobalConnectionInfo();
if (!connInfo) return;
const mdSelect = document.getElementById('cfgMacDomain');
const statusSpan = document.getElementById('fetchStatus');
mdSelect.innerHTML = '<option value="">⏳ 查詢設備中...</option>';
statusSpan.textContent = "正在自動抓取現有 MAC Domain 清單...";
statusSpan.style.color = "#f39c12";
try {
const result = await apiGetMacDomainList(connInfo.host, connInfo.user, connInfo.pass);
if (result.status === 'success' && result.data.length > 0) {
mdSelect.innerHTML = '';
result.data.forEach(md => {
const option = document.createElement('option');
option.value = md;
option.textContent = md;
mdSelect.appendChild(option);
});
statusSpan.textContent = "✅ 清單抓取成功!請選擇目標並點擊讀取配置。";
statusSpan.style.color = "#27ae60";
} else {
mdSelect.innerHTML = '<option value="">❌ 找不到資料</option>';
statusSpan.textContent = "無法解析清單,請確認設備狀態。";
statusSpan.style.color = "#e74c3c";
}
} catch (error) {
mdSelect.innerHTML = '<option value="">❌ 連線錯誤</option>';
statusSpan.textContent = "連線失敗:" + error;
statusSpan.style.color = "#e74c3c";
}
}
export async function fetchMacDomainConfig() {
const target = document.getElementById('cfgMacDomain').value.trim();
const connInfo = getGlobalConnectionInfo();
if (!connInfo || !target) return alert("請確認設備連線資訊與 MAC Domain");
document.getElementById('fetchStatus').textContent = "⏳ 正在讀取並解析設定中...";
document.getElementById('fetchStatus').style.color = "#f39c12";
try {
const result = await apiGetMacDomainConfig(target, connInfo.host, connInfo.user, connInfo.pass);
if (result.status === 'success') {
currentMacDomainData = result.data;
populateFormFromData();
document.getElementById('macDomainConfigArea').style.display = 'block';
document.getElementById('fetchStatus').textContent = "✅ 讀取成功!";
document.getElementById('fetchStatus').style.color = "#27ae60";
} else {
alert("讀取失敗:" + result.detail);
document.getElementById('fetchStatus').textContent = "❌ 讀取失敗";
}
} catch (error) {
alert("連線錯誤:" + error);
}
}
export function populateFormFromData() {
const d = currentMacDomainData;
if (!d) return;
document.getElementById('g_ip_prov').value = d.common_settings['ip-provisioning-mode'] || 'dual-stack';
document.getElementById('g_diplexer').value = d.common_settings['diplexer-band-edge'] || 'enabled';
document.getElementById('g_bat31').value = d.common_settings['cm-battery-mode-31-support'] || 'disabled';
document.getElementById('g_bat30').value = d.common_settings['cm-battery-mode-30-support'] || 'disabled';
document.getElementById('g_docsis40').value = d.common_settings['docsis40'] || 'disabled';
document.getElementById('g_ds_dyn').value = d.common_settings['ds-dynamic-bonding-group'] || 'disabled';
document.getElementById('g_us_dyn').value = d.common_settings['us-dynamic-bonding-group'] || 'disabled';
document.getElementById('b_admin').value = d.basic_channel_sets['admin-state'] || 'down';
document.getElementById('b_ds_pri').value = d.basic_channel_sets['ds-primary-set'] || '';
document.getElementById('b_ds_non_pri').value = d.basic_channel_sets['ds-non-primary-set'] || '';
document.getElementById('b_us_phy').value = d.basic_channel_sets['us-phy-channel-set'] || '';
document.getElementById('b_ds_ofdm').value = d.basic_channel_sets['ds-ofdm-set'] || '';
document.getElementById('b_us_ofdma').value = d.basic_channel_sets['us-ofdma-set'] || '';
const dsSelect = document.getElementById('select_ds_group');
dsSelect.innerHTML = '<option value="_new_">[ 新增 DS Group]</option>';
Object.keys(d.static_ds_bonding_groups).forEach(grp => dsSelect.innerHTML += `<option value="${grp}">${grp}</option>`);
if (Object.keys(d.static_ds_bonding_groups).length > 0) dsSelect.value = Object.keys(d.static_ds_bonding_groups)[0];
const usSelect = document.getElementById('select_us_group');
usSelect.innerHTML = '<option value="_new_">[ 新增 US Group]</option>';
Object.keys(d.static_us_bonding_groups).forEach(grp => usSelect.innerHTML += `<option value="${grp}">${grp}</option>`);
if (Object.keys(d.static_us_bonding_groups).length > 0) usSelect.value = Object.keys(d.static_us_bonding_groups)[0];
toggleGroupVisibility();
loadDsGroupData();
loadUsGroupData();
}
export function revertFormChanges() {
if (!currentMacDomainData) return;
if (!confirm("確定要放棄目前的修改,還原回設備原始的設定值嗎?")) return;
populateFormFromData();
const previewEl = document.getElementById('cliPreviewContainer');
if (previewEl) {
previewEl.textContent = '';
previewEl.style.display = 'none';
}
const deployBtn = document.getElementById('btnDeployConfig');
if (deployBtn) {
deployBtn.style.display = 'none';
deployBtn.disabled = true;
}
const fetchStatus = document.getElementById('fetchStatus');
fetchStatus.textContent = "🔄 已還原為原始設定!";
fetchStatus.style.color = "#2980b9";
setTimeout(() => {
fetchStatus.textContent = "✅ 讀取成功!";
fetchStatus.style.color = "#27ae60";
}, 3000);
}
export function toggleGroupVisibility() {
const dsDyn = document.getElementById('g_ds_dyn').value;
const usDyn = document.getElementById('g_us_dyn').value;
document.getElementById('section_group_ds').style.display = (dsDyn === 'disabled') ? 'block' : 'none';
document.getElementById('section_group_us').style.display = (usDyn === 'disabled') ? 'block' : 'none';
}
export function loadDsGroupData() {
const grp = document.getElementById('select_ds_group').value;
const newGrpInput = document.getElementById('input_new_ds_group');
if (grp === '_new_') {
newGrpInput.style.display = 'inline-block';
document.getElementById('ds_g_admin').value = 'down';
document.getElementById('ds_g_down').value = '';
document.getElementById('ds_g_ofdm').value = '';
document.getElementById('ds_g_fdx').value = '';
} else {
newGrpInput.style.display = 'none';
const data = currentMacDomainData.static_ds_bonding_groups[grp];
document.getElementById('ds_g_admin').value = data['admin-state'] || 'down';
document.getElementById('ds_g_down').value = data['down-channel-set'] || '';
document.getElementById('ds_g_ofdm').value = data['ofdm-channel-set'] || '';
document.getElementById('ds_g_fdx').value = data['fdx-ofdm-channel-set'] || '';
}
}
export function loadUsGroupData() {
const grp = document.getElementById('select_us_group').value;
const newGrpInput = document.getElementById('input_new_us_group');
if (grp === '_new_') {
newGrpInput.style.display = 'inline-block';
document.getElementById('us_g_admin').value = 'down';
document.getElementById('us_g_us').value = '';
document.getElementById('us_g_ofdma').value = '';
document.getElementById('us_g_fdx').value = '';
} else {
newGrpInput.style.display = 'none';
const data = currentMacDomainData.static_us_bonding_groups[grp];
document.getElementById('us_g_admin').value = data['admin-state'] || 'down';
document.getElementById('us_g_us').value = data['us-channel-set'] || '';
document.getElementById('us_g_ofdma').value = data['ofdma-channel-set'] || '';
document.getElementById('us_g_fdx').value = data['fdx-ofdma-channel-set'] || '';
}
}
export function generateMacDomainCLI() {
const md = document.getElementById('cfgMacDomain').value.trim();
let cli = `! --- Harmonic MAC Domain Configuration SOP ---\n`;
cli += `! 1. [區塊] MAC Domain 全域與 Base 設定\n`;
cli += `cable mac-domain ${md} admin-state down\ncommit\n`;
const baseCmds = [
`ip-provisioning-mode ${document.getElementById('g_ip_prov').value}`,
`diplexer-band-edge control ${document.getElementById('g_diplexer').value}`,
`cm-battery-mode-31-support ${document.getElementById('g_bat31').value}`,
`cm-battery-mode-30-support ${document.getElementById('g_bat30').value}`,
`docsis40 ${document.getElementById('g_docsis40').value}`,
`ds-dynamic-bonding-group ${document.getElementById('g_ds_dyn').value}`,
`us-dynamic-bonding-group ${document.getElementById('g_us_dyn').value}`,
`ds-primary-set ${document.getElementById('b_ds_pri').value}`,
`ds-non-primary-set ${document.getElementById('b_ds_non_pri').value}`,
`us-phy-channel-set ${document.getElementById('b_us_phy').value}`,
`ds-ofdm-set ${document.getElementById('b_ds_ofdm').value}`,
`us-ofdma-set ${document.getElementById('b_us_ofdma').value}`
];
baseCmds.forEach(cmd => {
if (!cmd.endsWith(" ")) cli += `cable mac-domain ${md} ${cmd}\n`;
});
cli += `cable mac-domain ${md} admin-state ${document.getElementById('b_admin').value}\ncommit\n`;
if (document.getElementById('g_ds_dyn').value === 'disabled') {
const isNewDs = document.getElementById('select_ds_group').value === '_new_';
let dsName = isNewDs ? document.getElementById('input_new_ds_group').value.trim() : document.getElementById('select_ds_group').value;
if (dsName) {
cli += `\n! 2. [區塊] DS Bonding Group [${dsName}] 設定\n`;
if (!isNewDs) cli += `cable mac-domain ${md} ds-bonding-group ${dsName} admin-state down\ncommit\n`;
if (document.getElementById('ds_g_down').value) cli += `cable mac-domain ${md} ds-bonding-group ${dsName} down-channel-set ${document.getElementById('ds_g_down').value}\n`;
if (document.getElementById('ds_g_ofdm').value) cli += `cable mac-domain ${md} ds-bonding-group ${dsName} ofdm-channel-set ${document.getElementById('ds_g_ofdm').value}\n`;
if (document.getElementById('ds_g_fdx').value) cli += `cable mac-domain ${md} ds-bonding-group ${dsName} fdx-ofdm-channel-set ${document.getElementById('ds_g_fdx').value}\n`;
cli += `cable mac-domain ${md} ds-bonding-group ${dsName} admin-state ${document.getElementById('ds_g_admin').value}\ncommit\n`;
}
}
if (document.getElementById('g_us_dyn').value === 'disabled') {
const isNewUs = document.getElementById('select_us_group').value === '_new_';
let usName = isNewUs ? document.getElementById('input_new_us_group').value.trim() : document.getElementById('select_us_group').value;
if (usName) {
cli += `\n! 3. [區塊] US Bonding Group [${usName}] 設定\n`;
if (!isNewUs) cli += `cable mac-domain ${md} us-bonding-group ${usName} admin-state down\ncommit\n`;
if (document.getElementById('us_g_us').value) cli += `cable mac-domain ${md} us-bonding-group ${usName} us-channel-set ${document.getElementById('us_g_us').value}\n`;
if (document.getElementById('us_g_ofdma').value) cli += `cable mac-domain ${md} us-bonding-group ${usName} ofdma-channel-set ${document.getElementById('us_g_ofdma').value}\n`;
if (document.getElementById('us_g_fdx').value) cli += `cable mac-domain ${md} us-bonding-group ${usName} fdx-ofdma-channel-set ${document.getElementById('us_g_fdx').value}\n`;
cli += `cable mac-domain ${md} us-bonding-group ${usName} admin-state ${document.getElementById('us_g_admin').value}\ncommit\n`;
}
}
const previewEl = document.getElementById('cliPreviewContainer');
previewEl.textContent = cli;
previewEl.style.display = 'block';
const deployBtn = document.getElementById('btnDeployConfig');
deployBtn.style.display = 'inline-block';
deployBtn.disabled = false;
}
export async function executeBondingConfig() {
if (!confirm("⚠️ 警告:此操作將導致 MAC Domain 重新啟動,影響用戶服務。確定要執行嗎?")) return;
const cliScript = document.getElementById('cliPreviewContainer').textContent;
const connInfo = getGlobalConnectionInfo();
if (!connInfo) return;
// 開啟 Modal 顯示執行進度
document.getElementById('outputModal').classList.add('active');
document.getElementById('modalTargetInfo').textContent = connInfo.host ? `(${connInfo.host})` : '';
document.body.style.overflow = 'hidden';
const outputEl = document.getElementById('modalOutput');
outputEl.innerHTML = `<span style="color: #f39c12;">🚀 正在排隊並執行配置腳本,這可能需要幾秒鐘,請勿關閉視窗...</span>\n\n${cliScript}`;
try {
const result = await apiExecuteConfig(cliScript, connInfo.host, connInfo.user, connInfo.pass);
if (result.status === 'success') {
outputEl.style.color = "#e0e0e0";
outputEl.textContent = `✅ 設定執行完成!\n==================================================\n${result.data}`;
} else {
outputEl.style.color = "#e74c3c";
outputEl.textContent = `❌ 設定執行失敗:\n${result.message}`;
}
} catch (error) {
outputEl.style.color = "#e74c3c";
outputEl.textContent = `❌ 連線或伺服器錯誤: ${error}`;
}
}