Browse Source

프론트 버튼 ux 구현, 버그 수정

v2
원형 1 year ago
parent
commit
598dc3a4f8
  1. 8
      src/main/java/org/mobidgim/mobidigimproject/controller/Controller.java
  2. 2
      src/main/java/org/mobidgim/mobidigimproject/model/device/subDTO/CanBus.java
  3. 2
      src/main/java/org/mobidgim/mobidigimproject/model/device/subDTO/Ethernet.java
  4. 2
      src/main/java/org/mobidgim/mobidigimproject/model/device/subDTO/Imu.java
  5. 7
      src/main/java/org/mobidgim/mobidigimproject/model/device/subDTO/Lte.java
  6. 6
      src/main/java/org/mobidgim/mobidigimproject/model/device/subDTO/Rs485.java
  7. 12
      src/main/java/org/mobidgim/mobidigimproject/model/device/subDTO/Server.java
  8. 2
      src/main/java/org/mobidgim/mobidigimproject/model/device/subDTO/Wifi.java
  9. 6
      src/main/java/org/mobidgim/mobidigimproject/model/device/subDTO/WifiSSIDS.java
  10. 14
      src/main/java/org/mobidgim/mobidigimproject/service/SettingService.java
  11. 85
      src/main/resources/static/index.html
  12. 86
      src/main/resources/static/style.css

8
src/main/java/org/mobidgim/mobidigimproject/controller/Controller.java

@ -12,6 +12,14 @@ import java.io.IOException;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@RestController
@RequestMapping("/setting")

2
src/main/java/org/mobidgim/mobidigimproject/model/device/subDTO/CanBus.java

