|
|
|
@ -55,6 +55,7 @@ |
|
|
|
|
|
|
|
<div id="ssid-list"></div> |
|
|
|
<button id="add-ssid" class="icon-button" title="add SSID">➕</button> |
|
|
|
<button id="delete-ssid" class="icon-button" title="delete SSID">➖</button> |
|
|
|
</div> |
|
|
|
<div class="actions"> |
|
|
|
<div class="file-upload-wrapper-device" |
|
|
|
@ -772,13 +773,6 @@ |
|
|
|
const selectedDeviceFile = event.target.files[0]; |
|
|
|
const DeviceFileName = selectedDeviceFile.name; |
|
|
|
|
|
|
|
// 파일명 검증 (data-expected-filename 사용) |
|
|
|
if (DeviceFileName !== expectedDeviceFileName){ |
|
|
|
alert(`Invalid file.'${expectedDeviceFileName}' Please select a file. Current file: ${DeviceFileName} `); |
|
|
|
uploadDeviceFileInput.value = ''; // 잘못된 파일 선택 시 input 초기화 |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
const reader = new FileReader(); |
|
|
|
|
|
|
|
reader.onload = async (e) => { |
|
|
|
@ -885,13 +879,6 @@ |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// 파일명 검증 (data-expected-filename 사용) |
|
|
|
if (fileName !== expectedFileName){ |
|
|
|
alert(`Invalid file. '${expectedFileName}' Please select a file. Current file: ${fileName} `); |
|
|
|
uploadFileInput.value = ''; // 잘못된 파일 선택 시 input 초기화 |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
reader.onload = async (e) => { |
|
|
|
try { |
|
|
|
const fileContent = e.target.result; |
|
|
|
@ -1041,6 +1028,20 @@ |
|
|
|
const expr = document.getElementById('modbus_expr_input').value; |
|
|
|
const mask = document.getElementById('modbus_mask_input').value; |
|
|
|
|
|
|
|
const firstRow = modbusFieldList.querySelector('tr'); |
|
|
|
|
|
|
|
// 첫 행이 비어있다면 그 자리에 값을 넣기 |
|
|
|
if (firstRow && firstRow.querySelector('.field-display').textContent.trim() === '') { |
|
|
|
firstRow.querySelector('.field-display').textContent = field; |
|
|
|
firstRow.querySelector('.addr-display').textContent = addr; |
|
|
|
firstRow.querySelector('.idt-display').textContent = idt; |
|
|
|
firstRow.querySelector('.odt-display').textContent = odt; |
|
|
|
firstRow.querySelector('.dv-display').textContent = defaultValue; |
|
|
|
firstRow.querySelector('.shift-display').textContent = shift; |
|
|
|
firstRow.querySelector('.expr-display').textContent = expr; |
|
|
|
firstRow.querySelector('.mask-display').textContent = mask; |
|
|
|
} else { |
|
|
|
// 새로운 행을 추가 |
|
|
|
const newRow = modbusRowTemplate.content.cloneNode(true); |
|
|
|
newRow.querySelector('.field-display').textContent = field; |
|
|
|
newRow.querySelector('.addr-display').textContent = addr; |
|
|
|
@ -1052,7 +1053,9 @@ |
|
|
|
newRow.querySelector('.mask-display').textContent = mask; |
|
|
|
|
|
|
|
modbusFieldList.appendChild(newRow); |
|
|
|
} |
|
|
|
|
|
|
|
// 입력 필드 초기화 |
|
|
|
document.getElementById('modbus_field_input').value = ''; |
|
|
|
document.getElementById('modbus_addr_input').value = ''; |
|
|
|
document.getElementById('modbus_idt_input').value = ''; |
|
|
|
@ -1095,6 +1098,20 @@ |
|
|
|
const expr = document.getElementById('opcua_expr_input').value; |
|
|
|
const mask = document.getElementById('opcua_mask_input').value; |
|
|
|
|
|
|
|
const firstRow = opcUaFieldList.querySelector('tr'); |
|
|
|
|
|
|
|
// 첫 행이 비어있다면 그 자리에 값을 넣기 |
|
|
|
if (firstRow && firstRow.querySelector('.opcua-field-display').textContent.trim() === '') { |
|
|
|
firstRow.querySelector('.opcua-field-display').textContent = field; |
|
|
|
firstRow.querySelector('.opcua-addr-display').textContent = addr; |
|
|
|
firstRow.querySelector('.opcua-ns-display').textContent = ns; |
|
|
|
firstRow.querySelector('.opcua-odt-display').textContent = odt; |
|
|
|
firstRow.querySelector('.opcua-dv-display').textContent = defaultValue; |
|
|
|
firstRow.querySelector('.opcua-shift-display').textContent = shift; |
|
|
|
firstRow.querySelector('.opcua-expr-display').textContent = expr; |
|
|
|
firstRow.querySelector('.opcua-mask-display').textContent = mask; |
|
|
|
} else { |
|
|
|
// 새로운 행을 추가 |
|
|
|
const newRow = opcUaRowTemplate.content.cloneNode(true); |
|
|
|
newRow.querySelector('.opcua-field-display').textContent = field; |
|
|
|
newRow.querySelector('.opcua-addr-display').textContent = addr; |
|
|
|
@ -1106,18 +1123,21 @@ |
|
|
|
newRow.querySelector('.opcua-mask-display').textContent = mask; |
|
|
|
|
|
|
|
opcUaFieldList.appendChild(newRow); |
|
|
|
} |
|
|
|
|
|
|
|
document.getElementById('opcua_field_input').value = ''; |
|
|
|
document.getElementById('opcua_addr_input').value = ''; |
|
|
|
document.getElementById('opcua_ns_input').value = ''; |
|
|
|
document.getElementById('opcua_odt_input').value = ''; |
|
|
|
document.getElementById('opcua_dv_input').value = ''; |
|
|
|
document.getElementById('opcua_shift_input').value = ''; |
|
|
|
document.getElementById('opcua_expr_input').value = ''; |
|
|
|
document.getElementById('opcua_mask_input').value = ''; |
|
|
|
// 입력 필드 초기화 |
|
|
|
document.getElementById('modbus_field_input').value = ''; |
|
|
|
document.getElementById('modbus_addr_input').value = ''; |
|
|
|
document.getElementById('modbus_idt_input').value = ''; |
|
|
|
document.getElementById('modbus_odt_input').value = ''; |
|
|
|
document.getElementById('modbus_dv_input').value = ''; |
|
|
|
document.getElementById('modbus_shift_input').value = ''; |
|
|
|
document.getElementById('modbus_expr_input').value = ''; |
|
|
|
document.getElementById('modbus_mask_input').value = ''; |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
document.getElementById('opcua_modify_btn').onclick = function () { |
|
|
|
if (!selectedRow) return alert('Please select the row you want to modify'); |
|
|
|
selectedRow.querySelector('.opcua-field-display').textContent = document.getElementById('opcua_field_input').value; |
|
|
|
@ -1437,6 +1457,65 @@ |
|
|
|
URL.revokeObjectURL(url); |
|
|
|
} |
|
|
|
/*-----------------------------------------------------*/ |
|
|
|
// localStorage 자동 저장 (Device) |
|
|
|
function autoSaveToLocal() { |
|
|
|
const data = collectDeviceData(); |
|
|
|
localStorage.setItem('deviceConfigAutoSave', JSON.stringify(data)); |
|
|
|
} |
|
|
|
|
|
|
|
// localStorage 자동 저장 (Protocol) |
|
|
|
function autoSaveProtocolToLocal() { |
|
|
|
const config = collectProtocolData(); |
|
|
|
localStorage.setItem('protocolConfigAutoSave', JSON.stringify(config)); |
|
|
|
} |
|
|
|
|
|
|
|
// localStorage에서 불러오기 |
|
|
|
function loadFromLocalIfExists() { |
|
|
|
const saved = localStorage.getItem('deviceConfigAutoSave'); |
|
|
|
if (saved) { |
|
|
|
try { |
|
|
|
loadFromData(JSON.parse(saved)); |
|
|
|
console.log('localStorage에서 자동 저장된 Device 설정을 불러왔습니다.'); |
|
|
|
return true; |
|
|
|
} catch (e) { |
|
|
|
console.warn('localStorage Device 설정 파싱 실패:', e); |
|
|
|
} |
|
|
|
} |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
// localStorage에서 불러오기 (Protocol) |
|
|
|
function loadProtocolFromLocalIfExists() { |
|
|
|
const saved = localStorage.getItem('protocolConfigAutoSave'); |
|
|
|
if (saved) { |
|
|
|
try { |
|
|
|
loadFromRegisterJson(JSON.parse(saved)); |
|
|
|
console.log('localStorage에서 자동 저장된 Protocol 설정을 불러왔습니다.'); |
|
|
|
return true; |
|
|
|
} catch (e) { |
|
|
|
console.warn('localStorage Protocol 설정 파싱 실패:', e); |
|
|
|
} |
|
|
|
} |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
// input, select 등 값이 바뀔 때마다 자동 저장 (Device) |
|
|
|
function bindAutoSaveEvents() { |
|
|
|
document.querySelectorAll('input, select').forEach(el => { |
|
|
|
el.addEventListener('change', autoSaveToLocal); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
// input, select 등 값이 바뀔 때마다 자동 저장 (Protocol) |
|
|
|
function bindAutoSaveProtocolEvents() { |
|
|
|
// reg, modbus, opcua, can 페이지 내의 input/select만 |
|
|
|
const protocolSections = ['#page-reg', '#page-modbus', '#page-opcua', '#page-can']; |
|
|
|
protocolSections.forEach(section => { |
|
|
|
document.querySelectorAll(section + ' input, ' + section + ' select').forEach(el => { |
|
|
|
el.addEventListener('change', autoSaveProtocolToLocal); |
|
|
|
}); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
/*-----protocol에 설정 데이터를 protocolConfig.json 파일로 변경하여 유저가 다운로드 할수 있게 하는 함수-----*/ |
|
|
|
function downloadProtocolJson(obj, filename='protocolConfig.json') { |
|
|
|
@ -1456,30 +1535,85 @@ |
|
|
|
|
|
|
|
/*-------페이지 로드시 서버에 있는 데이터를 불러오는 함수---------*/ |
|
|
|
async function loadInitialData() { |
|
|
|
// 1. localStorage 우선 적용 (Device) |
|
|
|
let deviceLoadedFromLocal = loadFromLocalIfExists(); |
|
|
|
// 2. 서버에서 파일 목록 조회 및 로드 (Device) |
|
|
|
if (!deviceLoadedFromLocal) { |
|
|
|
try { |
|
|
|
// Device 설정 로드 |
|
|
|
// 사용 가능한 Device 파일 목록 조회 |
|
|
|
const deviceFilesResponse = await fetch('http://localhost:8080/setting/device-files'); |
|
|
|
if (deviceFilesResponse.ok) { |
|
|
|
const deviceFilesData = await deviceFilesResponse.json(); |
|
|
|
if (deviceFilesData && deviceFilesData.body && deviceFilesData.body.length > 0) { |
|
|
|
// 첫 번째 유효한 Device 파일 로드 |
|
|
|
const firstDeviceFile = deviceFilesData.body[0]; |
|
|
|
console.log(`Device 파일 발견: ${firstDeviceFile}`); |
|
|
|
|
|
|
|
const deviceResponse = await fetch(`http://localhost:8080/setting/get-device/${firstDeviceFile}`); |
|
|
|
if (deviceResponse.ok) { |
|
|
|
const deviceData = await deviceResponse.json(); |
|
|
|
if (deviceData && deviceData.body) { |
|
|
|
loadFromData(deviceData.body); |
|
|
|
console.log(`Device 설정 자동 로드 완료: ${firstDeviceFile}`); |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
// 기본 파일명으로 시도 |
|
|
|
const deviceResponse = await fetch('http://localhost:8080/setting/get-device'); |
|
|
|
if (deviceResponse.ok) { |
|
|
|
const deviceData = await deviceResponse.json(); |
|
|
|
if (deviceData && deviceData.body) { |
|
|
|
loadFromData(deviceData.body); |
|
|
|
console.log('Device 설정 자동 로드 완료 (기본 파일)'); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
alert('Device configuration file missing or loading failed'); |
|
|
|
console.log('Device 설정 파일이 없거나 로드 실패, 기본값 사용:', error.message); |
|
|
|
} |
|
|
|
} |
|
|
|
bindAutoSaveEvents(); |
|
|
|
|
|
|
|
// 1. localStorage 우선 적용 (Protocol) |
|
|
|
let protocolLoadedFromLocal = loadProtocolFromLocalIfExists(); |
|
|
|
// 2. 서버에서 파일 목록 조회 및 로드 (Protocol) |
|
|
|
if (!protocolLoadedFromLocal) { |
|
|
|
try { |
|
|
|
// Protocol 설정 로드 |
|
|
|
// 사용 가능한 Protocol 파일 목록 조회 |
|
|
|
const protocolFilesResponse = await fetch('http://localhost:8080/setting/protocol-files'); |
|
|
|
if (protocolFilesResponse.ok) { |
|
|
|
const protocolFilesData = await protocolFilesResponse.json(); |
|
|
|
if (protocolFilesData && protocolFilesData.body && protocolFilesData.body.length > 0) { |
|
|
|
// 첫 번째 유효한 Protocol 파일 로드 |
|
|
|
const firstProtocolFile = protocolFilesData.body[0]; |
|
|
|
console.log(`Protocol 파일 발견: ${firstProtocolFile}`); |
|
|
|
|
|
|
|
const protocolResponse = await fetch(`http://localhost:8080/setting/get-protocol/${firstProtocolFile}`); |
|
|
|
if (protocolResponse.ok) { |
|
|
|
const protocolData = await protocolResponse.json(); |
|
|
|
if (protocolData && protocolData.body) { |
|
|
|
loadFromRegisterJson(protocolData.body); |
|
|
|
console.log(`Protocol 설정 자동 로드 완료: ${firstProtocolFile}`); |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
// 기본 파일명으로 시도 |
|
|
|
const protocolResponse = await fetch('http://localhost:8080/setting/get-protocol'); |
|
|
|
if (protocolResponse.ok) { |
|
|
|
const protocolData = await protocolResponse.json(); |
|
|
|
if (protocolData && protocolData.body) { |
|
|
|
loadFromRegisterJson(protocolData.body); |
|
|
|
console.log('Protocol 설정 자동 로드 완료 (기본 파일)'); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
alert('Protocol configuration file missing or loading failed'); } |
|
|
|
console.log('Protocol 설정 파일이 없거나 로드 실패, 기본값 사용:', error.message); |
|
|
|
} |
|
|
|
} |
|
|
|
bindAutoSaveProtocolEvents(); |
|
|
|
} |
|
|
|
/*-----------------------------------------------------*/ |
|
|
|
|
|
|
|
|