Browse Source

can input config

v2
gudae01 1 year ago
parent
commit
f8370436c4
  1. 6
      src/main/java/org/mobidgim/mobidigimproject/model/register/enums/AnalogInputLevel.java
  2. 8
      src/main/java/org/mobidgim/mobidigimproject/model/register/enums/FourByte.java
  3. 2
      src/main/java/org/mobidgim/mobidigimproject/model/register/enums/InputDataType.java
  4. 4
      src/main/java/org/mobidgim/mobidigimproject/model/register/enums/TwoByte.java
  5. 618
      src/main/resources/static/index.html

6
src/main/java/org/mobidgim/mobidigimproject/model/register/enums/AnalogInputLevel.java

@ -6,9 +6,9 @@ import lombok.AllArgsConstructor;
@AllArgsConstructor
public enum AnalogInputLevel {
two("2"),
four("4"),
six("6"),
TWO("2"),
FOUR("4"),
SIX("6"),
;
private final String analogInput;

8
src/main/java/org/mobidgim/mobidigimproject/model/register/enums/FourByte.java

@ -5,10 +5,10 @@ import lombok.AllArgsConstructor;
@AllArgsConstructor
public enum FourByte {
little("little"),
littleSwap("littleSwap"),
bigSwap("bigSwap"),
big("big");
LITTLE("little"),
LITTLE_SWAP("littleSwap"),
BIG_SWAP("bigSwap"),
BIG("big");
private final String fourByte;
@JsonValue

2
src/main/java/org/mobidgim/mobidigimproject/model/register/enums/InputDataType.java

@ -6,7 +6,7 @@ import lombok.AllArgsConstructor;
@AllArgsConstructor
public enum InputDataType {
integer("integer"),
flo("float"),
flo("float64"),
bool("boolean"),
unsignedInteger("unsignedInteger"),
shor("short"),

4
src/main/java/org/mobidgim/mobidigimproject/model/register/enums/TwoByte.java

@ -5,8 +5,8 @@ import lombok.AllArgsConstructor;
@AllArgsConstructor
public enum TwoByte {
little("little"),
big("big");
LITTLE("little"),
BIG("big");
private final String twoByte;
@JsonValue

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

@ -80,101 +80,54 @@
.config-actions button{min-width:140px;padding:10px 18px;font-size:16px;border:1px solid #bbb;background:#d9d9d9;border-radius:4px;cursor:pointer}
/* MODBUS 화면 심플 스타일 */
#page-modbus .card {
background: #f7f7f7;
border: 1px solid #bbb;
box-shadow: none;
padding: 24px;
border-radius: 4px;
display: flex;
flex-direction: column;
}
#page-modbus table {
width: 100%;
border-collapse: collapse;
background: #fff;
border: 1px solid #bbb;
}
#page-modbus th, #page-modbus td {
border: 1px solid #bbb;
padding: 6px 8px;
text-align: left;
background: #fff;
}
#page-modbus th {
background: #e5e5e5;
font-weight: 500;
}
#page-modbus .modbus-input-area {
display: grid;
grid-template-columns: 200px 200px 200px 200px;
gap: 20px 20px;
margin: 24px auto 16px auto;
background: #eaeaea;
padding: 16px;
border-radius: 4px;
margin-left: auto;
margin-right: auto;
}
#page-modbus .input-row {
display: contents;
}
#page-modbus .modbus-input-area label.nowrap {
white-space: nowrap;
}
#page-modbus .modbus-input-area label {
min-width: auto;
color: #444;
white-space: normal;
}
#page-modbus .modbus-input-area input {
background: #e0e0e0;
border: none;
border-radius: 2px;
padding: 4px 8px;
min-width: auto;
}
#page-modbus .modbus-actions {
display: flex;
gap: 24px;
justify-content: center;
margin: 16px 0 0 0;
}
#page-modbus .modbus-actions button {
background: #d3d3d3;
border: 1px solid #aaa;
border-radius: 2px;
padding: 8px 24px;
font-size: 16px;
cursor: pointer;
}
#page-modbus .card {background: #f7f7f7;border: 1px solid #bbb;box-shadow: none;padding: 24px;border-radius: 4px;display: flex;flex-direction: column;}
#page-modbus table {width: 100%;border-collapse: collapse;background: #fff;border: 1px solid #bbb;}
#page-modbus th, #page-modbus td {border: 1px solid #bbb;padding: 6px 8px;text-align: left;background: #fff;}
#page-modbus th {background: #e5e5e5;font-weight: 500;}
#page-modbus .modbus-input-area {display: grid;grid-template-columns: 200px 200px 200px 200px;gap: 20px 20px;margin: 24px auto 16px auto;background: #eaeaea;padding: 16px;border-radius: 4px;margin-left: auto;margin-right: auto;}
#page-modbus .input-row {display: contents;}
#page-modbus .modbus-input-area label.nowrap {white-space: nowrap;}
#page-modbus .modbus-input-area label {min-width: auto;color: #444;white-space: normal;}
#page-modbus .modbus-input-area input {background: #e0e0e0;border: none;border-radius: 2px;padding: 4px 8px;min-width: auto;}
#page-modbus .modbus-actions {display: flex;gap: 24px;justify-content: center;margin: 16px 0 0 0;}
#page-modbus .modbus-actions button {background: #d3d3d3;border: 1px solid #aaa;border-radius: 2px;padding: 8px 24px;font-size: 16px;cursor: pointer;}
/* 하단 버튼 영역 */
#modbus-bottom-actions {
display: flex;
gap: 24px;
justify-content: center;
background: #f7f7f7;
border: 1px solid #bbb;
border-radius: 4px;
margin: 24px 0 0 0;
padding: 20px 0;
}
#modbus-bottom-actions button {
background: #e0e0e0;
border: 1px solid #aaa;
border-radius: 2px;
padding: 10px 18px;
font-size: 16px;
min-width: 140px;
cursor: pointer;
}
#modbus-bottom-actions {display: flex;gap: 24px;justify-content: center;background: #f7f7f7;border: 1px solid #bbb;border-radius: 4px;margin: 24px 0 0 0;padding: 20px 0;}
#modbus-bottom-actions button {background: #e0e0e0;border: 1px solid #aaa;border-radius: 2px;padding: 10px 18px;font-size: 16px;min-width: 140px;cursor: pointer;}
/* OPC_UA 화면 */
#page-opcua .card {background: #f7f7f7;border: 1px solid #bbb;box-shadow: none;padding: 24px;border-radius: 4px;display: flex;flex-direction: column;}
#page-opcua table {width: 100%;border-collapse: collapse;background: #fff;border: 1px solid #bbb;}
#page-opcua th, #page-opcua td {border: 1px solid #bbb;padding: 6px 8px;text-align: left;background: #fff;}
#page-opcua th {background: #e5e5e5;font-weight: 500;}
#page-opcua .opcua-input-area {display: grid;grid-template-columns: 200px 200px 200px 200px;gap: 20px 20px;margin: 24px auto 16px auto;background: #eaeaea;padding: 16px;border-radius: 4px;margin-left: auto;margin-right: auto;}
#page-opcua .input-row {display: contents;}
#page-opcua .opcua-input-area label.nowrap {white-space: nowrap;}
#page-opcua .opcua-input-area label {min-width: auto;color: #444;white-space: normal;}
#page-opcua .opcua-input-area input {background: #e0e0e0;border: none;border-radius: 2px;padding: 4px 8px;min-width: auto;}
#page-opcua .opcua-actions {display: flex;gap: 24px;justify-content: center;margin: 16px 0 0 0;}
#page-opcua .opcua-actions button {background: #d3d3d3;border: 1px solid #aaa;border-radius: 2px;padding: 8px 24px;font-size: 16px;cursor: pointer;}
#opcUa-bottom-actions {display: flex;gap: 24px;justify-content: center;background: #f7f7f7;border: 1px solid #bbb;border-radius: 4px;margin: 24px 0 0 0;padding: 20px 0;}
#opcUa-bottom-actions button {background: #e0e0e0;border: 1px solid #aaa;border-radius: 2px;padding: 10px 18px;font-size: 16px;min-width: 140px;cursor: pointer;}
/* CAN 화면 스타일 */
#page-can .card {background: #f7f7f7; border: 1px solid #bbb; box-shadow: none; padding: 24px; border-radius: 4px; display: flex; flex-direction: column;}
#page-can table {width: 100%; border-collapse: collapse; background: #fff; border: 1px solid #bbb;}
#page-can th, #page-can td {border: 1px solid #bbb; padding: 6px 8px; text-align: left; background: #fff;}
#page-can th {background: #e5e5e5; font-weight: 500;}
#page-can .can-input-area {display: grid; grid-template-columns: 200px 200px 200px 200px; gap: 20px 20px; margin: 24px auto 16px auto; background: #eaeaea; padding: 16px; border-radius: 4px; margin-left: auto; margin-right: auto;}
#page-can .input-row {display: contents;}
#page-can .can-input-area label.nowrap {white-space: nowrap;}
#page-can .can-input-area label {min-width: auto; color: #444; white-space: normal;}
#page-can .can-input-area input {background: #e0e0e0; border: none; border-radius: 2px; padding: 4px 8px; min-width: auto;}
#page-can .can-actions {display: flex; gap: 24px; justify-content: center; margin: 16px 0 0 0;}
#page-can .can-actions button {background: #d3d3d3; border: 1px solid #aaa; border-radius: 2px; padding: 8px 24px; font-size: 16px; cursor: pointer;}
#can-bottom-actions {display: flex; gap: 24px; justify-content: center; background: #f7f7f7; border: 1px solid #bbb; border-radius: 4px; margin: 24px 0 0 0; padding: 20px 0;}
#can-bottom-actions button {background: #e0e0e0; border: 1px solid #aaa; border-radius: 2px; padding: 10px 18px; font-size: 16px; min-width: 140px; cursor: pointer;}
.selected-row{background: #d0e6ff !important;}
.selected-row > td {background: #d0e6ff !important;}
.selected-row{
background: #d0e6ff !important;
}
.selected-row > td {
background: #d0e6ff !important;
}
</style>
</head>
<body>
@ -195,6 +148,7 @@
<button data-page="reg">Config</button>
<button data-page="modbus" id="modbusSidebarBtn" style="display: none">MODBUS</button>
<button data-page="opcua" id="opcUaSidebarBtn" style="display: none">OPC_UA</button>
<button data-page="can" id="canSidebarBtn" style="display: none">CAN</button>
</div>
</details>
</aside>
@ -446,8 +400,8 @@
<select id="reg_four_byte_order">
<option selected disabled hidden="hidden"></option>
<option value="little">little</option>
<option value="little_swap">little swap</option>
<option value="big_swap">big swap</option>
<option value="littleSwap">little swap</option>
<option value="bigSwap">big swap</option>
<option value="big">big</option>
</select>
</div>
@ -538,11 +492,25 @@
<label>Field</label>
<input type="text" id="modbus_field_input" placeholder="Enter field name">
<label class="nowrap">idt (Input Data Type)</label>
<input type="text" id="modbus_idt_input" placeholder="Enter IDT">
<select id="modbus_idt_input">
<option selected disabled hidden="hidden"></option>
<option value="integer">integer</option>
<option value="float64">float64</option>
<option value="boolean">boolean</option>
<option value="unsignedInteger">unsignedInteger</option>
<option value="short">short</option>
<option value="unsignedShort">unsignedShort</option>
</select>
<label>addr</label>
<input type="text" id="modbus_addr_input" placeholder="Enter address">
<label class="nowrap">odt (Output Data Type)</label>
<input type="text" id="modbus_odt_input" placeholder="Enter ODT">
<select id="modbus_odt_input">
<option selected disabled hidden="hidden"></option>
<option value="integer">integer</option>
<option value="float64">float64</option>
<option value="boolean">boolean</option>
<option value="string">string</option>
</select>
<label>shift</label>
<input type="text" id="modbus_shift_input" placeholder="Enter shift value">
<label class="nowrap">dv</label>
@ -586,11 +554,14 @@
<table>
<thead>
<tr>
<th>field</th>
<th>addr</th>
<th>ns</th>
<th>odt</th>
<th>dv</th>
<th>Field</th>
<th>Address</th>
<th>NS</th>
<th>ODT</th>
<th>Default Value</th>
<th>Shift</th>
<th>Expression</th>
<th>Mask</th>
</tr>
</thead>
<tbody id="opcua-field-list">
@ -599,22 +570,28 @@
</div>
<div class="opcua-input-area">
<div class="input-row">
<label>field</label><input type="text" id="opcua_field_input">
<label>ns(NameSpace)</label><input type="text" id="opcua_ns_input">
</div>
<div class="input-row">
<label>addr(address)</label><input type="text" id="opcua_addr_input">
<label>odt(Output Data Type)</label><input type="text" id="opcua_odt_input">
</div>
<div class="input-row">
<label>shift</label><input type="text" id="opcua_shift_input">
<label>dv(Default Value)</label><input type="text" id="opcua_dv_input">
</div>
<div class="input-row">
<label>expr</label><input type="text" id="opcua_expr_input">
<label>mask</label><input type="text" id="opcua_mask_input">
</div>
<label>field</label>
<input type="text" id="opcua_field_input" placeholder="Enter field name">
<label class="nowrap">ns(NameSpace)</label>
<input type="text" id="opcua_ns_input" placeholder="Enter NS">
<label>addr(address)</label>
<input type="text" id="opcua_addr_input" placeholder="Enter address">
<label class="nowrap">odt(Output Data Type)</label>
<select id="opcua_odt_input">
<option selected disabled hidden="hidden"></option>
<option value="integer">integer</option>
<option value="float64">float64</option>
<option value="boolean">boolean</option>
<option value="string">string</option>
</select>
<label>shift</label>
<input type="text" id="opcua_shift_input" placeholder="Enter shift value">
<label class="nowrap">dv(Default Value)</label>
<input type="text" id="opcua_dv_input" placeholder="Enter default value">
<label>expr</label>
<input type="text" id="opcua_expr_input" placeholder="Enter expression">
<label class="nowrap">mask</label>
<input type="text" id="opcua_mask_input" placeholder="Enter mask">
</div>
<div class="opcua-actions">
@ -624,12 +601,78 @@
</div>
</div>
<div class="actions">
<div id="opcUa-bottom-actions">
<button id="loadOpcUaFileBtn">Load Protocol File</button>
<button id="saveOpcUaFileBtn">Save to Protocol</button>
</div>
</section>
<template id="can-row-template">
<tr class="can-row">
<td><span class="can-field-display"></span></td>
<td><span class="can-id-display"></span></td>
<td><span class="can-odt-display"></span></td>
<td><span class="can-dv-display"></span></td>
<td><span class="can-shift-display"></span></td>
<td><span class="can-mask-display"></span></td>
<td><span class="can-expr-display"></span></td>
</tr>
</template>
<section id="page-can" class="page" style="display:none;">
<div class="card">
<h3>CAN Configuration</h3>
<div class="can-table-container">
<table>
<thead>
<tr>
<th>Field</th>
<th>ID</th>
<th>ODT</th>
<th>Default Value</th>
<th>Shift</th>
<th>Expression</th>
<th>Mask</th>
</tr>
</thead>
<tbody id="can-field-list">
</tbody>
</table>
</div>
<div class="can-input-area">
<label>Field</label>
<input type="text" id="can_field_input" placeholder="Enter field name">
<label>ID</label>
<input type="text" id="can_id_input" placeholder="Enter ID">
<label>odt (Output Data Type)</label>
<select id="can_odt_input">
<option selected disabled hidden="hidden"></option>
<option value="integer">integer</option>
<option value="float64">float64</option>
<option value="boolean">boolean</option>
<option value="string">string</option>
</select>
<label>dv</label>
<input type="text" id="can_dv_input" placeholder="Enter default value">
<label>shift</label>
<input type="text" id="can_shift_input" placeholder="Enter shift value">
<label>expr</label>
<input type="text" id="can_expr_input" placeholder="Enter expression">
<label>mask</label>
<input type="text" id="can_mask_input" placeholder="Enter mask">
</div>
<div class="can-actions">
<button id="can_add_btn">Add</button>
<button id="can_modify_btn">Modify</button>
<button id="can_delete_btn">Delete</button>
</div>
</div>
<div id="can-bottom-actions">
<button id="loadCanBtn">Load Protocol File</button>
<button id="saveCanBtn">Save Protocol File</button>
</div>
</section>
</main>
</div>
@ -733,7 +776,8 @@
io : document.getElementById('page-io'),
reg : document.getElementById('page-reg'),
modbus : document.getElementById('page-modbus'),
opcua : document.getElementById('page-opcua')
opcua : document.getElementById('page-opcua'),
can : document.getElementById('page-can')
};
const titleEl = document.getElementById('page-title');
@ -872,18 +916,22 @@
const selectProtocol = regProtocolSelect.value;
const modbusSidebarBtn = document.getElementById('modbusSidebarBtn');
const opcUaSidebarBtn = document.getElementById('opcUaSidebarBtn');
const canSidebarBtn = document.getElementById('canSidebarBtn');
if(modbusSidebarBtn) modbusSidebarBtn.style.display = 'none';
if(opcUaSidebarBtn) opcUaSidebarBtn.style.display = 'none';
if(canSidebarBtn) canSidebarBtn.style.display = 'none';
if(selectProtocol === 'MODBUS'){
if (modbusSidebarBtn) modbusSidebarBtn.style.display = 'block';
}
else if(selectProtocol === 'OPC_UA'){
if(opcUaSidebarBtn) opcUaSidebarBtn.style.display = 'block';
}
// Protocol configuration 메뉴를 자동으로 펼치기
// CAN Input이 on일 때만 CAN 메뉴 보이기
const canInputEl = document.getElementById('reg_can_input');
if(canInputEl && canInputEl.value === 'on'){
if(canSidebarBtn) canSidebarBtn.style.display = 'block';
}
// Protocol configuration 메뉴 자동 펼치기
const protocolDetails = document.querySelectorAll('details.nav')[1];
if (protocolDetails) protocolDetails.open = true;
}
@ -961,28 +1009,53 @@
}
}
const opcUaContainer = document.getElementById('opc_ua_fields_container');
if (opcUaContainer) {
opcUaContainer.innerHTML = '';
if (lastLoadedRegisterData.OPC_UA && lastLoadedRegisterData.OPC_UA.length > 0) {
lastLoadedRegisterData.OPC_UA.forEach(field => {
// ... OPC_UA 필드 표시 로직 ...
// OPC_UA UI 테이블 렌더링
const opcUaFieldList = document.getElementById('opcua-field-list');
const opcUaRowTemplate = document.getElementById('opcua-row-template');
if (opcUaFieldList && opcUaRowTemplate) {
opcUaFieldList.innerHTML = '';
if (Array.isArray(register.OPC_UA) && register.OPC_UA.length > 0) {
register.OPC_UA.forEach(field => {
const newRow = opcUaRowTemplate.content.cloneNode(true);
newRow.querySelector('.opcua-field-display').textContent = field.field ?? '';
newRow.querySelector('.opcua-addr-display').textContent = field.addr ?? '';
newRow.querySelector('.opcua-ns-display').textContent = field.idt ?? '';
newRow.querySelector('.opcua-odt-display').textContent = field.odt ?? '';
newRow.querySelector('.opcua-dv-display').textContent = field.dv ?? '';
newRow.querySelector('.opcua-shift-display').textContent = field.shift ?? '';
newRow.querySelector('.opcua-expr-display').textContent = field.expr ?? '';
newRow.querySelector('.opcua-mask-display').textContent = field.mask ?? '';
opcUaFieldList.appendChild(newRow);
});
} else {
opcUaContainer.textContent = 'No OPC_UA fields configured.';
// OPC_UA 데이터가 없으면 빈 행 하나 추가
const newRow = opcUaRowTemplate.content.cloneNode(true);
opcUaFieldList.appendChild(newRow);
}
}
const canContainer = document.getElementById('can_fields_container');
if (canContainer) {
canContainer.innerHTML = '';
if (lastLoadedRegisterData.CAN && lastLoadedRegisterData.CAN.length > 0) {
lastLoadedRegisterData.CAN.forEach(field => {
// ... CAN 필드 표시 로직 ...
});
} else {
canContainer.textContent = 'No CAN fields configured.';
}
// CAN 테이블 렌더링
const canFieldList = document.getElementById('can-field-list');
const canRowTemplate = document.getElementById('can-row-template');
canFieldList.innerHTML = '';
if (Array.isArray(register.CAN) && register.CAN.length > 0) {
register.CAN.forEach(field => {
const newRow = canRowTemplate.content.cloneNode(true);
newRow.querySelector('.can-field-display').textContent = field.field ?? '';
newRow.querySelector('.can-id-display').textContent = field.id ?? '';
newRow.querySelector('.can-odt-display').textContent = field.odt ?? '';
newRow.querySelector('.can-dv-display').textContent = field.dv ?? '';
newRow.querySelector('.can-shift-display').textContent = field.shift ?? '';
newRow.querySelector('.can-expr-display').textContent = field.expr ?? '';
newRow.querySelector('.can-mask-display').textContent = field.mask ?? '';
canFieldList.appendChild(newRow);
});
} else {
const newRow = canRowTemplate.content.cloneNode(true);
canFieldList.appendChild(newRow);
}
}
@ -1011,19 +1084,16 @@
}
function collectConfigData() {
const collectedRegister = {...lastLoadedRegisterData}; // DTO 필드명(camelCase)으로 값을 수집할 객체
const collectedRegister = {...lastLoadedRegisterData};
// configIdMap을 순회하며 HTML ID로부터 값을 가져와 DTO 필드명에 매핑
for (const htmlId in configIdMap) {
const dtoKey = configIdMap[htmlId]; // HTML ID에 해당하는 DTO 필드명 (camelCase)
const dtoKey = configIdMap[htmlId];
const el = document.getElementById(htmlId);
if (el) {
collectedRegister[dtoKey] = el.value !== null && el.value !== undefined ? el.value.trim() : '';
}
}
// 체크박스 필드 (HTML ID와 DTO 필드명이 같음)
// AnalogPort 매핑: true -> "1", false -> "0"
['ai0', 'ai1', 'ai2', 'ai3', 'di0', 'di1', 'di2', 'di3'].forEach(id => {
const el = document.getElementById(id);
if (el && el.type === 'checkbox') {
@ -1034,6 +1104,79 @@
}
}
});
// MODBUS 테이블 수집 (빈 값은 필드에서 제외)
const modbusRows = document.querySelectorAll('#modbus-field-list tr');
collectedRegister.MODBUS = [];
modbusRows.forEach(row => {
const field = row.querySelector('.field-display')?.textContent.trim();
if (field) {
const obj = {};
obj.field = field;
const addr = row.querySelector('.addr-display')?.textContent.trim();
const idt = row.querySelector('.idt-display')?.textContent.trim();
const odt = row.querySelector('.odt-display')?.textContent.trim();
const dv = row.querySelector('.dv-display')?.textContent.trim();
const shift = row.querySelector('.shift-display')?.textContent.trim();
const expr = row.querySelector('.expr-display')?.textContent.trim();
const mask = row.querySelector('.mask-display')?.textContent.trim();
if (addr) obj.addr = addr;
if (idt) obj.idt = idt;
if (odt) obj.odt = odt;
if (dv) obj.dv = dv;
if (shift) obj.shift = shift;
if (expr) obj.expr = expr;
if (mask) obj.mask = mask;
collectedRegister.MODBUS.push(obj);
}
});
// OPC_UA 테이블 수집 (빈 값은 필드에서 제외)
const opcuaRows = document.querySelectorAll('#opcua-field-list tr');
collectedRegister.OPC_UA = [];
opcuaRows.forEach(row => {
const field = row.querySelector('.opcua-field-display')?.textContent.trim();
if (field) {
const obj = {};
obj.field = field;
const addr = row.querySelector('.opcua-addr-display')?.textContent.trim();
const ns = row.querySelector('.opcua-ns-display')?.textContent.trim();
const odt = row.querySelector('.opcua-odt-display')?.textContent.trim();
const dv = row.querySelector('.opcua-dv-display')?.textContent.trim();
const shift = row.querySelector('.opcua-shift-display')?.textContent.trim();
const expr = row.querySelector('.opcua-expr-display')?.textContent.trim();
const mask = row.querySelector('.opcua-mask-display')?.textContent.trim();
if (addr) obj.addr = addr;
if (ns) obj.ns = ns;
if (odt) obj.odt = odt;
if (dv) obj.dv = dv;
if (shift) obj.shift = shift;
if (expr) obj.expr = expr;
if (mask) obj.mask = mask;
collectedRegister.OPC_UA.push(obj);
}
});
// CAN 테이블 수집 (빈 값은 필드에서 제외)
const canRows = document.querySelectorAll('#can-field-list tr');
collectedRegister.CAN = [];
canRows.forEach(row => {
const field = row.querySelector('.can-field-display')?.textContent.trim();
if (field) {
const obj = {};
obj.field = field;
const id = row.querySelector('.can-id-display')?.textContent.trim();
const odt = row.querySelector('.can-odt-display')?.textContent.trim();
const dv = row.querySelector('.can-dv-display')?.textContent.trim();
const shift = row.querySelector('.can-shift-display')?.textContent.trim();
const expr = row.querySelector('.can-expr-display')?.textContent.trim();
const mask = row.querySelector('.can-mask-display')?.textContent.trim();
if (id) obj.id = id;
if (odt) obj.odt = odt;
if (dv) obj.dv = dv;
if (shift) obj.shift = shift;
if (expr) obj.expr = expr;
if (mask) obj.mask = mask;
collectedRegister.CAN.push(obj);
}
});
return collectedRegister;
}
@ -1066,6 +1209,33 @@
document.getElementById('modbus_mask_input').value = tr.querySelector('.mask-display').textContent;
});
const opcUalist = document.getElementById('opcua-field-list');
// 처음에 행이 없으면 빈 행을 하나 추가
if(opcUalist.children.length === 0) {
const opcUaRowTemplate = document.getElementById('opcua-row-template');
if(opcUaRowTemplate) {
const newRow = opcUaRowTemplate.content.cloneNode(true);
opcUalist.appendChild(newRow);
}
}
document.getElementById('opcua-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('opcua_field_input').value = tr.querySelector('.opcua-field-display').textContent;
document.getElementById('opcua_addr_input').value = tr.querySelector('.opcua-addr-display').textContent;
document.getElementById('opcua_ns_input').value = tr.querySelector('.opcua-ns-display').textContent;
document.getElementById('opcua_odt_input').value = tr.querySelector('.opcua-odt-display').textContent;
document.getElementById('opcua_dv_input').value = tr.querySelector('.opcua-dv-display').textContent;
document.getElementById('opcua_shift_input').value = tr.querySelector('.opcua-shift-display').textContent;
document.getElementById('opcua_expr_input').value = tr.querySelector('.opcua-expr-display').textContent;
document.getElementById('opcua_mask_input').value = tr.querySelector('.opcua-mask-display').textContent;
});
@ -1128,6 +1298,110 @@
document.querySelectorAll('.modbus-input-area input').forEach(i => i.value = '');
};
const opcUaAddBtn = document.getElementById('opcua_add_btn');
const opcUaFieldList = document.getElementById('opcua-field-list');
const opcUaRowTemplate = document.getElementById('opcua-row-template');
if(opcUaAddBtn && opcUaFieldList && opcUaRowTemplate){
opcUaAddBtn.addEventListener('click',()=>{
const field = document.getElementById('opcua_field_input').value;
const addr = document.getElementById('opcua_addr_input').value;
const ns = document.getElementById('opcua_ns_input').value;
const odt = document.getElementById('opcua_odt_input').value;
const defaultValue = document.getElementById('opcua_dv_input').value;
const shift = document.getElementById('opcua_shift_input').value;
const expr = document.getElementById('opcua_expr_input').value;
const mask = document.getElementById('opcua_mask_input').value;
const newRow = opcUaRowTemplate.content.cloneNode(true);
newRow.querySelector('.opcua-field-display').textContent = field;
newRow.querySelector('.opcua-addr-display').textContent = addr;
newRow.querySelector('.opcua-ns-display').textContent = ns;
newRow.querySelector('.opcua-odt-display').textContent = odt;
newRow.querySelector('.opcua-dv-display').textContent = defaultValue;
newRow.querySelector('.opcua-shift-display').textContent = shift;
newRow.querySelector('.opcua-expr-display').textContent = expr;
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('opcua_modify_btn').onclick = function() {
if (!selectedRow) return alert('수정할 행을 선택하세요!');
selectedRow.querySelector('.opcua-field-display').textContent = document.getElementById('opcua_field_input').value;
selectedRow.querySelector('.opcua-addr-display').textContent = document.getElementById('opcua_addr_input').value;
selectedRow.querySelector('.opcua-ns-display').textContent = document.getElementById('opcua_ns_input').value;
selectedRow.querySelector('.opcua-odt-display').textContent = document.getElementById('opcua_odt_input').value;
selectedRow.querySelector('.opcua-dv-display').textContent = document.getElementById('opcua_dv_input').value;
selectedRow.querySelector('.opcua-shift-display').textContent = document.getElementById('opcua_shift_input').value;
selectedRow.querySelector('.opcua-expr-display').textContent = document.getElementById('opcua_expr_input').value;
selectedRow.querySelector('.opcua-mask-display').textContent = document.getElementById('opcua_mask_input').value;
};
// 삭제 버튼
document.getElementById('opcua_delete_btn').onclick = function() {
if (!selectedRow) return alert('삭제할 행을 선택하세요!');
const list = document.getElementById('opcua-field-list');
selectedRow.remove();
selectedRow = null;
document.querySelectorAll('.opcua-input-area input').forEach(i => i.value = '');
};
// CAN 테이블
document.getElementById('can_add_btn').addEventListener('click',()=>{
const field = document.getElementById('can_field_input').value;
const id = document.getElementById('can_id_input').value;
const odt = document.getElementById('can_odt_input').value;
const dv = document.getElementById('can_dv_input').value;
const shift = document.getElementById('can_shift_input').value;
const expr = document.getElementById('can_expr_input').value;
const mask = document.getElementById('can_mask_input').value;
const canRowTemplate = document.getElementById('can-row-template');
const newRow = canRowTemplate.content.cloneNode(true);
newRow.querySelector('.can-field-display').textContent = field;
newRow.querySelector('.can-id-display').textContent = id;
newRow.querySelector('.can-odt-display').textContent = odt;
newRow.querySelector('.can-dv-display').textContent = dv;
newRow.querySelector('.can-shift-display').textContent = shift;
newRow.querySelector('.can-expr-display').textContent = expr;
newRow.querySelector('.can-mask-display').textContent = mask;
canFieldList.appendChild(newRow);
document.getElementById('can_field_input').value = '';
document.getElementById('can_id_input').value = '';
document.getElementById('can_odt_input').value = '';
document.getElementById('can_dv_input').value = '';
document.getElementById('can_shift_input').value = '';
document.getElementById('can_expr_input').value = '';
document.getElementById('can_mask_input').value = '';
});
document.getElementById('can_modify_btn').onclick = function() {
if (!selectedRow) return alert('수정할 행을 선택하세요!');
selectedRow.querySelector('.can-field-display').textContent = document.getElementById('can_field_input').value;
selectedRow.querySelector('.can-id-display').textContent = document.getElementById('can_id_input').value;
selectedRow.querySelector('.can-odt-display').textContent = document.getElementById('can_odt_input').value;
selectedRow.querySelector('.can-dv-display').textContent = document.getElementById('can_dv_input').value;
selectedRow.querySelector('.can-shift-display').textContent = document.getElementById('can_shift_input').value;
selectedRow.querySelector('.can-expr-display').textContent = document.getElementById('can_expr_input').value;
selectedRow.querySelector('.can-mask-display').textContent = document.getElementById('can_mask_input').value;
};
document.getElementById('can_delete_btn').onclick = function() {
if (!selectedRow) return alert('삭제할 행을 선택하세요!');
const list = document.getElementById('can-field-list');
selectedRow.remove();
selectedRow = null;
document.querySelectorAll('.can-input-area input').forEach(i => i.value = '');
};
regProtocolSelect = document.getElementById('reg_protocol');
if(regProtocolSelect) {
@ -1377,6 +1651,58 @@
alert('Register 설정 전송 중 통신 오류 발생');
});
});
document.getElementById('reg_can_input')?.addEventListener('change', toggleProtocolMenus);//--------------------------------
// DOMContentLoaded 내부에 추가: CAN 테이블도 처음에 빈 행이 없으면 하나 추가
const canFieldList = document.getElementById('can-field-list');
if(canFieldList.children.length === 0) {
const canRowTemplate = document.getElementById('can-row-template');
if(canRowTemplate) {
const newRow = canRowTemplate.content.cloneNode(true);
canFieldList.appendChild(newRow);
}
}
// CAN row 클릭 시 선택 표시 및 입력폼에 값 반영
canFieldList.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('can_field_input').value = tr.querySelector('.can-field-display').textContent;
document.getElementById('can_id_input').value = tr.querySelector('.can-id-display').textContent;
document.getElementById('can_odt_input').value = tr.querySelector('.can-odt-display').textContent;
document.getElementById('can_dv_input').value = tr.querySelector('.can-dv-display').textContent;
document.getElementById('can_shift_input').value = tr.querySelector('.can-shift-display').textContent;
document.getElementById('can_expr_input').value = tr.querySelector('.can-expr-display').textContent;
document.getElementById('can_mask_input').value = tr.querySelector('.can-mask-display').textContent;
});
});
document.getElementById('loadCanBtn').addEventListener('click', () => {
fetch('http://localhost:8080/setting/get-register')
.then(res => res.json())
.then(apiResponseData => {
if (apiResponseData && apiResponseData.body) {
loadFromRegisterJson(apiResponseData.body);
alert('Protocol 설정 파일 로드 완료');
}
});
});
document.getElementById('saveCanBtn').addEventListener('click', () => {
fetch('http://localhost:8080/setting/register', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(collectConfigData())
})
.then(res => {
if (res.ok) {
alert('Register 설정 전송 완료');
} else {
alert('Register 설정 전송 실패: ' + res.statusText);
}
});
});
</script>
</body>

Loading…
Cancel
Save