@ -1,6 +1,7 @@
package org.mobidgim.mobidigimproject.model.device.subDTO;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Getter;
import lombok.Setter;
import org.mobidgim.mobidigimproject.model.device.enums.CanBusType;
@ -8,6 +9,7 @@ import org.mobidgim.mobidigimproject.model.device.enums.CanSpeed;
@Getter
@Setter
@JsonInclude(JsonInclude.Include.NON_NULL)
public class CanBus {
private CanBusType canBusType;
private CanSpeed canBaudrate;

2
src/main/java/org/mobidgim/mobidigimproject/model/device/subDTO/Ethernet.java

@ -1,10 +1,12 @@
package org.mobidgim.mobidigimproject.model.device.subDTO;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Ethernet {
private String ethIp;
private String ethNetmask;

2
src/main/java/org/mobidgim/mobidigimproject/model/device/subDTO/Imu.java

@ -1,5 +1,6 @@
package org.mobidgim.mobidigimproject.model.device.subDTO;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.Setter;
@ -8,6 +9,7 @@ import org.mobidgim.mobidigimproject.model.device.enums.ImuRemapSign;
@Getter
@Setter
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Imu {
@JsonProperty("imu_remap_x")
private ImuRemap imuRemapX;

7
src/main/java/org/mobidgim/mobidigimproject/model/device/subDTO/Lte.java

@ -1,7 +1,14 @@
package org.mobidgim.mobidigimproject.model.device.subDTO;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Lte {
@JsonProperty("lte_ip")
private String LTEip;

6
src/main/java/org/mobidgim/mobidigimproject/model/device/subDTO/Rs485.java

@ -1,5 +1,6 @@
package org.mobidgim.mobidigimproject.model.device.subDTO;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Getter;
import lombok.Setter;
import org.mobidgim.mobidigimproject.model.device.enums.Rs485Parity;
@ -8,15 +9,16 @@ import org.mobidgim.mobidigimproject.model.device.enums.Rs485Mode;
@Getter
@Setter
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Rs485 {
private Rs485Mode rs485Mode;
private Rs485Baudrate rs485Baudrate;
private int rs485DataBits;
private Integer rs485DataBits;
private Rs485Parity rs485Parity;
private int rs485StopBits;
private Integer rs485StopBits;
}

12
src/main/java/org/mobidgim/mobidigimproject/model/device/subDTO/Server.java

@ -1,18 +1,20 @@
package org.mobidgim.mobidigimproject.model.device.subDTO;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.*;
@Getter
@Setter
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Server {
private String protocolServerIp;
private int protocolServerPort;
private Integer protocolServerPort;
private String updateServerIp;
private int updateServerPort;
private Integer updateServerPort;
private String rtcmServerIp;
private int rtcmServerPort;
private Integer rtcmServerPort;
private String opcUaServerIp;
private int opcUaServerPort;
private Integer opcUaServerPort;
private String modbusServerIp;
private int modbusServerPort;
private Integer modbusServerPort;
}

2
src/main/java/org/mobidgim/mobidigimproject/model/device/subDTO/Wifi.java

@ -1,11 +1,13 @@
package org.mobidgim.mobidigimproject.model.device.subDTO;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Getter;
import lombok.Setter;
import org.mobidgim.mobidigimproject.model.device.enums.WifiStatic;
@Getter
@Setter
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Wifi {
private WifiStatic wifiStatic;
private String wifiIp;

6
src/main/java/org/mobidgim/mobidigimproject/model/device/WifiSSIDS.java → src/main/java/org/mobidgim/mobidigimproject/model/device/subDTO/WifiSSIDS.java

@ -1,13 +1,13 @@
package org.mobidgim.mobidigimproject.model.device;
package org.mobidgim.mobidigimproject.model.device.subDTO;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonValue;
import lombok.Data;
import org.mobidgim.mobidigimproject.model.device.enums.WiFiSecurity;
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class WifiSSIDS {

14
src/main/java/org/mobidgim/mobidigimproject/service/SettingService.java

@ -1,6 +1,7 @@
package org.mobidgim.mobidigimproject.service;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
@ -8,22 +9,14 @@ import org.mobidgim.mobidigimproject.model.device.DeviceDTO;
import org.mobidgim.mobidigimproject.model.register.RegisterDTO;
import org.mobidgim.mobidigimproject.model.register.enums.CanInput;
import org.mobidgim.mobidigimproject.model.register.enums.Protocol;
import org.mobidgim.mobidigimproject.model.register.sebDTO.CanField;
import org.mobidgim.mobidigimproject.model.register.sebDTO.ModbusField;
import org.mobidgim.mobidigimproject.model.register.sebDTO.OpcUaField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.swing.text.html.parser.Parser;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@Service
public class SettingService {
@ -37,9 +30,9 @@ public class SettingService {
}
public void saveFileWithDevice(DeviceDTO request) throws IOException {
mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(request);
String directoryPath = "./temp";
@ -49,7 +42,6 @@ public class SettingService {
Files.createDirectory(dirPath);
}
String filename = "./temp/deviceConfig.json";
Files.writeString(Paths.get(filename), json);
}

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

@ -54,8 +54,7 @@
</template>
<div id="ssid-list"></div>
<button id="add-ssid" class="icon-button" title="SSID 추가"></button>
<button id="delete-ssid" class="icon-button" title="SSID 삭제"></button>
<button id="add-ssid" class="icon-button" title="add SSID"></button>
</div>
<div class="actions">
<div class="file-upload-wrapper-device"
@ -66,7 +65,7 @@
<input type="file" class="upload-input-device" accept=".json" style="display: none;">
<button class="select-file-btn-device">Load Local Device File</button>
</div>
<button class="download-device-file">Download Device File</button>
<button class="download-device-file">Download Local Device File</button>
</div>
</section>
@ -93,15 +92,15 @@
<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
<div class="grid-3-col"><span>TIoT Server</span> <input id="protocol_server_ip" placeholder="ex)123.123.123.123"/><input
id="protocol_server_port"/></div>
<div class="grid-3-col"><span>Update Server</span><input id="update_server_ip"/><input
<div class="grid-3-col"><span>Update Server</span><input id="update_server_ip" placeholder="ex)123.123.123.123"/><input
id="update_server_port"/></div>
<div class="grid-3-col"><span>DGPS Server</span> <input id="rtcm_server_ip"/><input
<div class="grid-3-col"><span>DGPS Server</span> <input id="rtcm_server_ip" placeholder="ex)123.123.123.123"/><input
id="rtcm_server_port"/></div>
<div class="grid-3-col"><span>OPC-UA</span> <input id="opc_ua_server_ip"/><input
<div class="grid-3-col"><span>OPC-UA</span> <input id="opc_ua_server_ip" placeholder="ex)123.123.123.123"/><input
id="opc_ua_server_port"/></div>
<div class="grid-3-col"><span>MODBUS</span> <input id="modbus_server_ip"/><input
<div class="grid-3-col"><span>MODBUS</span> <input id="modbus_server_ip" placeholder="ex)123.123.123.123"/><input
id="modbus_server_port"/></div>
</div>
<div class="actions">
@ -113,7 +112,7 @@
<input type="file" class="upload-input-device" accept=".json" style="display: none;">
<button class="select-file-btn-device">Load Local Device File</button>
</div>
<button class="download-device-file">Download Device File</button>
<button class="download-device-file">Download Local Device File</button>
</div>
</section>
@ -140,12 +139,12 @@
<div class="io-fieldset">
<div class="io-row"><span class="label-inline">IP</span><span class="colon">:</span><input
id="lte_ip"></div>
<div class="io-row"><span class="label-inline">PORT</span><span class="colon">:</span><input
id="lte_port"></div>
<div class="io-row"><span class="label-inline">NETMASK</span><span
class="colon">:</span><input id="lte_netmask"></div>
<div class="io-row"><span class="label-inline">GATEWAY</span><span
class="colon">:</span><input id="lte_gateway"></div>
<div class="io-row"><span class="label-inline">PORT</span><span class="colon">:</span><input
id="lte_port"></div>
</div>
</div>
</div>
@ -245,7 +244,7 @@
<input type="file" class="upload-input-device" accept=".json" style="display: none;">
<button class="select-file-btn-device">Load Local Device File</button>
</div>
<button class="download-device-file">Download Device File</button>
<button class="download-device-file">Download Local Device File</button>
</div>
</section>
@ -394,7 +393,7 @@
<input type="file" class="upload-input-protocol" accept=".json" style="display: none;">
<button class="select-file-btn-protocol">Load Local Protocol File</button>
</div>
<button class="download-protocol-file">Download Device File</button>
<button class="download-protocol-file">Download Local Protocol File</button>
</div>
</section>
@ -482,7 +481,7 @@
<input type="file" class="upload-input-protocol" accept=".json" style="display: none;">
<button class="select-file-btn-protocol">Load Local Protocol File</button>
</div>
<button class="download-protocol-file">Download Device File</button>
<button class="download-protocol-file">Download Local Protocol File</button>
</div>
</section>
@ -563,7 +562,7 @@
<input type="file" class="upload-input-protocol" accept=".json" style="display: none;">
<button class="select-file-btn-protocol">Load Local Protocol File</button>
</div>
<button class="download-protocol-file">Download Device File</button>
<button class="download-protocol-file">Download Local Protocol File</button>
</div>
</section>
@ -653,7 +652,7 @@
const ssidTmpl = document.getElementById('ssid-template');
const data = {
/* Wi-Fi */
wifi_static: 'off', wifi_ip: '', wifi_netmask: '', wifi_gateway: '', wifi_dns1: '', wifi_dns2: '',
wifi_static: '', wifi_ip: '', wifi_netmask: '', wifi_gateway: '', wifi_dns1: '', wifi_dns2: '',
/* Ethernet */
eth_ip: '', eth_netmask: '', eth_gateway: '',
@ -1257,18 +1256,6 @@
//ssid 행 추가 버튼
document.getElementById('add-ssid').addEventListener('click', addSsidRow);
//ssid 행 삭제 버튼
document.getElementById('delete-ssid').addEventListener('click', () => {
if (ssidList.children.length > 1) {
ssidList.removeChild(ssidList.lastElementChild);
} else if (ssidList.children.length === 1) {
const firstRow = ssidList.firstElementChild;
firstRow.querySelector('.ssid-name').value = '';
firstRow.querySelector('.ssid-pw').value = '';
firstRow.querySelector('select').value = 'none';
}
})
/*-----device input데이터 받는 함수------*/
function collectDeviceData() {
const res = { ...data };
@ -1276,12 +1263,10 @@
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) {
const val = el.value.trim();
// can_baudrate, rs485_baudrate는 숫자 or null
if (['can_baudrate', 'rs485_baudrate'].includes(k)) {
res[k] = val === '' ? null : Number(val);
} else {
@ -1289,18 +1274,27 @@
}
}
}
// IMU select → 축·부호 분리
//x,y,z,부호 처리
['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;
//null, 공백 없이 데이터 전처리
const filtered = {};
for (const [k, v] of Object.entries(res)) {
if (
v !== null &&
!(typeof v === 'string' && v.trim() === '')
) {
filtered[k] = v;
}
}
return filtered;
}
/*-----------------------------------------------------*/
@ -1495,15 +1489,26 @@
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();
const deleteBtn = document.createElement('button');
deleteBtn.textContent = '➖';
deleteBtn.dataset.action = 'delete-ssid';
deleteBtn.title = 'delete ssid';
deleteBtn.classList.add('delete-ssid');
node.appendChild(deleteBtn);
return node;
}
/*-----------------------------------------------------*/
/*-------ssid 데이터 리스트 추가 함수-----------*/
/*-------ssid password 숨김 함수-----------*/
function addSsidRow() {
ssidList.appendChild(createSsidRow());
}
function removeSsidRow(row) {
row.remove();
}
ssidList.addEventListener('click', e => {
if (e.target.classList.contains('toggle-pw')) {
const pw = e.target.closest('.ssid-row').querySelector('.ssid-pw');
@ -1525,9 +1530,10 @@
const ssid = row.querySelector('.ssid-name').value.trim();
const pw = row.querySelector('.ssid-pw').value.trim();
const sec = row.querySelector('select').value;
if (ssid === '' && pw === '') return;
if (ssid) arr.push({wifi_ssid: ssid, wifi_password: pw, wifi_security: sec});
});
return arr.length ? arr : [{wifi_ssid: '', wifi_password: '', wifi_security: 'none'}];
return arr
}
/*-----------------------------------------------------*/
@ -1717,6 +1723,7 @@
/*-------imu-remap 정수와 부호 분리 함수-------------*/
function axisValueToPair(val) {
if (!val || val === '') return { axis: '', sign: '' };
return val.startsWith('-')
? { axis: val.slice(1), sign: 'minus' }
: { axis: val, sign: 'plus' };
@ -1740,8 +1747,8 @@
/* IMU select 값 재구성 */
['x', 'y', 'z'].forEach(a => {
const axis = obj[`imu_remap_${a}`] || 'x';
const sign = obj[`imu_remap_${a}_sign`] || 'plus';
const axis = obj[`imu_remap_${a}`] || '';
const sign = obj[`imu_remap_${a}_sign`] || '';
document.getElementById(`imu_remap_${a}`).value = pairToAxisValue(axis, sign);
});

86
src/main/resources/static/style.css

@ -91,18 +91,62 @@ details.nav {
/* SSID rows */
.ssid-row {
display: grid;
grid-template-columns:220px 220px 60px 120px;
gap: 16px;
margin-bottom: 12px
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 8px;
}
.ssid-row input.ssid-name,
.ssid-row input.ssid-pw {
width: 200px;
padding: 6px 8px;
font-size: 16px;
border: 1px solid #aaa;
border-radius: 4px;
}
.ssid-row input, .ssid-row select {
.ssid-row .toggle-pw {
padding: 6px 10px;
font-size: 14px;
border: 1px solid #aaa;
background-color: #eee;
border-radius: 4px;
cursor: pointer;
min-width: 60px;
text-align: center;
}
.ssid-row .toggle-pw:hover {
background-color: #cecece;
}
.ssid-row .toggle-pw:active {
background-color: #bdbdbd;
transform: scale(0.97);
}
.ssid-row select {
width: 100px;
padding: 6px 8px;
font-size: 16px;
border: 1px solid #aaa;
border-radius: 4px;
width: 100%
}
.ssid-row .delete-ssid {
padding: 6px 10px;
font-size: 14px;
background-color: #ffdddd;
border: 1px solid #aaa;
border-radius: 4px;
cursor: pointer;
}
.ssid-row .delete-ssid:hover {
background-color: #ffaaaa;
}
.ssid-row .delete-ssid:active{
background-color: #fd9e9e;
transform: scale(0.97);
}
.icon-button {
@ -123,8 +167,25 @@ details.nav {
background-color: #c0c0c0;
}
/* 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%}
.grid-3-col {
display: grid;
grid-template-columns: 180px 220px 100px; /* SSID와 유사하게 축소 */
align-items: center;
gap: 12px;
margin: 8px 0;
}
.grid-3-col input {
padding: 6px 8px;
font-size: 16px;
border: 1px solid #aaa;
border-radius: 4px; /* 기존 1px → 4px 통일 */
width: 100%; /* grid item 내에서만 퍼지므로 유지 가능 */
}
.grid-3-col input::placeholder {
color: #999;
}
/* radio */
.radio-group {display: flex;align-items: center;gap: 24px}
@ -158,6 +219,8 @@ details.nav {
/* Footer Buttons */
.actions {display: flex;gap: 24px;justify-content: center;padding: 20px}
.actions button {min-width: 140px;padding: 10px 18px;font-size: 16px;border: 1px solid #bbb;background: #d9d9d9;border-radius: 4px;cursor: pointer}
.actions button:hover {background-color: #bdbdbd;}
.actions button:active {background-color: #bdbdbd; transform: scale(0.97);}
.config-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;}
.config-actions button{min-width:140px;padding:10px 18px;font-size:16px;border:1px solid #bbb;background:#d9d9d9;border-radius:4px;cursor:pointer}
.topbar {
@ -181,6 +244,13 @@ details.nav {
border-radius: 4px;
cursor: pointer;
}
.save-file:hover {
background-color: #45a049;;
}
.save-file:active {
background-color: #3e8e41;
transform: scale(0.97);
}
/* 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;}

Loading…
Cancel
Save