From f94f2b91e864d357e6ad14875691d56cdedf2071 Mon Sep 17 00:00:00 2001 From: huangping Date: Mon, 25 May 2026 00:59:12 +0800 Subject: [PATCH] feat: add M7 DeviceService and DTOs --- .../platform/api/service/DeviceService.java | 231 ++++++++++++++++++ .../api/web/dto/DeviceBindingResponse.java | 70 ++++++ .../api/web/dto/DeviceCreateRequest.java | 50 ++++ .../platform/api/web/dto/DeviceResponse.java | 124 ++++++++++ .../api/web/dto/DeviceSwapRequestDto.java | 50 ++++ 5 files changed, 525 insertions(+) create mode 100644 services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/service/DeviceService.java create mode 100644 services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/web/dto/DeviceBindingResponse.java create mode 100644 services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/web/dto/DeviceCreateRequest.java create mode 100644 services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/web/dto/DeviceResponse.java create mode 100644 services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/web/dto/DeviceSwapRequestDto.java diff --git a/services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/service/DeviceService.java b/services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/service/DeviceService.java new file mode 100644 index 0000000..5e008f1 --- /dev/null +++ b/services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/service/DeviceService.java @@ -0,0 +1,231 @@ +package cn.craftlabs.platform.api.service; + +import cn.craftlabs.platform.api.persistence.customer.PlatformCustomer; +import cn.craftlabs.platform.api.persistence.customer.PlatformCustomerMapper; +import cn.craftlabs.platform.api.persistence.device.PlatformDevice; +import cn.craftlabs.platform.api.persistence.device.PlatformDeviceMapper; +import cn.craftlabs.platform.api.persistence.device.PlatformDeviceSnBinding; +import cn.craftlabs.platform.api.persistence.device.PlatformDeviceSnBindingMapper; +import cn.craftlabs.platform.api.persistence.device.PlatformDeviceSwapRequest; +import cn.craftlabs.platform.api.persistence.device.PlatformDeviceSwapRequestMapper; +import cn.craftlabs.platform.api.persistence.license.PlatformLicenseSn; +import cn.craftlabs.platform.api.persistence.license.PlatformLicenseSnMapper; +import cn.craftlabs.platform.api.persistence.project.PlatformProject; +import cn.craftlabs.platform.api.persistence.project.PlatformProjectMapper; +import cn.craftlabs.platform.api.web.dto.DeviceBindingResponse; +import cn.craftlabs.platform.api.web.dto.DeviceCreateRequest; +import cn.craftlabs.platform.api.web.dto.DeviceResponse; +import cn.craftlabs.platform.api.web.dto.DeviceSwapRequestDto; +import cn.craftlabs.platform.api.web.dto.PageResponse; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.util.List; +import java.util.stream.Collectors; + +@Service +public class DeviceService { + + private final PlatformDeviceMapper deviceMapper; + private final PlatformDeviceSnBindingMapper bindingMapper; + private final PlatformDeviceSwapRequestMapper swapRequestMapper; + private final PlatformCustomerMapper customerMapper; + private final PlatformProjectMapper projectMapper; + private final PlatformLicenseSnMapper licenseSnMapper; + + public DeviceService( + PlatformDeviceMapper deviceMapper, + PlatformDeviceSnBindingMapper bindingMapper, + PlatformDeviceSwapRequestMapper swapRequestMapper, + PlatformCustomerMapper customerMapper, + PlatformProjectMapper projectMapper, + PlatformLicenseSnMapper licenseSnMapper) { + this.deviceMapper = deviceMapper; + this.bindingMapper = bindingMapper; + this.swapRequestMapper = swapRequestMapper; + this.customerMapper = customerMapper; + this.projectMapper = projectMapper; + this.licenseSnMapper = licenseSnMapper; + } + + @Transactional(readOnly = true) + public PageResponse listDevices(int page, int size, Long customerId, String site, String snCode) { + LambdaQueryWrapper q = + Wrappers.lambdaQuery(PlatformDevice.class) + .eq(customerId != null, PlatformDevice::getCustomerId, customerId) + .eq(site != null && !site.isEmpty(), PlatformDevice::getSite, site) + .orderByDesc(PlatformDevice::getId); + Page mpPage = new Page<>(page + 1L, size); + deviceMapper.selectPage(mpPage, q); + List content = + mpPage.getRecords().stream().map(this::toDeviceResponse).collect(Collectors.toList()); + return new PageResponse<>(content, mpPage.getTotal(), page, size); + } + + @Transactional(readOnly = true) + public DeviceResponse getDevice(Long id) { + PlatformDevice d = deviceMapper.selectById(id); + return d != null ? toDeviceResponse(d) : null; + } + + @Transactional + public DeviceResponse createDevice(DeviceCreateRequest request) { + OffsetDateTime now = OffsetDateTime.now(ZoneOffset.UTC); + PlatformDevice d = new PlatformDevice(); + d.setMid(request.getMid()); + d.setAlias(request.getAlias()); + d.setSite(request.getSite()); + d.setCustomerId(request.getCustomerId()); + d.setProjectId(request.getProjectId()); + d.setStatus("ONLINE"); + d.setFirstSeenAt(now); + d.setCreatedAt(now); + d.setUpdatedAt(now); + deviceMapper.insert(d); + return toDeviceResponse(d); + } + + @Transactional + public DeviceResponse updateDevice(Long id, DeviceCreateRequest request) { + PlatformDevice d = deviceMapper.selectById(id); + if (d == null) { + return null; + } + d.setMid(request.getMid()); + d.setAlias(request.getAlias()); + d.setSite(request.getSite()); + d.setCustomerId(request.getCustomerId()); + d.setProjectId(request.getProjectId()); + d.setUpdatedAt(OffsetDateTime.now(ZoneOffset.UTC)); + deviceMapper.updateById(d); + return toDeviceResponse(d); + } + + @Transactional(readOnly = true) + public List getBindings(Long deviceId) { + LambdaQueryWrapper q = + Wrappers.lambdaQuery(PlatformDeviceSnBinding.class) + .eq(PlatformDeviceSnBinding::getDeviceId, deviceId) + .orderByDesc(PlatformDeviceSnBinding::getBindAt); + return bindingMapper.selectList(q).stream() + .map(this::toBindingResponse) + .collect(Collectors.toList()); + } + + @Transactional + public void createSwapRequest(DeviceSwapRequestDto request) { + OffsetDateTime now = OffsetDateTime.now(ZoneOffset.UTC); + PlatformDeviceSwapRequest sr = new PlatformDeviceSwapRequest(); + sr.setOldDeviceId(request.getOldDeviceId()); + sr.setNewMid(request.getNewMid()); + sr.setSnId(request.getSnId()); + sr.setReason(request.getReason()); + sr.setStatus("PENDING"); + sr.setRemark(request.getRemark()); + sr.setCreatedAt(now); + swapRequestMapper.insert(sr); + } + + @Transactional + public void handleDeviceEvent(String mid, Long snId) { + OffsetDateTime now = OffsetDateTime.now(ZoneOffset.UTC); + LambdaQueryWrapper q = + Wrappers.lambdaQuery(PlatformDevice.class) + .eq(PlatformDevice::getMid, mid); + PlatformDevice device = deviceMapper.selectOne(q); + if (device == null) { + device = new PlatformDevice(); + device.setMid(mid); + device.setStatus("ONLINE"); + device.setFirstSeenAt(now); + device.setCreatedAt(now); + device.setUpdatedAt(now); + deviceMapper.insert(device); + } else { + device.setLastHeartbeatAt(now); + device.setUpdatedAt(now); + deviceMapper.updateById(device); + } + PlatformDeviceSnBinding binding = new PlatformDeviceSnBinding(); + binding.setDeviceId(device.getId()); + binding.setLicenseSnId(snId); + binding.setBindType("ACTIVATE"); + binding.setBindAt(now); + binding.setCreatedAt(now); + bindingMapper.insert(binding); + } + + private DeviceResponse toDeviceResponse(PlatformDevice d) { + DeviceResponse r = new DeviceResponse(); + r.setId(d.getId()); + r.setMid(d.getMid()); + r.setAlias(d.getAlias()); + r.setSite(d.getSite()); + r.setCustomerId(d.getCustomerId()); + r.setProjectId(d.getProjectId()); + r.setStatus(d.getStatus()); + r.setStatusLabel(statusLabel(d.getStatus())); + r.setFirstSeenAt(d.getFirstSeenAt()); + r.setLastHeartbeatAt(d.getLastHeartbeatAt()); + r.setCreatedAt(d.getCreatedAt()); + if (d.getCustomerId() != null) { + PlatformCustomer c = customerMapper.selectById(d.getCustomerId()); + if (c != null) { + r.setCustomerName(c.getName()); + } + } + if (d.getProjectId() != null) { + PlatformProject p = projectMapper.selectById(d.getProjectId()); + if (p != null) { + r.setProjectName(p.getName()); + } + } + return r; + } + + private DeviceBindingResponse toBindingResponse(PlatformDeviceSnBinding b) { + DeviceBindingResponse r = new DeviceBindingResponse(); + r.setId(b.getId()); + r.setLicenseSnId(b.getLicenseSnId()); + r.setBindType(b.getBindType()); + r.setBindTypeLabel(bindTypeLabel(b.getBindType())); + r.setBindAt(b.getBindAt()); + r.setRemark(b.getRemark()); + if (b.getLicenseSnId() != null) { + PlatformLicenseSn sn = licenseSnMapper.selectById(b.getLicenseSnId()); + if (sn != null) { + r.setSnCode(sn.getSnCode()); + } + } + return r; + } + + private static String statusLabel(String status) { + if (status == null) { + return "离线"; + } + switch (status) { + case "ONLINE": return "在线"; + case "OFFLINE": return "离线"; + case "RETIRED": return "已退役"; + default: return "离线"; + } + } + + private static String bindTypeLabel(String bindType) { + if (bindType == null) { + return ""; + } + switch (bindType) { + case "ACTIVATE": return "激活绑定"; + case "SWAP": return "换机"; + case "UNBIND": return "解绑"; + default: return ""; + } + } +} diff --git a/services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/web/dto/DeviceBindingResponse.java b/services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/web/dto/DeviceBindingResponse.java new file mode 100644 index 0000000..fe956aa --- /dev/null +++ b/services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/web/dto/DeviceBindingResponse.java @@ -0,0 +1,70 @@ +package cn.craftlabs.platform.api.web.dto; + +import java.time.OffsetDateTime; + +public class DeviceBindingResponse { + + private Long id; + private Long licenseSnId; + private String snCode; + private String bindType; + private String bindTypeLabel; + private OffsetDateTime bindAt; + private String remark; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getLicenseSnId() { + return licenseSnId; + } + + public void setLicenseSnId(Long licenseSnId) { + this.licenseSnId = licenseSnId; + } + + public String getSnCode() { + return snCode; + } + + public void setSnCode(String snCode) { + this.snCode = snCode; + } + + public String getBindType() { + return bindType; + } + + public void setBindType(String bindType) { + this.bindType = bindType; + } + + public String getBindTypeLabel() { + return bindTypeLabel; + } + + public void setBindTypeLabel(String bindTypeLabel) { + this.bindTypeLabel = bindTypeLabel; + } + + public OffsetDateTime getBindAt() { + return bindAt; + } + + public void setBindAt(OffsetDateTime bindAt) { + this.bindAt = bindAt; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } +} diff --git a/services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/web/dto/DeviceCreateRequest.java b/services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/web/dto/DeviceCreateRequest.java new file mode 100644 index 0000000..9de1f2c --- /dev/null +++ b/services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/web/dto/DeviceCreateRequest.java @@ -0,0 +1,50 @@ +package cn.craftlabs.platform.api.web.dto; + +public class DeviceCreateRequest { + + private String mid; + private String alias; + private String site; + private Long customerId; + private Long projectId; + + public String getMid() { + return mid; + } + + public void setMid(String mid) { + this.mid = mid; + } + + public String getAlias() { + return alias; + } + + public void setAlias(String alias) { + this.alias = alias; + } + + public String getSite() { + return site; + } + + public void setSite(String site) { + this.site = site; + } + + public Long getCustomerId() { + return customerId; + } + + public void setCustomerId(Long customerId) { + this.customerId = customerId; + } + + public Long getProjectId() { + return projectId; + } + + public void setProjectId(Long projectId) { + this.projectId = projectId; + } +} diff --git a/services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/web/dto/DeviceResponse.java b/services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/web/dto/DeviceResponse.java new file mode 100644 index 0000000..85f2aa8 --- /dev/null +++ b/services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/web/dto/DeviceResponse.java @@ -0,0 +1,124 @@ +package cn.craftlabs.platform.api.web.dto; + +import java.time.OffsetDateTime; + +public class DeviceResponse { + + private Long id; + private String mid; + private String alias; + private String site; + private Long customerId; + private String customerName; + private Long projectId; + private String projectName; + private String status; + private String statusLabel; + private OffsetDateTime firstSeenAt; + private OffsetDateTime lastHeartbeatAt; + private OffsetDateTime createdAt; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getMid() { + return mid; + } + + public void setMid(String mid) { + this.mid = mid; + } + + public String getAlias() { + return alias; + } + + public void setAlias(String alias) { + this.alias = alias; + } + + public String getSite() { + return site; + } + + public void setSite(String site) { + this.site = site; + } + + public Long getCustomerId() { + return customerId; + } + + public void setCustomerId(Long customerId) { + this.customerId = customerId; + } + + public String getCustomerName() { + return customerName; + } + + public void setCustomerName(String customerName) { + this.customerName = customerName; + } + + public Long getProjectId() { + return projectId; + } + + public void setProjectId(Long projectId) { + this.projectId = projectId; + } + + public String getProjectName() { + return projectName; + } + + public void setProjectName(String projectName) { + this.projectName = projectName; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getStatusLabel() { + return statusLabel; + } + + public void setStatusLabel(String statusLabel) { + this.statusLabel = statusLabel; + } + + public OffsetDateTime getFirstSeenAt() { + return firstSeenAt; + } + + public void setFirstSeenAt(OffsetDateTime firstSeenAt) { + this.firstSeenAt = firstSeenAt; + } + + public OffsetDateTime getLastHeartbeatAt() { + return lastHeartbeatAt; + } + + public void setLastHeartbeatAt(OffsetDateTime lastHeartbeatAt) { + this.lastHeartbeatAt = lastHeartbeatAt; + } + + public OffsetDateTime getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(OffsetDateTime createdAt) { + this.createdAt = createdAt; + } +} diff --git a/services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/web/dto/DeviceSwapRequestDto.java b/services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/web/dto/DeviceSwapRequestDto.java new file mode 100644 index 0000000..f137dfd --- /dev/null +++ b/services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/web/dto/DeviceSwapRequestDto.java @@ -0,0 +1,50 @@ +package cn.craftlabs.platform.api.web.dto; + +public class DeviceSwapRequestDto { + + private Long oldDeviceId; + private String newMid; + private Long snId; + private String reason; + private String remark; + + public Long getOldDeviceId() { + return oldDeviceId; + } + + public void setOldDeviceId(Long oldDeviceId) { + this.oldDeviceId = oldDeviceId; + } + + public String getNewMid() { + return newMid; + } + + public void setNewMid(String newMid) { + this.newMid = newMid; + } + + public Long getSnId() { + return snId; + } + + public void setSnId(Long snId) { + this.snId = snId; + } + + public String getReason() { + return reason; + } + + public void setReason(String reason) { + this.reason = reason; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } +}