13 changed files with 536 additions and 37 deletions
@ -0,0 +1,18 @@ |
|||||
|
package org.mobidgim.mobidigimproject.config.filterconfig; |
||||
|
|
||||
|
import org.mobidgim.mobidigimproject.filter.LoggerFilter; |
||||
|
import org.springframework.boot.web.servlet.FilterRegistrationBean; |
||||
|
import org.springframework.context.annotation.Bean; |
||||
|
import org.springframework.context.annotation.Configuration; |
||||
|
|
||||
|
@Configuration |
||||
|
public class FilterConfig { |
||||
|
@Bean |
||||
|
public FilterRegistrationBean<LoggerFilter> loggerFilter() { |
||||
|
FilterRegistrationBean<LoggerFilter> registration = new FilterRegistrationBean<>(); |
||||
|
registration.setFilter(new LoggerFilter()); |
||||
|
registration.addUrlPatterns("/*"); |
||||
|
registration.setOrder(1); |
||||
|
return registration; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,63 @@ |
|||||
|
package org.mobidgim.mobidigimproject.filter; |
||||
|
|
||||
|
import jakarta.servlet.*; |
||||
|
import jakarta.servlet.http.HttpServletRequest; |
||||
|
import jakarta.servlet.http.HttpServletResponse; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.web.util.ContentCachingRequestWrapper; |
||||
|
import org.springframework.web.util.ContentCachingResponseWrapper; |
||||
|
|
||||
|
import java.io.IOException; |
||||
|
|
||||
|
@Slf4j |
||||
|
public class LoggerFilter implements Filter { |
||||
|
|
||||
|
@Override |
||||
|
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { |
||||
|
|
||||
|
|
||||
|
var req = new ContentCachingRequestWrapper((HttpServletRequest) request); |
||||
|
var res = new ContentCachingResponseWrapper((HttpServletResponse) response); |
||||
|
log.info("INIT URI: {}", req.getRequestURI()); |
||||
|
chain.doFilter(req,res); |
||||
|
|
||||
|
var headersNames = req.getHeaderNames(); |
||||
|
var headersValues = new StringBuilder(); |
||||
|
|
||||
|
headersNames.asIterator().forEachRemaining(headerKey->{ |
||||
|
var headerValue = req.getHeader(headerKey); |
||||
|
|
||||
|
headersValues.append("[") |
||||
|
.append(headerKey) |
||||
|
.append(":") |
||||
|
.append(headerValue) |
||||
|
.append("]"); |
||||
|
}); |
||||
|
|
||||
|
var requestBody = new String(req.getContentAsByteArray()); |
||||
|
|
||||
|
var uri = req.getRequestURI(); |
||||
|
var method = req.getMethod(); |
||||
|
log.info(">>>> uri: {}, method: {}, header: {}, body: {}",uri,method,headersValues,requestBody); |
||||
|
|
||||
|
var responseHeadersValues = new StringBuilder(); |
||||
|
|
||||
|
res.getHeaderNames().forEach(headerKey ->{ |
||||
|
var headerValue = req.getHeader(headerKey); |
||||
|
|
||||
|
responseHeadersValues.append("[") |
||||
|
.append(headerKey) |
||||
|
.append(":") |
||||
|
.append(headerValue) |
||||
|
.append("]"); |
||||
|
}); |
||||
|
var responseBody = new String(res.getContentAsByteArray()); |
||||
|
log.info("<<<< uri: {}, method: {}, header: {}, body: {}",uri,method,responseHeadersValues,responseBody); |
||||
|
|
||||
|
res.copyBodyToResponse(); |
||||
|
|
||||
|
|
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
||||
@ -1,4 +0,0 @@ |
|||||
package org.mobidgim.mobidigimproject.model.register; |
|
||||
|
|
||||
public class RegisterDTO { |
|
||||
} |
|
||||
@ -0,0 +1,410 @@ |
|||||
|
<!DOCTYPE html> |
||||
|
<html lang="ko"> |
||||
|
<head> |
||||
|
<meta charset="UTF-8" /> |
||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
||||
|
<title>Device Configuration UI</title> |
||||
|
|
||||
|
<style> |
||||
|
*{margin:0;padding:0;box-sizing:border-box} |
||||
|
body{font-family:"Pretendard",sans-serif;min-height:100vh;display:flex;background:#fff;color:#111} |
||||
|
|
||||
|
/* ───── Sidebar ───── */ |
||||
|
.sidebar{width:260px;border-right:1px solid #ddd;padding:32px 24px;display:flex;flex-direction:column} |
||||
|
.sidebar h2{font-size:24px;margin-bottom:32px} |
||||
|
details.nav{margin-bottom:24px} |
||||
|
.nav>summary{list-style:none;cursor:pointer;display:flex;align-items:center;font-size:20px} |
||||
|
.nav>summary::before{content:"";width:8px;height:8px;margin-right:8px; |
||||
|
border-left:2px solid #111;border-bottom:2px solid #111;transform:rotate(-45deg);transition:.2s} |
||||
|
.nav[open]>summary::before{transform:rotate(45deg)} |
||||
|
.nav-items{display:flex;flex-direction:column;margin-top:10px;padding-left:16px;gap:6px} |
||||
|
.nav-items button{background:none;border:none;cursor:pointer;font-size:16px;text-align:left;padding:4px 0} |
||||
|
|
||||
|
/* ───── Top-bar ───── */ |
||||
|
.topbar{height:68px;background:#d9d9d9;display:flex;align-items:center; |
||||
|
padding:0 32px;font-size:28px;font-weight:500;box-shadow:0 2px 4px rgba(0,0,0,.15) inset} |
||||
|
|
||||
|
/* ───── Main Board ───── */ |
||||
|
.content{flex:1;display:flex;flex-direction:column} |
||||
|
.board{flex:1;overflow:auto;padding:40px;display:flex;flex-direction:column;gap:32px} |
||||
|
.card{background:#fff;border:1px solid #e5e5e5;box-shadow:0 2px 4px rgba(0,0,0,.15) inset; |
||||
|
padding:32px;border-radius:8px} |
||||
|
.card h3{font-size:24px;margin-bottom:24px} |
||||
|
|
||||
|
/* SSID rows */ |
||||
|
.ssid-row{display:grid;grid-template-columns:1fr 1fr 1fr 72px;gap:16px;margin-bottom:12px} |
||||
|
.ssid-row input,.ssid-row select{padding:6px 8px;font-size:16px;border:1px solid #aaa;border-radius:4px;width:100%} |
||||
|
.ssid-row button{padding:6px 10px;font-size:14px;background:#f1f1f1;border:1px solid #777;border-radius:4px;cursor:pointer} |
||||
|
|
||||
|
/* 3-column grids (Network / Server) */ |
||||
|
.grid-3-col{display:grid;grid-template-columns:180px 240px 120px;align-items:center;gap:16px} |
||||
|
.grid-3-col input{padding:6px 8px;font-size:16px;border:1px solid #aaa;border-radius:1px;width:100%} |
||||
|
|
||||
|
/* radio */ |
||||
|
.radio-group{display:flex;align-items:center;gap:24px} |
||||
|
.radio-label{display:inline-flex;align-items:center;gap:4px;cursor:pointer} |
||||
|
.radio-label input{margin:0} |
||||
|
|
||||
|
/* I/O */ |
||||
|
.io-top{display:grid;grid-template-columns:repeat(auto-fit,minmax(360px,1fr));gap:40px;margin-bottom:32px} |
||||
|
.io-bot{display:grid;grid-template-columns:repeat(auto-fit,minmax(360px,1fr));gap:40px} |
||||
|
.io-group h4{font-size:20px;font-weight:600;margin-bottom:16px;display:flex;align-items:center;gap:8px} |
||||
|
.io-group h4::before{content:"";width:8px;height:8px;background:#aaa;display:inline-block} |
||||
|
.io-fieldset{border:1px solid #bbb;padding:24px 32px;border-radius:4px;display:flex;flex-direction:column;gap:16px;width:100%} |
||||
|
.io-row{display:grid;grid-template-columns:120px 12px 1fr;align-items:center;gap:8px} |
||||
|
.io-row input,.io-row select{padding:4px 6px;border:1px solid #aaa;border-radius:4px;font-size:14px;width:100%} |
||||
|
|
||||
|
/* 비활성 input 시각화 */ |
||||
|
.disabled{background:#f5f5f5;cursor:not-allowed} |
||||
|
|
||||
|
/* Footer Buttons */ |
||||
|
.actions{display:flex;gap:24px;justify-content:center} |
||||
|
.actions button{min-width:140px;padding:10px 18px;font-size:16px;border:1px solid #bbb;background:#d9d9d9;border-radius:4px;cursor:pointer} |
||||
|
</style> |
||||
|
</head> |
||||
|
<body> |
||||
|
<!-- ───── Sidebar ───── --> |
||||
|
<aside class="sidebar"> |
||||
|
<h2>Configuration</h2> |
||||
|
<details class="nav" open> |
||||
|
<summary>Device configuration</summary> |
||||
|
<div class="nav-items"> |
||||
|
<button data-page="ssid">SSID</button> |
||||
|
<button data-page="network">Network & Server</button> |
||||
|
<button data-page="io">I/O</button> |
||||
|
</div> |
||||
|
</details> |
||||
|
<details class="nav"> |
||||
|
<summary>Register configuration</summary> |
||||
|
<div class="nav-items"><button data-page="reg">Config</button></div> |
||||
|
</details> |
||||
|
</aside> |
||||
|
|
||||
|
<!-- ───── Content ───── --> |
||||
|
<div class="content"> |
||||
|
<header class="topbar" id="page-title">SSID</header> |
||||
|
<main class="board"> |
||||
|
|
||||
|
<!-- ▽ SSID PAGE ▽ --> |
||||
|
<section id="page-ssid" class="page"> |
||||
|
<div class="card"> |
||||
|
<h3>SSID List</h3> |
||||
|
|
||||
|
<template id="ssid-template"> |
||||
|
<div class="ssid-row"> |
||||
|
<input class="ssid-name" placeholder="Name" /> |
||||
|
<input class="ssid-pw" type="password" placeholder="Password" /> |
||||
|
<select> |
||||
|
<option value="none">NONE</option> |
||||
|
<option value="wpa/wpa2">WPA/WPA2</option> |
||||
|
</select> |
||||
|
<button type="button" class="toggle-pw">show</button> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<div id="ssid-list"></div> |
||||
|
<button id="add-ssid" style="margin-top:12px">Add SSID</button> |
||||
|
</div> |
||||
|
</section> |
||||
|
|
||||
|
<!-- ▽ NETWORK PAGE ▽ --> |
||||
|
<section id="page-network" class="page" style="display:none"> |
||||
|
<div class="card" style="margin-bottom:32px"> |
||||
|
<h3>Network</h3> |
||||
|
<div class="grid-3-col" style="margin-bottom:16px"> |
||||
|
<div class="radio-group"> |
||||
|
<label class="radio-label"><input type="radio" name="ipMode" value="static"> Static</label> |
||||
|
<label class="radio-label"><input type="radio" name="ipMode" value="dhcp"> DHCP</label> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<div class="grid-3-col"><span>IP</span><input id="wifi_ip" placeholder="000.000.000.000" /></div> |
||||
|
<div class="grid-3-col"><span>SUBNET</span><input id="wifi_netmask" placeholder="255.255.255.0" /></div> |
||||
|
<div class="grid-3-col"><span>GATEWAY</span><input id="wifi_gateway" placeholder="000.000.000.001" /></div> |
||||
|
<div class="grid-3-col"><span>DNS #1</span><input id="wifi_dns1" placeholder="008.008.008.008" /></div> |
||||
|
<div class="grid-3-col"><span>DNS #2</span><input id="wifi_dns2" placeholder="008.008.004.004" /></div> |
||||
|
</div> |
||||
|
|
||||
|
<div class="card"> |
||||
|
<h3>Server</h3> |
||||
|
<div class="grid-3-col"><strong></strong><span style="text-align:center">IP</span><span style="text-align:center">Port</span></div> |
||||
|
<div class="grid-3-col"><span>TIoT Server</span> <input id="protocol_server_ip"/><input id="protocol_server_port"/></div> |
||||
|
<div class="grid-3-col"><span>Update Server</span><input id="update_server_ip" /><input id="update_server_port" /></div> |
||||
|
<div class="grid-3-col"><span>DGPS Server</span> <input id="rtcm_server_ip" /><input id="rtcm_server_port" /></div> |
||||
|
<div class="grid-3-col"><span>OPC-UA</span> <input id="opc_ua_server_ip" /><input id="opc_ua_server_port"/></div> |
||||
|
</div> |
||||
|
</section> |
||||
|
|
||||
|
<!-- ▽ I/O PAGE ▽ --> |
||||
|
<section id="page-io" class="page" style="display:none"> |
||||
|
<div class="card"> |
||||
|
<div class="io-top"> |
||||
|
<!-- Ethernet --> |
||||
|
<div class="io-group"> |
||||
|
<h4>Ethernet</h4> |
||||
|
<div class="io-fieldset"> |
||||
|
<div class="io-row"><span>IP</span><span>:</span><input id="eth_ip"></div> |
||||
|
<div class="io-row"><span>SUBNET</span><span>:</span><input id="eth_netmask"></div> |
||||
|
<div class="io-row"><span>GATEWAY</span><span>:</span><input id="eth_gateway"></div> |
||||
|
<div class="io-row"><span>SERVER IP</span><span>:</span><input id="protocol_server_ip"></div> |
||||
|
<div class="io-row"><span>SERVER PORT</span><span>:</span><input id="protocol_server_port"></div> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<!-- LTE --> |
||||
|
<div class="io-group"> |
||||
|
<h4>LTE</h4> |
||||
|
<div class="io-fieldset"> |
||||
|
<div class="io-row"><span>IP</span><span>:</span><input id="lte_ip"></div> |
||||
|
<div class="io-row"><span>SUBNET</span><span>:</span><input id="lte_netmask"></div> |
||||
|
<div class="io-row"><span>GATEWAY</span><span>:</span><input id="lte_gateway"></div> |
||||
|
<div class="io-row"><span>Port</span><span>:</span><input id="lte_port"></div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<div class="io-bot"> |
||||
|
<!-- RS-485 --> |
||||
|
<div class="io-group"> |
||||
|
<h4>MODBUS 422 / 485</h4> |
||||
|
<div class="io-row"><span>Mode</span><span>:</span> |
||||
|
<select id="rs485_mode"> |
||||
|
<option value="half">half</option> |
||||
|
<option value="full">full</option> |
||||
|
</select> |
||||
|
</div> |
||||
|
<div class="io-row"><span>Speed</span><span>:</span><input id="rs485_baudrate"></div> |
||||
|
<div class="io-row"><span>Parity</span><span>:</span><input id="rs485_parity"></div> |
||||
|
</div> |
||||
|
|
||||
|
<!-- CAN --> |
||||
|
<div class="io-group"> |
||||
|
<h4>CAN</h4> |
||||
|
<div class="io-row"><span>Type</span><span>:</span> |
||||
|
<select id="can_bus_type"> |
||||
|
<option value="extended">extended</option> |
||||
|
<option value="standard">standard</option> |
||||
|
</select> |
||||
|
</div> |
||||
|
<div class="io-row"><span>Speed</span><span>:</span><input id="can_baudrate"></div> |
||||
|
</div> |
||||
|
|
||||
|
<!-- IMU --> |
||||
|
<div class="io-group"> |
||||
|
<h4>IMU Re-map</h4> |
||||
|
<div class="io-row"><span>X</span><span>:</span> |
||||
|
<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>Y</span><span>:</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>Z</span><span>:</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> |
||||
|
</section> |
||||
|
|
||||
|
<!-- ▽ Register PAGE (placeholder) ▽ --> |
||||
|
<section id="page-reg" class="page" style="display:none"> |
||||
|
<div class="card"><h3>Register Config (준비중)</h3></div> |
||||
|
</section> |
||||
|
|
||||
|
<!-- 공통 액션 버튼 --> |
||||
|
<div class="actions"> |
||||
|
<button id="load-local">Load Local File</button> |
||||
|
<button id="save-local">Save Local File</button> |
||||
|
<button id="save-device">Save to Device</button> |
||||
|
</div> |
||||
|
</main> |
||||
|
</div> |
||||
|
|
||||
|
<!-- ───── Script ───── --> |
||||
|
<script> |
||||
|
/* ───────────── 1. 기본 데이터 구조 ───────────── */ |
||||
|
const data = { |
||||
|
/* Wi-Fi */ |
||||
|
wifi_static : 'off', wifi_ip:'', wifi_netmask:'', wifi_gateway:'', wifi_dns1:'', wifi_dns2:'', |
||||
|
|
||||
|
/* Ethernet */ |
||||
|
eth_ip:'', eth_netmask:'', eth_gateway:'', |
||||
|
|
||||
|
/* 서버들 */ |
||||
|
protocol_server_ip:'', protocol_server_port:null, |
||||
|
update_server_ip :'', |
||||
|
update_server_port:null, |
||||
|
rtcm_server_ip :'', |
||||
|
rtcm_server_port :null, |
||||
|
opc_ua_server_ip :'', |
||||
|
opc_ua_server_port:null, |
||||
|
modbus_server_ip :'', |
||||
|
modbus_server_port:null, |
||||
|
|
||||
|
/* CAN / RS-485 */ |
||||
|
can_bus_type:'', can_baudrate:null, |
||||
|
rs485_mode:'', rs485_baudrate:null, rs485_databits:null, |
||||
|
rs485_parity:'', rs485_stopbits:null, |
||||
|
|
||||
|
/* IMU (축 + 부호) */ |
||||
|
imu_remap_x:'', imu_remap_y:'', imu_remap_z:'', |
||||
|
imu_remap_x_sign:'', imu_remap_y_sign:'', imu_remap_z_sign:'', |
||||
|
|
||||
|
/* SSID 목록 */ |
||||
|
WIFI_SSID:[{wifi_ssid:'',wifi_password:'',wifi_security:'none'}] |
||||
|
}; |
||||
|
|
||||
|
/* ───────────── 2. 페이지 전환 ───────────── */ |
||||
|
const pages = { |
||||
|
ssid : document.getElementById('page-ssid'), |
||||
|
network: document.getElementById('page-network'), |
||||
|
io : document.getElementById('page-io'), |
||||
|
reg : document.getElementById('page-reg') |
||||
|
}; |
||||
|
const titleEl = document.getElementById('page-title'); |
||||
|
|
||||
|
document.querySelectorAll('.nav-items button').forEach(btn=>{ |
||||
|
btn.addEventListener('click',()=>{ |
||||
|
Object.values(pages).forEach(p=>p.style.display='none'); |
||||
|
pages[btn.dataset.page].style.display='block'; |
||||
|
titleEl.textContent = btn.textContent; |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
/* ───────────── 3. SSID 행 생성 / 수집 ───────────── */ |
||||
|
const ssidList = document.getElementById('ssid-list'); |
||||
|
const ssidTmpl = document.getElementById('ssid-template'); |
||||
|
|
||||
|
function createSsidRow(obj={wifi_ssid:'',wifi_password:'',wifi_security:'none'}){ |
||||
|
const node = ssidTmpl.content.firstElementChild.cloneNode(true); |
||||
|
node.querySelector('.ssid-name').value = obj.wifi_ssid ?? ''; |
||||
|
node.querySelector('.ssid-pw' ).value = obj.wifi_password ?? ''; |
||||
|
node.querySelector('select').value = (obj.wifi_security ?? 'none').toLowerCase(); |
||||
|
return node; |
||||
|
} |
||||
|
function addSsidRow(){ ssidList.appendChild(createSsidRow()); } |
||||
|
document.getElementById('add-ssid').addEventListener('click', addSsidRow); |
||||
|
|
||||
|
ssidList.addEventListener('click',e=>{ |
||||
|
if(e.target.classList.contains('toggle-pw')){ |
||||
|
const pw = e.target.closest('.ssid-row').querySelector('.ssid-pw'); |
||||
|
pw.type = pw.type==='password' ? 'text' : 'password'; |
||||
|
e.target.textContent = pw.type==='password' ? 'show' : 'hide'; |
||||
|
} |
||||
|
}); |
||||
|
function gatherSsidRows(){ |
||||
|
const arr=[]; |
||||
|
ssidList.querySelectorAll('.ssid-row').forEach(row=>{ |
||||
|
const ssid = row.querySelector('.ssid-name').value.trim(); |
||||
|
const pw = row.querySelector('.ssid-pw' ).value.trim(); |
||||
|
const sec = row.querySelector('select' ).value; |
||||
|
if(ssid) arr.push({wifi_ssid:ssid, wifi_password:pw, wifi_security:sec}); |
||||
|
}); |
||||
|
return arr.length ? arr : [{wifi_ssid:'',wifi_password:'',wifi_security:'none'}]; |
||||
|
} |
||||
|
|
||||
|
/* ───────────── 4. DHCP ↔ Static 전환 입력 잠금 ───────────── */ |
||||
|
const netFields = ['wifi_ip','wifi_netmask','wifi_gateway','wifi_dns1','wifi_dns2'] |
||||
|
.map(id=>document.getElementById(id)); |
||||
|
|
||||
|
function toggleNetInputs(){ |
||||
|
const isStatic = document.querySelector('input[name="ipMode"]:checked')?.value === 'static'; |
||||
|
netFields.forEach(el=>{ |
||||
|
el.disabled = !isStatic; |
||||
|
el.classList.toggle('disabled', !isStatic); |
||||
|
}); |
||||
|
} |
||||
|
document.querySelectorAll('input[name="ipMode"]').forEach(r=>r.addEventListener('change', toggleNetInputs)); |
||||
|
|
||||
|
/* ───────────── 5. IMU Re-map 보조 함수 ───────────── */ |
||||
|
function axisValueToPair(val){ |
||||
|
return val.startsWith('-') |
||||
|
? {axis:val.slice(1), sign:'minus'} |
||||
|
: {axis:val, sign:'plus'}; |
||||
|
} |
||||
|
function pairToAxisValue(axis, sign){ |
||||
|
return sign==='minus' ? `-${axis}` : axis; |
||||
|
} |
||||
|
|
||||
|
/* ───────────── 6. 데이터 → 화면 로딩 ───────────── */ |
||||
|
function loadFromData(obj){ |
||||
|
/* Wi-Fi 모드 radio */ |
||||
|
document.querySelector(`input[name="ipMode"][value="${obj.wifi_static==='on'?'static':'dhcp'}"]`).checked = true; |
||||
|
|
||||
|
/* 일반 input/select */ |
||||
|
for(const k in obj){ |
||||
|
const el = document.getElementById(k); |
||||
|
if(el) el.value = obj[k] ?? ''; |
||||
|
} |
||||
|
|
||||
|
/* IMU select 값 재구성 */ |
||||
|
['x','y','z'].forEach(a=>{ |
||||
|
const axis = obj[`imu_remap_${a}`] || 'x'; |
||||
|
const sign = obj[`imu_remap_${a}_sign`] || 'plus'; |
||||
|
document.getElementById(`imu_remap_${a}`).value = pairToAxisValue(axis, sign); |
||||
|
}); |
||||
|
|
||||
|
/* SSID */ |
||||
|
ssidList.innerHTML=''; |
||||
|
(obj.WIFI_SSID||[]).forEach(o=>ssidList.appendChild(createSsidRow(o))); |
||||
|
if(!ssidList.children.length) addSsidRow(); |
||||
|
|
||||
|
toggleNetInputs(); // 초기 잠금 상태 |
||||
|
} |
||||
|
loadFromData(data); |
||||
|
|
||||
|
/* ───────────── 7. 화면 → 데이터 수집 ───────────── */ |
||||
|
function collectData(){ |
||||
|
const res = {...data}; |
||||
|
|
||||
|
res.wifi_static = document.querySelector('input[name="ipMode"]:checked')?.value === 'static' |
||||
|
? 'on' : 'off'; |
||||
|
|
||||
|
/* 일반 input/select */ |
||||
|
for(const k in res){ |
||||
|
const el = document.getElementById(k); |
||||
|
if(el) res[k] = el.value.trim(); |
||||
|
} |
||||
|
|
||||
|
/* IMU select → 축·부호 분리 */ |
||||
|
['x','y','z'].forEach(a=>{ |
||||
|
const {axis, sign} = axisValueToPair(document.getElementById(`imu_remap_${a}`).value); |
||||
|
res[`imu_remap_${a}`] = axis; |
||||
|
res[`imu_remap_${a}_sign`] = sign; |
||||
|
}); |
||||
|
|
||||
|
/* SSID 배열 */ |
||||
|
res.WIFI_SSID = gatherSsidRows(); |
||||
|
return res; |
||||
|
} |
||||
|
|
||||
|
/* ───────────── 8. 저장 버튼 POST ───────────── */ |
||||
|
document.getElementById('save-device').addEventListener('click', ()=>{ |
||||
|
fetch('http://localhost:8080/setting/device',{ |
||||
|
method :'POST', |
||||
|
headers:{'Content-Type':'application/json'}, |
||||
|
body : JSON.stringify(collectData()) |
||||
|
}) |
||||
|
.then(()=>alert('전송 완료')) |
||||
|
.catch(console.error); |
||||
|
}); |
||||
|
</script> |
||||
|
</body> |
||||
|
</html> |
||||
Loading…
Reference in new issue