Browse Source

modbus config

v2
gudae01 1 year ago
parent
commit
046050ede9
  1. 354
      src/main/resources/static/index.html

354
src/main/resources/static/index.html

@ -86,6 +86,8 @@
box-shadow: none; box-shadow: none;
padding: 24px; padding: 24px;
border-radius: 4px; border-radius: 4px;
display: flex;
flex-direction: column;
} }
#page-modbus table { #page-modbus table {
width: 100%; width: 100%;
@ -105,29 +107,32 @@
} }
#page-modbus .modbus-input-area { #page-modbus .modbus-input-area {
display: grid; display: grid;
grid-template-columns: 1fr 1fr; grid-template-columns: 200px 200px 200px 200px;
gap: 8px 32px; gap: 20px 20px;
margin: 24px 0 16px 0; margin: 24px auto 16px auto;
background: #eaeaea; background: #eaeaea;
padding: 16px 0; padding: 16px;
border-radius: 4px; border-radius: 4px;
margin-left: auto;
margin-right: auto;
} }
#page-modbus .input-row { #page-modbus .input-row {
display: flex; display: contents;
align-items: center; }
gap: 12px; #page-modbus .modbus-input-area label.nowrap {
margin-bottom: 8px; white-space: nowrap;
} }
#page-modbus .input-row label { #page-modbus .modbus-input-area label {
min-width: 80px; min-width: auto;
color: #444; color: #444;
white-space: normal;
} }
#page-modbus .input-row input { #page-modbus .modbus-input-area input {
background: #e0e0e0; background: #e0e0e0;
border: none; border: none;
border-radius: 2px; border-radius: 2px;
padding: 4px 8px; padding: 4px 8px;
min-width: 120px; min-width: auto;
} }
#page-modbus .modbus-actions { #page-modbus .modbus-actions {
display: flex; display: flex;
@ -163,6 +168,13 @@
min-width: 140px; min-width: 140px;
cursor: pointer; cursor: pointer;
} }
.selected-row{
background: #d0e6ff !important;
}
.selected-row > td {
background: #d0e6ff !important;
}
</style> </style>
</head> </head>
<body> <body>
@ -316,42 +328,42 @@
<option value="2500">250kb/s</option> <option value="2500">250kb/s</option>
<option value="5000">500kb/s</option> <option value="5000">500kb/s</option>
<option value="10000">1M/s</option> <option value="10000">1M/s</option>
</select> </select>
</div> </div>
<!-- IMU --> <!-- IMU -->
<div class="io-group"> <div class="io-group">
<h4>IMU Re-map</h4> <h4>IMU Re-map</h4>
<div class="io-row"><span class="label-inline">X</span><span class="colon">:</span> <div class="io-row"><span class="label-inline">X</span><span class="colon">:</span>
<select id="imu_remap_x"> <select id="imu_remap_x">
<option value="x">x</option>
<option value="y">y</option>
<option value="z">z</option>
<option value="-x">-x</option>
<option value="-y">-y</option>
<option value="-z">-z</option>
</select>
</div>
<div class="io-row"><span class="label-inline">Y</span><span class="colon">:</span><select id="imu_remap_y">
<option value="x">x</option> <option value="x">x</option>
<option value="y">y</option> <option value="y">y</option>
<option value="z">z</option> <option value="z">z</option>
<option value="-x">-x</option> <option value="-x">-x</option>
<option value="-y">-y</option> <option value="-y">-y</option>
<option value="-z">-z</option> <option value="-z">-z</option>
</select> </select></div>
<div class="io-row"><span class="label-inline">Z</span><span class="colon">:</span><select id="imu_remap_z">
<option value="x">x</option>
<option value="y">y</option>
<option value="z">z</option>
<option value="-x">-x</option>
<option value="-y">-y</option>
<option value="-z">-z</option>
</select></div>
</div> </div>
<div class="io-row"><span class="label-inline">Y</span><span class="colon">:</span><select id="imu_remap_y">
<option value="x">x</option>
<option value="y">y</option>
<option value="z">z</option>
<option value="-x">-x</option>
<option value="-y">-y</option>
<option value="-z">-z</option>
</select></div>
<div class="io-row"><span class="label-inline">Z</span><span class="colon">:</span><select id="imu_remap_z">
<option value="x">x</option>
<option value="y">y</option>
<option value="z">z</option>
<option value="-x">-x</option>
<option value="-y">-y</option>
<option value="-z">-z</option>
</select></div>
</div> </div>
</div> </div>
</div>
</div> </div>
<div class="actions"> <div class="actions">
<button id="loadDeviceBtn_io">Load Device File</button> <button id="loadDeviceBtn_io">Load Device File</button>
@ -487,21 +499,34 @@
</div> </div>
</section> </section>
<template id="modbus-row-template">
<tr>
<td><span class="field-display"></span></td>
<td><span class="addr-display"></span></td>
<td><span class="idt-display"></span></td>
<td><span class="odt-display"></span></td>
<td><span class="dv-display"></span></td>
<td><span class="shift-display"></span></td>
<td><span class="expr-display"></span></td>
<td><span class="mask-display"></span></td>
</tr>
</template>
<section id="page-modbus" class="page" style="display:none;"> <section id="page-modbus" class="page" style="display:none;">
<div class="card"> <div class="card">
<h3>Register configuration</h3> <h3>Register_Configuration Modbus화면</h3>
<div class="modbus-table-container"> <div class="modbus-table-container">
<table> <table>
<thead> <thead>
<tr> <tr>
<th>field</th> <th>Field</th>
<th>addr</th> <th>Address</th>
<th>idt</th> <th>IDT</th>
<th>odt</th> <th>ODT</th>
<th>dv</th> <th>Default Value</th>
<th>shift</th> <th>Shift</th>
<th>expr</th> <th>Expression</th>
<th>mask</th> <th>Mask</th>
</tr> </tr>
</thead> </thead>
<tbody id="modbus-field-list"> <tbody id="modbus-field-list">
@ -510,22 +535,22 @@
</div> </div>
<div class="modbus-input-area"> <div class="modbus-input-area">
<div class="input-row"> <label>Field</label>
<label>field</label><input type="text" id="modbus_field_input"> <input type="text" id="modbus_field_input" placeholder="Enter field name">
<label>idt(Input Data Type)</label><input type="text" id="modbus_idt_input"> <label class="nowrap">idt (Input Data Type)</label>
</div> <input type="text" id="modbus_idt_input" placeholder="Enter IDT">
<div class="input-row"> <label>addr</label>
<label>addr(address)</label><input type="text" id="modbus_addr_input"> <input type="text" id="modbus_addr_input" placeholder="Enter address">
<label>odt(Output Data Type)</label><input type="text" id="modbus_odt_input"> <label class="nowrap">odt (Output Data Type)</label>
</div> <input type="text" id="modbus_odt_input" placeholder="Enter ODT">
<div class="input-row"> <label>shift</label>
<label>shift</label><input type="text" id="modbus_shift_input"> <input type="text" id="modbus_shift_input" placeholder="Enter shift value">
<label>dv(Default Value)</label><input type="text" id="modbus_dv_input"> <label class="nowrap">dv</label>
</div> <input type="text" id="modbus_dv_input" placeholder="Enter default value">
<div class="input-row"> <label>expr</label>
<label>expr</label><input type="text" id="modbus_expr_input"> <input type="text" id="modbus_expr_input" placeholder="Enter expression">
<label>mask</label><input type="text" id="modbus_mask_input"> <label class="nowrap">mask</label>
</div> <input type="text" id="modbus_mask_input" placeholder="Enter mask">
</div> </div>
<div class="modbus-actions"> <div class="modbus-actions">
@ -535,7 +560,6 @@
</div> </div>
</div> </div>
<!-- 하단 버튼 영역 추가 -->
<div id="modbus-bottom-actions"> <div id="modbus-bottom-actions">
<button id="loadModbusBtn">Load Protocol File</button> <button id="loadModbusBtn">Load Protocol File</button>
<button id="saveModbusBtn">Save Protocol File</button> <button id="saveModbusBtn">Save Protocol File</button>
@ -869,9 +893,6 @@
console.error("Register data is null or undefined."); console.error("Register data is null or undefined.");
return; return;
} }
// 백엔드에서 받은 DTO 객체를 lastLoadedRegisterData에 저장합니다.
// 이 객체는 이미 camelCase 필드명을 가집니다.
lastLoadedRegisterData = {...register}; lastLoadedRegisterData = {...register};
console.log("Extracted Body Data:", lastLoadedRegisterData); // DTO 객체 로깅 console.log("Extracted Body Data:", lastLoadedRegisterData); // DTO 객체 로깅
@ -905,7 +926,7 @@
} }
} }
// protocol 값이 있으면 select 값을 변경 (데이터 로드 시에만) // protocol 값이 있으면 select 값을 변경 (데이터 로드 시에만)
if (register.protocol && regProtocolSelect) { if (register.protocol && regProtocolSelect) {
@ -915,18 +936,28 @@
// 프로토콜 값에 따라 사이드바 버튼 토글 // 프로토콜 값에 따라 사이드바 버튼 토글
toggleProtocolMenus(); toggleProtocolMenus();
// 예시: MODBUS 필드를 UI에 표시하는 가상의 로직 (HTML 컨테이너 필요) // MODBUS UI 테이블 렌더링
const modbusContainer = document.getElementById('modbus_fields_container'); // HTML에 이 ID의 div가 있다고 가정 const modbusFieldList = document.getElementById('modbus-field-list');
if (modbusContainer) { const modbusRowTemplate = document.getElementById('modbus-row-template');
modbusContainer.innerHTML = ''; // 기존 내용 지우기 if (modbusFieldList && modbusRowTemplate) {
if (lastLoadedRegisterData.MODBUS && lastLoadedRegisterData.MODBUS.length > 0) { modbusFieldList.innerHTML = '';
lastLoadedRegisterData.MODBUS.forEach(field => { if (Array.isArray(register.MODBUS) && register.MODBUS.length > 0) {
const fieldDiv = document.createElement('div'); register.MODBUS.forEach(field => {
fieldDiv.textContent = `Field: ${field.field}, Addr: ${field.addr}, IDT: ${field.idt}`; // 예시 const newRow = modbusRowTemplate.content.cloneNode(true);
modbusContainer.appendChild(fieldDiv); newRow.querySelector('.field-display').textContent = field.field ?? '';
newRow.querySelector('.addr-display').textContent = field.addr ?? '';
newRow.querySelector('.idt-display').textContent = field.idt ?? '';
newRow.querySelector('.odt-display').textContent = field.odt ?? '';
newRow.querySelector('.dv-display').textContent = field.dv ?? '';
newRow.querySelector('.shift-display').textContent = field.shift ?? '';
newRow.querySelector('.expr-display').textContent = field.expr ?? '';
newRow.querySelector('.mask-display').textContent = field.mask ?? '';
modbusFieldList.appendChild(newRow);
}); });
} else { } else {
modbusContainer.textContent = 'No MODBUS fields configured.'; // MODBUS 데이터가 없으면 빈 행 하나 추가
const newRow = modbusRowTemplate.content.cloneNode(true);
modbusFieldList.appendChild(newRow);
} }
} }
@ -956,57 +987,148 @@
function collectData() { function collectData() {
const res = {...data}; const res = {...data};
res.wifi_static = document.querySelector('input[name="ipMode"]:checked')?.value === 'static' res.wifi_static = document.querySelector('input[name="ipMode"]:checked')?.value === 'static'
? 'on' : 'off'; ? 'on' : 'off';
/* 일반 input/select */ /* 일반 input/select */
for (const k in res) { for (const k in res) {
const el = document.getElementById(k); const el = document.getElementById(k);
if (el) res[k] = el.value.trim(); if (el) res[k] = el.value.trim();
} }
/* IMU select → 축·부호 분리 */ /* IMU select → 축·부호 분리 */
['x', 'y', 'z'].forEach(a => { ['x', 'y', 'z'].forEach(a => {
const {axis, sign} = axisValueToPair(document.getElementById(`imu_remap_${a}`).value); const {axis, sign} = axisValueToPair(document.getElementById(`imu_remap_${a}`).value);
res[`imu_remap_${a}`] = axis; res[`imu_remap_${a}`] = axis;
res[`imu_remap_${a}_sign`] = sign; res[`imu_remap_${a}_sign`] = sign;
}); });
/* SSID 배열 */ /* SSID 배열 */
res.WIFI_SSID = gatherSsidRows(); res.WIFI_SSID = gatherSsidRows();
return res; return res;
} }
function collectConfigData() { function collectConfigData() {
const collectedRegister = {...lastLoadedRegisterData}; // DTO 필드명(camelCase)으로 값을 수집할 객체 const collectedRegister = {...lastLoadedRegisterData}; // DTO 필드명(camelCase)으로 값을 수집할 객체
// configIdMap을 순회하며 HTML ID로부터 값을 가져와 DTO 필드명에 매핑 // configIdMap을 순회하며 HTML ID로부터 값을 가져와 DTO 필드명에 매핑
for (const htmlId in configIdMap) { for (const htmlId in configIdMap) {
const dtoKey = configIdMap[htmlId]; // HTML ID에 해당하는 DTO 필드명 (camelCase) const dtoKey = configIdMap[htmlId]; // HTML ID에 해당하는 DTO 필드명 (camelCase)
const el = document.getElementById(htmlId); const el = document.getElementById(htmlId);
if (el) { if (el) {
collectedRegister[dtoKey] = el.value !== null && el.value !== undefined ? el.value.trim() : ''; collectedRegister[dtoKey] = el.value !== null && el.value !== undefined ? el.value.trim() : '';
}
} }
}
// 체크박스 필드 (HTML ID와 DTO 필드명이 같음) // 체크박스 필드 (HTML ID와 DTO 필드명이 같음)
// AnalogPort 매핑: true -> "1", false -> "0" // AnalogPort 매핑: true -> "1", false -> "0"
['ai0', 'ai1', 'ai2', 'ai3', 'di0', 'di1', 'di2', 'di3'].forEach(id => { ['ai0', 'ai1', 'ai2', 'ai3', 'di0', 'di1', 'di2', 'di3'].forEach(id => {
const el = document.getElementById(id); const el = document.getElementById(id);
if (el && el.type === 'checkbox') { if (el && el.type === 'checkbox') {
collectedRegister[id] = el.checked ? "1" : "0"; collectedRegister[id] = el.checked ? "1" : "0";
} else { } else {
if (collectedRegister[id] === undefined) { if (collectedRegister[id] === undefined) {
collectedRegister[id] = "0"; collectedRegister[id] = "0";
}
} }
}
});
return collectedRegister;
}
document.addEventListener('DOMContentLoaded', () => {
const list = document.getElementById('modbus-field-list');
// 처음에 행이 없으면 빈 행을 하나 추가
if(list.children.length === 0) {
const modbusRowTemplate = document.getElementById('modbus-row-template');
if(modbusRowTemplate) {
const newRow = modbusRowTemplate.content.cloneNode(true);
list.appendChild(newRow);
}
}
let selectedRow = null;
document.getElementById('modbus-field-list').addEventListener('click', function(e){
let tr = e.target.closest('tr');
if (!tr) return;
Array.from(this.children).forEach(row => row.classList.remove('selected-row'));
tr.classList.add('selected-row');
selectedRow = tr;
document.getElementById('modbus_field_input').value = tr.querySelector('.field-display').textContent;
document.getElementById('modbus_addr_input').value = tr.querySelector('.addr-display').textContent;
document.getElementById('modbus_idt_input').value = tr.querySelector('.idt-display').textContent;
document.getElementById('modbus_odt_input').value = tr.querySelector('.odt-display').textContent;
document.getElementById('modbus_dv_input').value = tr.querySelector('.dv-display').textContent;
document.getElementById('modbus_shift_input').value = tr.querySelector('.shift-display').textContent;
document.getElementById('modbus_expr_input').value = tr.querySelector('.expr-display').textContent;
document.getElementById('modbus_mask_input').value = tr.querySelector('.mask-display').textContent;
});
const modbusAddBtn = document.getElementById('modbus_add_btn');
const modbusFieldList = document.getElementById('modbus-field-list');
const modbusRowTemplate = document.getElementById('modbus-row-template');
if(modbusAddBtn && modbusFieldList && modbusRowTemplate){
modbusAddBtn.addEventListener('click',()=>{
const field = document.getElementById('modbus_field_input').value;
const addr = document.getElementById('modbus_addr_input').value;
const idt = document.getElementById('modbus_idt_input').value;
const odt = document.getElementById('modbus_odt_input').value;
const defaultValue = document.getElementById('modbus_dv_input').value;
const shift = document.getElementById('modbus_shift_input').value;
const expr = document.getElementById('modbus_expr_input').value;
const mask = document.getElementById('modbus_mask_input').value;
const newRow = modbusRowTemplate.content.cloneNode(true);
newRow.querySelector('.field-display').textContent = field;
newRow.querySelector('.addr-display').textContent = addr;
newRow.querySelector('.idt-display').textContent = idt;
newRow.querySelector('.odt-display').textContent = odt;
newRow.querySelector('.dv-display').textContent = defaultValue;
newRow.querySelector('.shift-display').textContent = shift;
newRow.querySelector('.expr-display').textContent = expr;
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 = '';
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 = '';
}); });
return collectedRegister;
} }
document.addEventListener('DOMContentLoaded', () => { document.getElementById('modbus_modify_btn').onclick = function() {
if (!selectedRow) return alert('수정할 행을 선택하세요!');
selectedRow.querySelector('.field-display').textContent = document.getElementById('modbus_field_input').value;
selectedRow.querySelector('.addr-display').textContent = document.getElementById('modbus_addr_input').value;
selectedRow.querySelector('.idt-display').textContent = document.getElementById('modbus_idt_input').value;
selectedRow.querySelector('.odt-display').textContent = document.getElementById('modbus_odt_input').value;
selectedRow.querySelector('.dv-display').textContent = document.getElementById('modbus_dv_input').value;
selectedRow.querySelector('.shift-display').textContent = document.getElementById('modbus_shift_input').value;
selectedRow.querySelector('.expr-display').textContent = document.getElementById('modbus_expr_input').value;
selectedRow.querySelector('.mask-display').textContent = document.getElementById('modbus_mask_input').value;
};
// 삭제 버튼
document.getElementById('modbus_delete_btn').onclick = function() {
if (!selectedRow) return alert('삭제할 행을 선택하세요!');
const list = document.getElementById('modbus-field-list');
selectedRow.remove();
selectedRow = null;
document.querySelectorAll('.modbus-input-area input').forEach(i => i.value = '');
};
regProtocolSelect = document.getElementById('reg_protocol'); regProtocolSelect = document.getElementById('reg_protocol');
if(regProtocolSelect) { if(regProtocolSelect) {
regProtocolSelect.addEventListener('change', () => { regProtocolSelect.addEventListener('change', () => {

Loading…
Cancel
Save