diff --git a/fys-admin/src/main/java/com/fuyuanshen/DromaraApplication.java b/fys-admin/src/main/java/com/fuyuanshen/DromaraApplication.java index ca41060..999701d 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/DromaraApplication.java +++ b/fys-admin/src/main/java/com/fuyuanshen/DromaraApplication.java @@ -1,24 +1,24 @@ -package com.fuyuanshen; + package com.fuyuanshen; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup; -import org.springframework.scheduling.annotation.EnableScheduling; + import org.springframework.boot.SpringApplication; + import org.springframework.boot.autoconfigure.SpringBootApplication; + import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup; + import org.springframework.scheduling.annotation.EnableScheduling; -/** - * 启动程序 - * - * @author Lion Li - */ -@SpringBootApplication -@EnableScheduling -public class DromaraApplication { + /** + * 启动程序 + * + * @author Lion Li + */ + @SpringBootApplication + @EnableScheduling + public class DromaraApplication { + + public static void main(String[] args) { + SpringApplication application = new SpringApplication(DromaraApplication.class); + application.setApplicationStartup(new BufferingApplicationStartup(2048)); + application.run(args); + System.out.println("(♥◠‿◠)ノ゙ fys-Vue-Plus启动成功 ლ(´ڡ`ლ)゙"); + } - public static void main(String[] args) { - SpringApplication application = new SpringApplication(DromaraApplication.class); - application.setApplicationStartup(new BufferingApplicationStartup(2048)); - application.run(args); - System.out.println("(♥◠‿◠)ノ゙ fys-Vue-Plus启动成功 ლ(´ڡ`ლ)゙"); } - -} diff --git a/fys-admin/src/main/java/com/fuyuanshen/app/controller/AppAuthController.java b/fys-admin/src/main/java/com/fuyuanshen/app/controller/AppAuthController.java index 0cd57e2..7be1be8 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/app/controller/AppAuthController.java +++ b/fys-admin/src/main/java/com/fuyuanshen/app/controller/AppAuthController.java @@ -72,10 +72,8 @@ public class AppAuthController { private final AppLoginService loginService; private final AppRegisterService registerService; - private final ISysConfigService configService; private final ISysTenantService tenantService; private final ISysClientService clientService; - private final ISysDictTypeService dictTypeService; /** diff --git a/fys-admin/src/main/java/com/fuyuanshen/app/controller/AppDeviceController.java b/fys-admin/src/main/java/com/fuyuanshen/app/controller/AppDeviceController.java index 402244e..02976bf 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/app/controller/AppDeviceController.java +++ b/fys-admin/src/main/java/com/fuyuanshen/app/controller/AppDeviceController.java @@ -92,4 +92,5 @@ public class AppDeviceController extends BaseController { public R getDeviceInfo(String deviceMac) { return R.ok(appDeviceService.getDeviceInfo(deviceMac)); } + } diff --git a/fys-admin/src/main/java/com/fuyuanshen/app/controller/AppDeviceShareController.java b/fys-admin/src/main/java/com/fuyuanshen/app/controller/AppDeviceShareController.java index 388c84f..9cb4249 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/app/controller/AppDeviceShareController.java +++ b/fys-admin/src/main/java/com/fuyuanshen/app/controller/AppDeviceShareController.java @@ -44,10 +44,9 @@ import static com.fuyuanshen.common.core.constant.GlobalConstants.DEVICE_SHARE_C @RequestMapping("/app/deviceShare") public class AppDeviceShareController extends BaseController { - private final IAppDeviceShareService deviceShareService; - private final AppDeviceShareService appDeviceShareService; + /** * 分享管理列表 */ @@ -95,6 +94,7 @@ public class AppDeviceShareController extends BaseController { return toAjax(appDeviceShareService.remove(ids)); } + /** * 短信验证码 * @@ -116,4 +116,5 @@ public class AppDeviceShareController extends BaseController { } return R.ok(); } + } diff --git a/fys-admin/src/main/java/com/fuyuanshen/app/controller/AppFileController.java b/fys-admin/src/main/java/com/fuyuanshen/app/controller/AppFileController.java index 6c23621..012887f 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/app/controller/AppFileController.java +++ b/fys-admin/src/main/java/com/fuyuanshen/app/controller/AppFileController.java @@ -25,6 +25,7 @@ public class AppFileController extends BaseController { private final AppFileService appFileService; + /** * 查询文件列表 */ @@ -33,6 +34,7 @@ public class AppFileController extends BaseController { return R.ok(appFileService.list(bo)); } + /** * 上传文件 */ @@ -52,4 +54,5 @@ public class AppFileController extends BaseController { } return toAjax(appFileService.delete(ids)); } + } diff --git a/fys-admin/src/main/java/com/fuyuanshen/app/controller/AppOperationVideoController.java b/fys-admin/src/main/java/com/fuyuanshen/app/controller/AppOperationVideoController.java index c695db7..5338ba2 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/app/controller/AppOperationVideoController.java +++ b/fys-admin/src/main/java/com/fuyuanshen/app/controller/AppOperationVideoController.java @@ -25,6 +25,7 @@ public class AppOperationVideoController extends BaseController { private final IAppOperationVideoService appOperationVideoService; + /** * 查询操作视频列表 */ @@ -68,4 +69,5 @@ public class AppOperationVideoController extends BaseController { public R deleteOperationVideo(@PathVariable Long id) { return toAjax(appOperationVideoService.deleteWithValidByIds(List.of(id), true)); } + } diff --git a/fys-admin/src/main/java/com/fuyuanshen/app/controller/AppVideoController.java b/fys-admin/src/main/java/com/fuyuanshen/app/controller/AppVideoController.java index 11bc754..f48a1a0 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/app/controller/AppVideoController.java +++ b/fys-admin/src/main/java/com/fuyuanshen/app/controller/AppVideoController.java @@ -1,5 +1,6 @@ package com.fuyuanshen.app.controller; +import cn.dev33.satoken.annotation.SaIgnore; import com.fuyuanshen.app.service.AudioProcessService; import com.fuyuanshen.app.service.VideoProcessService; import com.fuyuanshen.common.core.domain.R; @@ -51,4 +52,13 @@ public class AppVideoController extends BaseController { public R> uploadAudioTTS(@RequestParam String text) throws IOException { return R.ok(audioProcessService.generateStandardPcmData(text)); } + + /** + * 提取文本内容(只支持txt/docx) + */ + @PostMapping(value = "/extract", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + @RepeatSubmit(interval = 2, timeUnit = TimeUnit.SECONDS,message = "请勿重复提交!") + public R extract(@RequestParam("file") MultipartFile file) throws Exception { + return R.ok("Success",audioProcessService.extract(file)); + } } diff --git a/fys-admin/src/main/java/com/fuyuanshen/app/controller/device/TestController.java b/fys-admin/src/main/java/com/fuyuanshen/app/controller/device/TestController.java index a9afd17..fbb84cd 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/app/controller/device/TestController.java +++ b/fys-admin/src/main/java/com/fuyuanshen/app/controller/device/TestController.java @@ -28,6 +28,7 @@ public class TestController extends BaseController { private final DeviceBJQBizService appDeviceService; + /** * 上传设备logo图片 */ diff --git a/fys-admin/src/main/java/com/fuyuanshen/app/controller/device/bjq/AppDeviceBJQ6075Controller.java b/fys-admin/src/main/java/com/fuyuanshen/app/controller/device/bjq/AppDeviceBJQ6075Controller.java new file mode 100644 index 0000000..c3e9df3 --- /dev/null +++ b/fys-admin/src/main/java/com/fuyuanshen/app/controller/device/bjq/AppDeviceBJQ6075Controller.java @@ -0,0 +1,154 @@ +package com.fuyuanshen.app.controller.device.bjq; + +import com.fuyuanshen.app.domain.bo.AppPersonnelInfoBo; +import com.fuyuanshen.app.domain.dto.AppDeviceLogoUploadDto; +import com.fuyuanshen.app.domain.dto.DeviceInstructDto; +import com.fuyuanshen.app.domain.vo.AppDevice6075DetailVo; +import com.fuyuanshen.common.core.domain.R; +import com.fuyuanshen.common.core.validate.AddGroup; +import com.fuyuanshen.common.ratelimiter.annotation.FunctionAccessAnnotation; +import com.fuyuanshen.common.ratelimiter.annotation.FunctionAccessBatcAnnotation; +import com.fuyuanshen.common.web.core.BaseController; +import com.fuyuanshen.equipment.domain.dto.AppDeviceSendMsgBo; +import com.fuyuanshen.web.service.device.DeviceBJQ6075BizService; +import com.fuyuanshen.web.service.device.DeviceBJQBizService; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +/** + * BJQ6075 设备控制类 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/app/bjq6075/device") +public class AppDeviceBJQ6075Controller extends BaseController { + + private final DeviceBJQBizService appDeviceService; + private final DeviceBJQ6075BizService appDeviceService6075; + + + /** + * 获取设备详细信息 + * + * @param id 主键 + */ + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(appDeviceService6075.getInfo(id)); + } + + + /** + * 人员信息登记 + */ + @PostMapping(value = "/registerPersonInfo") + public R registerPersonInfo(@Validated(AddGroup.class) @RequestBody AppPersonnelInfoBo bo) { + return toAjax(appDeviceService.registerPersonInfo(bo)); + } + + /** + * 发送信息 + */ + @PostMapping(value = "/sendMessage") + @FunctionAccessBatcAnnotation(value = "sendMessage", timeOut = 30, batchMaxTimeOut = 40) + public R sendMessage(@RequestBody AppDeviceSendMsgBo bo) { + return toAjax(appDeviceService.sendMessage(bo)); + } + + /** + * 发送报警信息 + */ + @PostMapping(value = "/sendAlarmMessage") + @FunctionAccessBatcAnnotation(value = "sendAlarmMessage", timeOut = 5, batchMaxTimeOut = 10) + public R sendAlarmMessage(@RequestBody AppDeviceSendMsgBo bo) { + return toAjax(appDeviceService.sendAlarmMessage(bo)); + } + + /** + * 上传设备logo图片 + */ + @PostMapping("/uploadLogo") + @FunctionAccessAnnotation("uploadLogo") + public R upload(@Validated @ModelAttribute AppDeviceLogoUploadDto bo) { + + MultipartFile file = bo.getFile(); + if (file.getSize() > 1024 * 1024 * 2) { + return R.warn("图片不能大于2M"); + } + appDeviceService.uploadDeviceLogo(bo); + + return R.ok(); + } + + /** + * 灯光模式 + * (主光模式) + * 0(关闭灯光),1(强光),2(超强光), 3(工作光), 4(节能光),5(爆闪),6(SOS) + */ + @PostMapping("/lightModeSettings") + public R lightModeSettings(@RequestBody DeviceInstructDto params) { + appDeviceService.lightModeSettings(params); + return R.ok(); + } + + + /** + * 灯光模式 + * (辅光模式) + * 0(关闭灯光),1(泛光),2(泛光爆闪), 3(警示灯), 4(警示灯/泛光) + */ + @PostMapping("/auxiliaryLightModeSettings") + public R auxiliaryLightModeSettings(@RequestBody DeviceInstructDto params) { + appDeviceService.lightModeSettings(params); + return R.ok(); + } + + + /** + * 灯光亮度设置 + */ + @PostMapping("/lightBrightnessSettings") + public R lightBrightnessSettings(@RequestBody DeviceInstructDto params) { + appDeviceService.lightBrightnessSettings(params); + return R.ok(); + } + + /** + * 激光模式设置 + */ + @PostMapping("/laserModeSettings") + public R laserModeSettings(@RequestBody DeviceInstructDto params) { + appDeviceService.laserModeSettings(params); + return R.ok(); + } + + + /** + * 声光报警模式设置 + * Sound and light alarm + */ + @PostMapping("/salaModeSettings") + public R salaModeSettings(@RequestBody DeviceInstructDto params) { + appDeviceService.laserModeSettings(params); + return R.ok(); + } + + + /** + * 获取设备分享详细信息 + * + * @param id 主键 + */ + @GetMapping("/getShareInfo/{id}") + public R getShareInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(appDeviceService6075.getInfo(id)); + } + + +} diff --git a/fys-admin/src/main/java/com/fuyuanshen/app/domain/dto/AppDeviceLogoUploadDto.java b/fys-admin/src/main/java/com/fuyuanshen/app/domain/dto/AppDeviceLogoUploadDto.java index 00ca2d2..669c13a 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/app/domain/dto/AppDeviceLogoUploadDto.java +++ b/fys-admin/src/main/java/com/fuyuanshen/app/domain/dto/AppDeviceLogoUploadDto.java @@ -11,8 +11,9 @@ public class AppDeviceLogoUploadDto { private Long deviceId; private String deviceImei; + /** - * 文件 + * 文件 */ private MultipartFile file; @@ -25,4 +26,5 @@ public class AppDeviceLogoUploadDto { private List deviceIds; private Integer chunkSize; + } diff --git a/fys-admin/src/main/java/com/fuyuanshen/app/domain/dto/DeviceInstructDto.java b/fys-admin/src/main/java/com/fuyuanshen/app/domain/dto/DeviceInstructDto.java index 074bed3..75fa57b 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/app/domain/dto/DeviceInstructDto.java +++ b/fys-admin/src/main/java/com/fuyuanshen/app/domain/dto/DeviceInstructDto.java @@ -8,9 +8,15 @@ public class DeviceInstructDto { private Long deviceId; private String deviceImei; + /** - * 下发指令 + * 下发指令 */ private String instructValue; + /** + * 下发指令类型 + */ + private String instructType; + } diff --git a/fys-admin/src/main/java/com/fuyuanshen/app/service/AudioProcessService.java b/fys-admin/src/main/java/com/fuyuanshen/app/service/AudioProcessService.java index a36e8f1..31c5ac3 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/app/service/AudioProcessService.java +++ b/fys-admin/src/main/java/com/fuyuanshen/app/service/AudioProcessService.java @@ -8,10 +8,19 @@ import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamConstants; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import java.io.*; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.util.Arrays; import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; /** * 音频处理服务 @@ -101,6 +110,12 @@ public class AudioProcessService { // log.info("测试文件已保存: {}", savedPath); // } + // 保存WAV文件到本地 + String savedPath = saveByteArrayToFile(pcmData, "tts_output.wav"); + if (savedPath != null) { + log.info("WAV文件已保存: {}", savedPath); + } + // 将byte[]转换为16进制字符串列表 List hexList = audioProcessUtil.bytesToHexList(pcmData); @@ -113,6 +128,55 @@ public class AudioProcessService { } } + public String saveWavFileLocally(String text, String filename) throws IOException { + // 参数校验 + if (text == null || text.trim().isEmpty()) { + throw new IllegalArgumentException("文本内容不能为空"); + } + + if (filename == null || filename.trim().isEmpty()) { + filename = "tts_output.wav"; // 默认文件名 + } + + try { + // 生成PCM数据 + byte[] rawPcmData = alibabaTTSUtil.generateStandardPcmData(text); + + // 转换为标准WAV格式(添加44字节头部) + byte[] wavData = audioProcessUtil.rawPcmToStandardWav(rawPcmData); + + // 保存到本地文件 + String filePath = saveByteArrayToFile(wavData, filename); + + log.info("WAV文件已保存: {}", filePath); + return filePath; + } catch (Exception e) { + log.error("保存WAV文件失败: {}", e.getMessage(), e); + throw new IOException("保存WAV文件失败", e); + } + } + + private String saveByteArrayToFile(byte[] data, String filename) throws IOException { + // 确定保存路径(可以是临时目录或指定目录) + String directory = System.getProperty("java.io.tmpdir"); // 使用系统临时目录 + File dir = new File(directory); + if (!dir.exists()) { + dir.mkdirs(); + } + + // 创建完整文件路径 + File file = new File(dir, filename); + + // 写入文件 + try (FileOutputStream fos = new FileOutputStream(file)) { + fos.write(data); + } + + return file.getAbsolutePath(); + } + + + /** * 验证音频文件 */ @@ -170,5 +234,75 @@ public class AudioProcessService { } } + /** + * 提取文本 + */ + public String extract(MultipartFile file) throws Exception { + String name = file.getOriginalFilename(); + if (name == null || + (!name.endsWith(".txt") && !name.endsWith(".docx"))) { + throw new IllegalArgumentException("仅支持 .txt 或 .docx"); + } + if (file.getSize() > MAX_AUDIO_SIZE) { + throw new IllegalArgumentException("文件超过5MB"); + } + + String text; + /* 全程流式,不落地磁盘,不一次性读字节数组 */ + try (InputStream in = file.getInputStream()) { + if (name.endsWith(".txt")) { + text = readTxt(in); + } else { + text = readDocx(in); + } + } + return text; + } + + /* ---------- txt:按行读,StringBuilder 复用 ---------- */ + private String readTxt(InputStream in) throws IOException { + BufferedReader br = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)); + StringBuilder sb = new StringBuilder(4096); + String line; + while ((line = br.readLine()) != null) { + sb.append(line).append('\n'); + } + return sb.toString(); + } + + /* ---------- docx:ZipInputStream 只扫 document.xml ---------- */ + private String readDocx(InputStream in) throws IOException { + ZipInputStream zin = new ZipInputStream(in); + ZipEntry e; + while ((e = zin.getNextEntry()) != null) { + if ("word/document.xml".equals(e.getName())) { + return staxExtract(zin); // 流式读 XML + } + } + return ""; + } + + /* ---------- StAX 流式提取 ---------- */ + private String staxExtract(InputStream xml) throws IOException { + XMLStreamReader r = null; + StringBuilder sb = new StringBuilder(4096); + try { + //System.out.println(new String(xml.readAllBytes())); + r = XMLInputFactory.newInstance().createXMLStreamReader(xml); + while (r.hasNext()) { + if (r.next() == XMLStreamConstants.START_ELEMENT && + "t".equals(r.getLocalName())) { + String elementText = r.getElementText(); + sb.append(elementText); + } + } + } catch (XMLStreamException ex) { + throw new IOException(ex); + } finally { + if (r != null) try { r.close(); } catch (XMLStreamException ignore) {} + } + return sb.toString(); + } + } \ No newline at end of file diff --git a/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/base/MqttRuleEngine.java b/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/base/MqttRuleEngine.java index b27d57a..0591470 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/base/MqttRuleEngine.java +++ b/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/base/MqttRuleEngine.java @@ -21,26 +21,31 @@ public class MqttRuleEngine { private ThreadPoolTaskExecutor threadPoolTaskExecutor; private final LinkedHashMap rulesMap = new LinkedHashMap<>(); + + public MqttRuleEngine(List rules) { // 按优先级排序 rules.sort(Comparator.comparing(MqttMessageRule::getPriority)); rules.forEach(rule -> rulesMap.put(rule.getCommandType(), rule) ); } - + + /** * 执行匹配 + * * @param context 处理上下文 * @return */ public boolean executeRule(MqttRuleContext context) { int commandType = context.getCommandType(); - MqttMessageRule mqttMessageRule = rulesMap.get("Light_"+commandType); + MqttMessageRule mqttMessageRule = rulesMap.get("Light_" + commandType); if (mqttMessageRule != null) { threadPoolTaskExecutor.execute(() -> mqttMessageRule.execute(context)); return true; } - + return false; } + } diff --git a/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/constants/MqttConstants.java b/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/constants/MqttConstants.java index 7a80a1e..6c9cd76 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/constants/MqttConstants.java +++ b/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/constants/MqttConstants.java @@ -3,7 +3,6 @@ package com.fuyuanshen.global.mqtt.constants; public interface MqttConstants { - /** * 全局发布消息的key */ @@ -13,4 +12,5 @@ public interface MqttConstants { * 全局订阅消息的key */ String GLOBAL_SUB_KEY = "A/"; + } diff --git a/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/receiver/DeviceMessageHandler.java b/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/receiver/DeviceMessageHandler.java new file mode 100644 index 0000000..75fcc07 --- /dev/null +++ b/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/receiver/DeviceMessageHandler.java @@ -0,0 +1,279 @@ +package com.fuyuanshen.global.mqtt.receiver; + +import cn.hutool.core.lang.Dict; +import com.fuyuanshen.common.core.constant.GlobalConstants; +import com.fuyuanshen.common.core.utils.ImageToCArrayConverter; +import com.fuyuanshen.common.json.utils.JsonUtils; +import com.fuyuanshen.common.redis.utils.RedisUtils; +import com.fuyuanshen.global.mqtt.base.MqttRuleContext; +import com.fuyuanshen.global.mqtt.base.MqttRuleEngine; +import com.fuyuanshen.global.mqtt.base.MqttXinghanCommandType; +import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants; +import com.fuyuanshen.global.queue.MqttMessageQueueConstants; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.messaging.Message; +import org.springframework.messaging.MessageHandler; +import org.springframework.messaging.MessageHeaders; +import org.springframework.messaging.MessagingException; +import org.springframework.stereotype.Service; + +import java.time.Duration; +import java.util.Objects; + +import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX; + +/** + * 6075 + * + * @author: 默苍璃 + * @date: 2025-11-05 17:41 + */ +@Service +@Slf4j +public class DeviceMessageHandler implements MessageHandler { + + @Autowired + private MqttRuleEngine ruleEngine; + + + @Override + public void handleMessage(Message message) throws MessagingException { + Object payload = message.getPayload(); + MessageHeaders headers = message.getHeaders(); + String receivedTopic = Objects.requireNonNull(headers.get("mqtt_receivedTopic")).toString(); + String receivedQos = Objects.requireNonNull(headers.get("mqtt_receivedQos")).toString(); + String timestamp = Objects.requireNonNull(headers.get("timestamp")).toString(); + + log.info("MQTT payload= {} \n receivedTopic = {} \n receivedQos = {} \n timestamp = {}", + payload, receivedTopic, receivedQos, timestamp); + + Dict payloadDict = JsonUtils.parseMap(payload.toString()); + if (receivedTopic == null || payloadDict == null) { + return; + } + + // 解析设备IMEI + String[] subStr = receivedTopic.split("/"); + String deviceImei = subStr[1]; + + // 处理设备在线状态 + handleDeviceOnlineStatus(deviceImei); + + // 处理不同类型的设备信息 + processDeviceInformation(payloadDict, deviceImei); + + // 执行规则引擎处理 + executeRuleEngine(payloadDict, deviceImei); + } + + + /** + * 处理设备在线状态 + */ + private void handleDeviceOnlineStatus(String deviceImei) { + if (StringUtils.isNotBlank(deviceImei)) { + // 添加去重队列 + String queueKey = MqttMessageQueueConstants.MQTT_MESSAGE_QUEUE_KEY; + String dedupKey = MqttMessageQueueConstants.MQTT_MESSAGE_DEDUP_KEY; + RedisUtils.offerDeduplicated(queueKey, dedupKey, deviceImei, Duration.ofSeconds(900)); + + // 设置设备在线状态 + String deviceOnlineStatusRedisKey = GlobalConstants.GLOBAL_REDIS_KEY + + DEVICE_KEY_PREFIX + deviceImei + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX; + RedisUtils.setCacheObject(deviceOnlineStatusRedisKey, "1", Duration.ofSeconds(360)); + } + } + + + /** + * 处理不同类型的设备信息 + */ + private void processDeviceInformation(Dict payloadDict, String deviceImei) { + // 开机画面 + if (payloadDict.containsKey("bootScreen")) { + handleBootScreen(payloadDict, deviceImei); + } + + // 人员信息 + if (payloadDict.containsKey("personInfo")) { + handlePersonInfo(payloadDict, deviceImei); + } + + // 设备信息 + if (payloadDict.containsKey("deviceInfo")) { + handleDeviceInfo(payloadDict, deviceImei); + } + + // 经纬度 + if (payloadDict.containsKey("latitude") && payloadDict.containsKey("longitude")) { + handleLocation(payloadDict, deviceImei); + } + + // 电子地图 + if (payloadDict.containsKey("mapData")) { + handleMapData(payloadDict, deviceImei); + } + + // 电池电量 + if (payloadDict.containsKey("batteryLevel")) { + handleBatteryLevel(payloadDict, deviceImei); + } + + // 开启/关闭状态 + if (payloadDict.containsKey("powerState")) { + handlePowerState(payloadDict, deviceImei); + } + + // 海拔高度 + if (payloadDict.containsKey("altitude")) { + handleAltitude(payloadDict, deviceImei); + } + + // 相对高度 + if (payloadDict.containsKey("relativeHeight")) { + handleRelativeHeight(payloadDict, deviceImei); + } + + // 群呼/单呼 + if (payloadDict.containsKey("callType")) { + handleCallType(payloadDict, deviceImei); + } + + // 文字信息 + if (payloadDict.containsKey("textMessage")) { + handleTextMessage(payloadDict, deviceImei); + } + } + + /** + * 处理开机画面 + */ + private void handleBootScreen(Dict payloadDict, String deviceImei) { + log.info("处理设备{}的开机画面信息", deviceImei); + // 实现具体的开机画面处理逻辑 + } + + /** + * 处理人员信息 + */ + private void handlePersonInfo(Dict payloadDict, String deviceImei) { + log.info("处理设备{}的人员信息", deviceImei); + // 实现具体的人员信息处理逻辑 + } + + /** + * 处理设备信息 + */ + private void handleDeviceInfo(Dict payloadDict, String deviceImei) { + log.info("处理设备{}的设备信息", deviceImei); + // 实现具体的设备信息处理逻辑 + } + + /** + * 处理位置信息 + */ + private void handleLocation(Dict payloadDict, String deviceImei) { + log.info("处理设备{}的位置信息: 纬度={}, 经度={}", + deviceImei, payloadDict.getStr("latitude"), payloadDict.getStr("longitude")); + // 实现具体的位置信息处理逻辑 + } + + /** + * 处理电子地图数据 + */ + private void handleMapData(Dict payloadDict, String deviceImei) { + log.info("处理设备{}的电子地图数据", deviceImei); + // 实现具体的电子地图数据处理逻辑 + } + + /** + * 处理电池电量 + */ + private void handleBatteryLevel(Dict payloadDict, String deviceImei) { + log.info("处理设备{}的电池电量: {}", deviceImei, payloadDict.getStr("batteryLevel")); + // 实现具体的电池电量处理逻辑 + } + + /** + * 处理开关状态 + */ + private void handlePowerState(Dict payloadDict, String deviceImei) { + String powerState = payloadDict.getStr("powerState"); + log.info("处理设备{}的开关状态: {}", deviceImei, powerState); + // 实现具体的开关状态处理逻辑 + } + + /** + * 处理海拔高度 + */ + private void handleAltitude(Dict payloadDict, String deviceImei) { + log.info("处理设备{}的海拔高度: {}", deviceImei, payloadDict.getStr("altitude")); + // 实现具体的海拔高度处理逻辑 + } + + /** + * 处理相对高度 + */ + private void handleRelativeHeight(Dict payloadDict, String deviceImei) { + log.info("处理设备{}的相对高度: {}", deviceImei, payloadDict.getStr("relativeHeight")); + // 实现具体的相对高度处理逻辑 + } + + /** + * 处理呼叫类型 + */ + private void handleCallType(Dict payloadDict, String deviceImei) { + String callType = payloadDict.getStr("callType"); + log.info("处理设备{}的呼叫类型: {}", deviceImei, callType); + // 实现具体的呼叫类型处理逻辑 + } + + /** + * 处理文字信息 + */ + private void handleTextMessage(Dict payloadDict, String deviceImei) { + String textMessage = payloadDict.getStr("textMessage"); + log.info("处理设备{}的文字信息: {}", deviceImei, textMessage); + // 实现具体的文字信息处理逻辑 + } + + /** + * 执行规则引擎处理 + */ + private void executeRuleEngine(Dict payloadDict, String deviceImei) { + String state = payloadDict.getStr("state"); + Object[] convertArr = ImageToCArrayConverter.convertByteStringToMixedObjectArray(state); + + if (convertArr.length > 0) { + Byte val1 = (Byte) convertArr[0]; + MqttRuleContext context = new MqttRuleContext(); + context.setCommandType(val1); + context.setConvertArr(convertArr); + context.setDeviceImei(deviceImei); + context.setPayloadDict(payloadDict); + + boolean ruleExecuted = ruleEngine.executeRule(context); + + if (!ruleExecuted) { + log.warn("未找到匹配的规则来处理命令类型: {}", val1); + } + } + + /* ===== 追加:根据报文内容识别格式并统一解析 ===== */ + int intType = MqttXinghanCommandType.computeVirtualCommandType(payloadDict); + if (intType > 0) { + MqttRuleContext newCtx = new MqttRuleContext(); + newCtx.setCommandType((byte) intType); + newCtx.setDeviceImei(deviceImei); + newCtx.setPayloadDict(payloadDict); + + boolean ok = ruleEngine.executeRule(newCtx); + if (!ok) { + log.warn("新规则引擎未命中, imei={}", deviceImei); + } + } + } + +} diff --git a/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/receiver/ReceiverMessageHandler.java b/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/receiver/ReceiverMessageHandler.java index 55f24c6..5b26612 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/receiver/ReceiverMessageHandler.java +++ b/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/receiver/ReceiverMessageHandler.java @@ -90,4 +90,5 @@ public class ReceiverMessageHandler implements MessageHandler { } } } + } diff --git a/fys-admin/src/main/java/com/fuyuanshen/mp/controller/MPAuthController.java b/fys-admin/src/main/java/com/fuyuanshen/mp/controller/MPAuthController.java index cec5b4a..fc04d02 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/mp/controller/MPAuthController.java +++ b/fys-admin/src/main/java/com/fuyuanshen/mp/controller/MPAuthController.java @@ -63,10 +63,6 @@ import java.util.Map; @RequestMapping("/mp") public class MPAuthController { - private final AppLoginService loginService; - private final SysRegisterService registerService; - private final ISysConfigService configService; - private final ISysTenantService tenantService; private final ISysClientService clientService; private final MPAuthService mpAuthService; private final MPService mpService; @@ -74,7 +70,7 @@ public class MPAuthController { @Operation(summary = "小程序登录授权") @PostMapping(value = "/login") - public ResponseEntity login(@RequestBody AuthUserDto authUser, HttpServletRequest request) throws Exception { + public ResponseEntity login(@RequestBody AuthUserDto authUser) throws Exception { Long phoneNumber = authUser.getPhoneNumber(); // 判断小程序用户是否存在,不存在创建 diff --git a/fys-admin/src/main/java/com/fuyuanshen/mp/service/MPAuthService.java b/fys-admin/src/main/java/com/fuyuanshen/mp/service/MPAuthService.java index 7ab05c3..c6a59be 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/mp/service/MPAuthService.java +++ b/fys-admin/src/main/java/com/fuyuanshen/mp/service/MPAuthService.java @@ -60,9 +60,9 @@ import java.util.function.Supplier; @Service public class MPAuthService { - private final ISysUserService userService; private final AppUserService appUserService; + /** * 小程序注册 */ @@ -128,6 +128,7 @@ public class MPAuthService { return loginVo; } + /** * 构建登录用户 */ @@ -160,5 +161,4 @@ public class MPAuthService { } - } diff --git a/fys-admin/src/main/java/com/fuyuanshen/mp/service/MPService.java b/fys-admin/src/main/java/com/fuyuanshen/mp/service/MPService.java index 720720f..0835eca 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/mp/service/MPService.java +++ b/fys-admin/src/main/java/com/fuyuanshen/mp/service/MPService.java @@ -10,11 +10,8 @@ import org.springframework.stereotype.Service; * * @author Lion Li */ - - public interface MPService { - /** * 获取小程序用户信息 * @@ -23,4 +20,5 @@ public interface MPService { UserApp getMpUser(Long phoneNumber); UserApp loadUserByUsername(String username); + } diff --git a/fys-admin/src/main/java/com/fuyuanshen/mp/service/impl/MPAuthServiceImpl.java b/fys-admin/src/main/java/com/fuyuanshen/mp/service/impl/MPAuthServiceImpl.java index 11a05e7..724294f 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/mp/service/impl/MPAuthServiceImpl.java +++ b/fys-admin/src/main/java/com/fuyuanshen/mp/service/impl/MPAuthServiceImpl.java @@ -8,5 +8,4 @@ package com.fuyuanshen.mp.service.impl; public class MPAuthServiceImpl { - } diff --git a/fys-admin/src/main/java/com/fuyuanshen/mp/service/impl/MPServiceImpl.java b/fys-admin/src/main/java/com/fuyuanshen/mp/service/impl/MPServiceImpl.java index 0506314..80b2214 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/mp/service/impl/MPServiceImpl.java +++ b/fys-admin/src/main/java/com/fuyuanshen/mp/service/impl/MPServiceImpl.java @@ -19,11 +19,9 @@ import org.springframework.stereotype.Service; @RequiredArgsConstructor public class MPServiceImpl implements MPService { - private final AppUserService appUserService; - /** * 获取小程序用户信息 * diff --git a/fys-admin/src/main/java/com/fuyuanshen/web/controller/CaptchaController.java b/fys-admin/src/main/java/com/fuyuanshen/web/controller/CaptchaController.java index 30d7106..c0d9c39 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/web/controller/CaptchaController.java +++ b/fys-admin/src/main/java/com/fuyuanshen/web/controller/CaptchaController.java @@ -51,6 +51,7 @@ public class CaptchaController { private final CaptchaProperties captchaProperties; private final MailProperties mailProperties; + /** * 短信验证码 * diff --git a/fys-admin/src/main/java/com/fuyuanshen/web/controller/device/DeviceBJQController.java b/fys-admin/src/main/java/com/fuyuanshen/web/controller/device/DeviceBJQController.java index 610c317..c5c4bd5 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/web/controller/device/DeviceBJQController.java +++ b/fys-admin/src/main/java/com/fuyuanshen/web/controller/device/DeviceBJQController.java @@ -28,6 +28,7 @@ public class DeviceBJQController extends BaseController { private final DeviceBJQBizService appDeviceService; + /** * 获取设备详细信息 * @@ -35,10 +36,11 @@ public class DeviceBJQController extends BaseController { */ @GetMapping("/{id}") public R getInfo(@NotNull(message = "主键不能为空") - @PathVariable Long id) { + @PathVariable Long id) { return R.ok(appDeviceService.getInfo(id)); } + /** * 人员信息登记 */ @@ -74,7 +76,7 @@ public class DeviceBJQController extends BaseController { public R upload(@Validated @ModelAttribute AppDeviceLogoUploadDto bo) { MultipartFile file = bo.getFile(); - if(file.getSize()>1024*1024*2){ + if (file.getSize() > 1024 * 1024 * 2) { return R.warn("图片不能大于2M"); } appDeviceService.uploadDeviceLogo(bo); @@ -90,7 +92,7 @@ public class DeviceBJQController extends BaseController { public R batchUploadLogo(@Validated @ModelAttribute AppDeviceLogoUploadDto bo) { MultipartFile file = bo.getFile(); - if(file.getSize()>1024*1024*2){ + if (file.getSize() > 1024 * 1024 * 2) { return R.warn("图片不能大于2M"); } appDeviceService.batchUploadLogo(bo); @@ -112,7 +114,6 @@ public class DeviceBJQController extends BaseController { /** * 灯光亮度设置 - * */ // @FunctionAccessAnnotation("lightBrightnessSettings") @PostMapping("/lightBrightnessSettings") @@ -123,7 +124,6 @@ public class DeviceBJQController extends BaseController { /** * 激光模式设置 - * */ @PostMapping("/laserModeSettings") // @FunctionAccessAnnotation("laserModeSettings") diff --git a/fys-admin/src/main/java/com/fuyuanshen/web/controller/device/DeviceControlCenterController.java b/fys-admin/src/main/java/com/fuyuanshen/web/controller/device/DeviceControlCenterController.java index 64f395e..2b1b2ee 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/web/controller/device/DeviceControlCenterController.java +++ b/fys-admin/src/main/java/com/fuyuanshen/web/controller/device/DeviceControlCenterController.java @@ -29,7 +29,7 @@ import java.util.Map; @RestController @RequiredArgsConstructor @RequestMapping("/api/device") -public class DeviceControlCenterController extends BaseController { +public class DeviceControlCenterController extends BaseController { private final DeviceBizService appDeviceService; @@ -42,6 +42,7 @@ public class DeviceControlCenterController extends BaseController { return appDeviceService.queryWebDeviceList(bo, pageQuery); } + /** * 绑定设备 */ @@ -59,6 +60,7 @@ public class DeviceControlCenterController extends BaseController { return toAjax(appDeviceService.unBindDevice(id)); } + /** * 查询设备类型列表 */ @@ -68,6 +70,7 @@ public class DeviceControlCenterController extends BaseController { return R.ok(typeList); } + /** * 重命名设备 * @@ -100,7 +103,7 @@ public class DeviceControlCenterController extends BaseController { */ @GetMapping("/instructionRecord") public TableDataInfo getInstructionRecord(InstructionRecordDto dto, PageQuery pageQuery) { - return appDeviceService.getInstructionRecord(dto,pageQuery); + return appDeviceService.getInstructionRecord(dto, pageQuery); } /** @@ -111,7 +114,7 @@ public class DeviceControlCenterController extends BaseController { pageQuery.setPageNum(1); pageQuery.setPageSize(2000); TableDataInfo instructionRecord = appDeviceService.getInstructionRecord(dto, pageQuery); - if(instructionRecord.getRows() == null){ + if (instructionRecord.getRows() == null) { return; } ExcelUtil.exportExcel(instructionRecord.getRows(), "设备操作日志", InstructionRecordVo.class, response); @@ -123,7 +126,7 @@ public class DeviceControlCenterController extends BaseController { */ @GetMapping("/locationHistory") public TableDataInfo getLocationHistory(InstructionRecordDto dto, PageQuery pageQuery) { - return appDeviceService.getLocationHistory(dto,pageQuery); + return appDeviceService.getLocationHistory(dto, pageQuery); } /** @@ -134,7 +137,7 @@ public class DeviceControlCenterController extends BaseController { pageQuery.setPageNum(1); pageQuery.setPageSize(2000); TableDataInfo result = appDeviceService.getLocationHistory(dto, pageQuery); - if(result.getRows() == null){ + if (result.getRows() == null) { return; } ExcelUtil.exportExcel(result.getRows(), "历史轨迹记录", LocationHistoryVo.class, response); @@ -147,4 +150,5 @@ public class DeviceControlCenterController extends BaseController { public R> getLocationHistoryDetail(Long id) { return R.ok(appDeviceService.getLocationHistoryDetail(id)); } + } diff --git a/fys-admin/src/main/java/com/fuyuanshen/web/controller/device/DeviceXinghanController.java b/fys-admin/src/main/java/com/fuyuanshen/web/controller/device/DeviceXinghanController.java index 5e95b70..7ab4f90 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/web/controller/device/DeviceXinghanController.java +++ b/fys-admin/src/main/java/com/fuyuanshen/web/controller/device/DeviceXinghanController.java @@ -160,4 +160,5 @@ public class DeviceXinghanController extends BaseController { RedisUtils.setCacheObject(versionKey, json, Duration.ofDays(30)); return R.ok(); } + } diff --git a/fys-admin/src/main/java/com/fuyuanshen/web/controller/device/bjq/DeviceBJQ6075Controller.java b/fys-admin/src/main/java/com/fuyuanshen/web/controller/device/bjq/DeviceBJQ6075Controller.java new file mode 100644 index 0000000..40a648c --- /dev/null +++ b/fys-admin/src/main/java/com/fuyuanshen/web/controller/device/bjq/DeviceBJQ6075Controller.java @@ -0,0 +1,140 @@ +package com.fuyuanshen.web.controller.device.bjq; + +import com.fuyuanshen.app.domain.bo.AppPersonnelInfoBo; +import com.fuyuanshen.app.domain.dto.AppDeviceLogoUploadDto; +import com.fuyuanshen.app.domain.dto.DeviceInstructDto; +import com.fuyuanshen.app.domain.vo.AppDeviceDetailVo; +import com.fuyuanshen.common.core.domain.R; +import com.fuyuanshen.common.core.validate.AddGroup; +import com.fuyuanshen.common.ratelimiter.annotation.FunctionAccessAnnotation; +import com.fuyuanshen.common.ratelimiter.annotation.FunctionAccessBatcAnnotation; +import com.fuyuanshen.common.web.core.BaseController; +import com.fuyuanshen.equipment.domain.dto.AppDeviceSendMsgBo; +import com.fuyuanshen.web.service.device.DeviceBJQBizService; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +/** + * web后台:设备控制类 + * 6075 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/api/bjq6075/device") +public class DeviceBJQ6075Controller extends BaseController { + + private final DeviceBJQBizService appDeviceService; + + + /** + * 获取设备详细信息 + * + * @param id 主键 + */ + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(appDeviceService.getInfo(id)); + } + + + /** + * 人员信息登记 + */ + @PostMapping(value = "/registerPersonInfo") +// @FunctionAccessAnnotation("registerPersonInfo") + public R registerPersonInfo(@Validated(AddGroup.class) @RequestBody AppPersonnelInfoBo bo) { + return toAjax(appDeviceService.registerPersonInfo(bo)); + } + + + /** + * 发送信息 + */ + @PostMapping(value = "/sendMessage") + @FunctionAccessBatcAnnotation(value = "sendMessage", timeOut = 30, batchMaxTimeOut = 40) + public R sendMessage(@RequestBody AppDeviceSendMsgBo bo) { + return toAjax(appDeviceService.sendMessage(bo)); + } + + + /** + * 发送报警信息 + */ + @PostMapping(value = "/sendAlarmMessage") + @FunctionAccessBatcAnnotation(value = "sendAlarmMessage", timeOut = 5, batchMaxTimeOut = 10) + public R sendAlarmMessage(@RequestBody AppDeviceSendMsgBo bo) { + return toAjax(appDeviceService.sendAlarmMessage(bo)); + } + + + /** + * 上传设备logo图片 + */ + @PostMapping("/uploadLogo") + @FunctionAccessAnnotation("uploadLogo") + public R upload(@Validated @ModelAttribute AppDeviceLogoUploadDto bo) { + + MultipartFile file = bo.getFile(); + if (file.getSize() > 1024 * 1024 * 2) { + return R.warn("图片不能大于2M"); + } + appDeviceService.uploadDeviceLogo(bo); + + return R.ok(); + } + + + /** + * 批量上传设备logo图片 + */ + @PostMapping("/batchUploadLogo") + @FunctionAccessAnnotation("batchUploadLogo") + public R batchUploadLogo(@Validated @ModelAttribute AppDeviceLogoUploadDto bo) { + + MultipartFile file = bo.getFile(); + if (file.getSize() > 1024 * 1024 * 2) { + return R.warn("图片不能大于2M"); + } + appDeviceService.batchUploadLogo(bo); + + return R.ok(); + } + + /** + * 灯光模式 + * 0(关灯),1(强光模式),2(弱光模式), 3(爆闪模式), 4(泛光模式) + */ +// @FunctionAccessAnnotation("lightModeSettings") + @PostMapping("/lightModeSettings") + public R lightModeSettings(@RequestBody DeviceInstructDto params) { + // params 转 JSONObject + appDeviceService.lightModeSettings(params); + return R.ok(); + } + + /** + * 灯光亮度设置 + */ +// @FunctionAccessAnnotation("lightBrightnessSettings") + @PostMapping("/lightBrightnessSettings") + public R lightBrightnessSettings(@RequestBody DeviceInstructDto params) { + appDeviceService.lightBrightnessSettings(params); + return R.ok(); + } + + /** + * 激光模式设置 + */ + @PostMapping("/laserModeSettings") +// @FunctionAccessAnnotation("laserModeSettings") + public R laserModeSettings(@RequestBody DeviceInstructDto params) { + appDeviceService.laserModeSettings(params); + return R.ok(); + } + +} diff --git a/fys-admin/src/main/java/com/fuyuanshen/web/service/device/DeviceBJQ6075BizService.java b/fys-admin/src/main/java/com/fuyuanshen/web/service/device/DeviceBJQ6075BizService.java new file mode 100644 index 0000000..2e1de5e --- /dev/null +++ b/fys-admin/src/main/java/com/fuyuanshen/web/service/device/DeviceBJQ6075BizService.java @@ -0,0 +1,102 @@ +package com.fuyuanshen.web.service.device; + +import cn.hutool.core.bean.BeanUtil; +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import com.fuyuanshen.app.domain.AppPersonnelInfo; +import com.fuyuanshen.app.domain.AppPersonnelInfoRecords; +import com.fuyuanshen.app.domain.bo.AppPersonnelInfoBo; +import com.fuyuanshen.app.domain.dto.AppDeviceLogoUploadDto; +import com.fuyuanshen.app.domain.dto.DeviceInstructDto; +import com.fuyuanshen.app.domain.vo.AppDevice6075DetailVo; +import com.fuyuanshen.app.domain.vo.AppDeviceDetailVo; +import com.fuyuanshen.app.domain.vo.AppPersonnelInfoVo; +import com.fuyuanshen.app.mapper.AppPersonnelInfoMapper; +import com.fuyuanshen.app.mapper.AppPersonnelInfoRecordsMapper; +import com.fuyuanshen.common.core.constant.GlobalConstants; +import com.fuyuanshen.common.core.exception.ServiceException; +import com.fuyuanshen.common.core.utils.*; +import com.fuyuanshen.common.redis.utils.RedisUtils; +import com.fuyuanshen.common.satoken.utils.AppLoginHelper; +import com.fuyuanshen.equipment.domain.Device; +import com.fuyuanshen.equipment.domain.DeviceType; +import com.fuyuanshen.equipment.domain.dto.AppDeviceSendMsgBo; +import com.fuyuanshen.equipment.enums.LightModeEnum; +import com.fuyuanshen.equipment.mapper.DeviceLogMapper; +import com.fuyuanshen.equipment.mapper.DeviceMapper; +import com.fuyuanshen.equipment.mapper.DeviceTypeMapper; +import com.fuyuanshen.global.mqtt.config.MqttGateway; +import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants; +import com.fuyuanshen.global.mqtt.constants.MqttConstants; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.io.ClassPathResource; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.io.InputStream; +import java.time.Duration; +import java.util.*; + +import static com.fuyuanshen.common.core.constant.GlobalConstants.GLOBAL_REDIS_KEY; +import static com.fuyuanshen.common.core.utils.Bitmap80x12Generator.buildArr; +import static com.fuyuanshen.common.core.utils.Bitmap80x12Generator.generateFixedBitmapData; +import static com.fuyuanshen.common.core.utils.ImageToCArrayConverter.convertHexToDecimal; +import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.*; + + +@Service +public interface DeviceBJQ6075BizService { + + /** + * 获取设备详情 + * + * @param id 设备ID + * @return 设备详情 + */ + public AppDevice6075DetailVo getInfo(Long id); + + public int sendMessage(AppDeviceSendMsgBo bo); + + /** + * 记录设备操作日志 + * + * @param deviceId 设备ID + * @param content 日志内容 + * @param operator 操作人 + */ + public void recordDeviceLog(Long deviceId, String deviceName, String deviceAction, String content, Long operator); + + + public boolean registerPersonInfo(AppPersonnelInfoBo bo); + + public void uploadDeviceLogo2(AppDeviceLogoUploadDto bo); + + public void uploadDeviceLogo(AppDeviceLogoUploadDto bo); + + /** + * 灯光模式 + * 0(关灯),1(强光模式),2(弱光模式), 3(爆闪模式), 4(泛光模式) + */ + + public void lightModeSettings(DeviceInstructDto params); + + // 灯光亮度设置 + public void lightBrightnessSettings(DeviceInstructDto params); + + // 激光模式设置 + public void laserModeSettings(DeviceInstructDto params); + + public String mapReverseGeocoding(DeviceInstructDto params); + + public int sendAlarmMessage(AppDeviceSendMsgBo bo); + + public void messageSending(String deviceImei); + + public boolean getDeviceStatus(String deviceImei); + + public void batchUploadLogo(AppDeviceLogoUploadDto bo); + +} diff --git a/fys-admin/src/main/java/com/fuyuanshen/web/service/device/DeviceBJQBizService.java b/fys-admin/src/main/java/com/fuyuanshen/web/service/device/DeviceBJQBizService.java index fdd2099..03d2c98 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/web/service/device/DeviceBJQBizService.java +++ b/fys-admin/src/main/java/com/fuyuanshen/web/service/device/DeviceBJQBizService.java @@ -69,8 +69,8 @@ public class DeviceBJQBizService { if (device == null) { throw new ServiceException("设备不存在" + deviceId); } - if(getDeviceStatus(device.getDeviceImei())){ - throw new ServiceException(device.getDeviceName()+",设备已断开连接"); + if (getDeviceStatus(device.getDeviceImei())) { + throw new ServiceException(device.getDeviceName() + ",设备已断开连接"); } try { ClassPathResource resource = new ClassPathResource("image/background.png"); @@ -78,26 +78,26 @@ public class DeviceBJQBizService { byte[] largeData = ImageWithTextGenerate.generate160x80ImageWithText2(bo.getSendMsg(), inputStream, 25600); int[] ints = convertHexToDecimal(largeData); - RedisUtils.setCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + device.getDeviceImei() + ":app_send_message_data" , Arrays.toString(ints), Duration.ofSeconds(5 * 60L)); + RedisUtils.setCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + ":app_send_message_data", Arrays.toString(ints), Duration.ofSeconds(5 * 60L)); - String data = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + device.getDeviceImei() + ":app_send_message_data"); + String data = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + ":app_send_message_data"); byte[] arr = ImageToCArrayConverter.convertStringToByteArray(data); byte[] specificChunk = ImageToCArrayConverter.getChunk(arr, 0, 512); - log.info("发送信息第0块数据大小: {} 字节",specificChunk.length); + log.info("发送信息第0块数据大小: {} 字节", specificChunk.length); ArrayList intData = new ArrayList<>(); intData.add(6); intData.add(1); - ImageToCArrayConverter.buildArr(convertHexToDecimal(specificChunk),intData); + ImageToCArrayConverter.buildArr(convertHexToDecimal(specificChunk), intData); intData.add(0); intData.add(0); intData.add(0); intData.add(0); Map map = new HashMap<>(); map.put("instruct", intData); - mqttGateway.sendMsgToMqtt(MqttConstants.GLOBAL_PUB_KEY+device.getDeviceImei(), 1 , JSON.toJSONString(map)); - log.info("发送信息点阵数据到设备消息=>topic:{},payload:{}", MqttConstants.GLOBAL_PUB_KEY+device.getDeviceImei(),JSON.toJSONString(map)); + mqttGateway.sendMsgToMqtt(MqttConstants.GLOBAL_PUB_KEY + device.getDeviceImei(), 1, JSON.toJSONString(map)); + log.info("发送信息点阵数据到设备消息=>topic:{},payload:{}", MqttConstants.GLOBAL_PUB_KEY + device.getDeviceImei(), JSON.toJSONString(map)); UpdateWrapper updateWrapper = new UpdateWrapper<>(); updateWrapper.eq("id", deviceId) @@ -106,10 +106,10 @@ public class DeviceBJQBizService { recordDeviceLog(deviceId, device.getDeviceName(), "发送信息", bo.getSendMsg(), AppLoginHelper.getUserId()); } catch (Exception e) { - log.info("发送信息设备发送信息失败:{}" ,deviceId); + log.info("发送信息设备发送信息失败:{}", deviceId); throw new ServiceException("发送指令失败"); } - //发送消息 + // 发送消息 messageSending(device.getDeviceImei()); } @@ -119,11 +119,12 @@ public class DeviceBJQBizService { /** * 记录设备操作日志 + * * @param deviceId 设备ID - * @param content 日志内容 + * @param content 日志内容 * @param operator 操作人 */ - private void recordDeviceLog(Long deviceId,String deviceName, String deviceAction, String content, Long operator) { + private void recordDeviceLog(Long deviceId, String deviceName, String deviceAction, String content, Long operator) { try { // 创建设备日志实体 com.fuyuanshen.equipment.domain.DeviceLog deviceLog = new com.fuyuanshen.equipment.domain.DeviceLog(); @@ -171,62 +172,62 @@ public class DeviceBJQBizService { AppPersonnelInfoVo personnelInfoVo = MapstructUtils.convert(appPersonnelInfo, AppPersonnelInfoVo.class); vo.setPersonnelInfo(personnelInfoVo); } - //设备在线状态 - String onlineStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + device.getDeviceImei()+ DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX); - //设备在线状态 - if("1".equals(onlineStatus)){ - vo.setOnlineStatus(1); - }else if("2".equals(onlineStatus)){ - vo.setOnlineStatus(2); - }else{ - vo.setOnlineStatus(0); + // 设备在线状态 + String onlineStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX); + // 设备在线状态 + if ("1".equals(onlineStatus)) { + vo.setOnlineStatus(1); + } else if ("2".equals(onlineStatus)) { + vo.setOnlineStatus(2); + } else { + vo.setOnlineStatus(0); } - String deviceStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + device.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_STATUS_KEY_PREFIX); + String deviceStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_STATUS_KEY_PREFIX); // 获取电量 - if(StringUtils.isNotBlank(deviceStatus)){ + if (StringUtils.isNotBlank(deviceStatus)) { JSONObject jsonObject = JSONObject.parseObject(deviceStatus); vo.setMainLightMode(jsonObject.getString("mainLightMode")); vo.setLaserLightMode(jsonObject.getString("laserLightMode")); vo.setBatteryPercentage(jsonObject.getString("batteryPercentage")); vo.setChargeState(jsonObject.getString("chargeState")); vo.setBatteryRemainingTime(jsonObject.getString("batteryRemainingTime")); - }else{ + } else { vo.setBatteryPercentage("0"); } - String lightModeStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + device.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_LIGHT_MODE_KEY_PREFIX); + String lightModeStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_LIGHT_MODE_KEY_PREFIX); // 获取电量 - if(StringUtils.isNotBlank(deviceStatus)){ + if (StringUtils.isNotBlank(deviceStatus)) { vo.setMainLightMode(lightModeStatus); } - String lightBrightnessStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + device.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_LIGHT_BRIGHTNESS_KEY_PREFIX); - if(StringUtils.isNotBlank(lightBrightnessStatus)){ + String lightBrightnessStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_LIGHT_BRIGHTNESS_KEY_PREFIX); + if (StringUtils.isNotBlank(lightBrightnessStatus)) { vo.setLightBrightness(lightBrightnessStatus); } - String laserLightMode = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + device.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_LASER_MODE_KEY_PREFIX); - if(StringUtils.isNotBlank(laserLightMode)){ + String laserLightMode = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_LASER_MODE_KEY_PREFIX); + if (StringUtils.isNotBlank(laserLightMode)) { vo.setLaserLightMode(laserLightMode); } // 获取经度纬度 - String locationKey = GlobalConstants.GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + device.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_LOCATION_KEY_PREFIX; + String locationKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_LOCATION_KEY_PREFIX; String locationInfo = RedisUtils.getCacheObject(locationKey); - if(StringUtils.isNotBlank(locationInfo)){ + if (StringUtils.isNotBlank(locationInfo)) { JSONObject jsonObject = JSONObject.parseObject(locationInfo); vo.setLongitude(jsonObject.get("longitude").toString()); vo.setLatitude(jsonObject.get("latitude").toString()); - vo.setAddress((String)jsonObject.get("address")); + vo.setAddress((String) jsonObject.get("address")); } - String alarmStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY +DEVICE_KEY_PREFIX+ device.getDeviceImei()+ DEVICE_ALARM_KEY_PREFIX); - if(StringUtils.isNotBlank(alarmStatus)){ + String alarmStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + DEVICE_ALARM_KEY_PREFIX); + if (StringUtils.isNotBlank(alarmStatus)) { vo.setAlarmStatus(alarmStatus); } - String lightBrightness = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY +DEVICE_KEY_PREFIX+ device.getDeviceImei()+ DEVICE_LIGHT_BRIGHTNESS_KEY_PREFIX); - if(StringUtils.isNotBlank(lightBrightness)){ + String lightBrightness = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + DEVICE_LIGHT_BRIGHTNESS_KEY_PREFIX); + if (StringUtils.isNotBlank(lightBrightness)) { vo.setLightBrightness(lightBrightness); } @@ -234,15 +235,14 @@ public class DeviceBJQBizService { } - public boolean registerPersonInfo(AppPersonnelInfoBo bo) { Long deviceId = bo.getDeviceId(); Device deviceObj = deviceMapper.selectById(deviceId); if (deviceObj == null) { throw new RuntimeException("请先将设备入库!!!"); } - if(getDeviceStatus(deviceObj.getDeviceImei())){ - throw new ServiceException(deviceObj.getDeviceName()+",设备已断开连接"); + if (getDeviceStatus(deviceObj.getDeviceImei())) { + throw new ServiceException(deviceObj.getDeviceName() + ",设备已断开连接"); } QueryWrapper qw = new QueryWrapper() .eq("device_id", deviceId); @@ -266,7 +266,7 @@ public class DeviceBJQBizService { map.put("instruct", intData); mqttGateway.sendMsgToMqtt(MqttConstants.GLOBAL_PUB_KEY + deviceObj.getDeviceImei(), 1, JSON.toJSONString(map)); log.info("发送点阵数据到设备消息=>topic:{},payload:{}", MqttConstants.GLOBAL_PUB_KEY + deviceObj.getDeviceImei(), bo); - String logContent = "单位:"+bo.getUnitName()+",职位:"+bo.getPosition()+",姓名:"+bo.getName()+",ID:"+bo.getCode(); + String logContent = "单位:" + bo.getUnitName() + ",职位:" + bo.getPosition() + ",姓名:" + bo.getName() + ",ID:" + bo.getCode(); recordDeviceLog(deviceId, deviceObj.getDeviceName(), "人员信息登记", logContent, AppLoginHelper.getUserId()); if (ObjectUtils.length(appPersonnelInfoVos) == 0) { AppPersonnelInfo appPersonnelInfo = MapstructUtils.convert(bo, AppPersonnelInfo.class); @@ -297,6 +297,7 @@ public class DeviceBJQBizService { } return true; } + public void uploadDeviceLogo2(AppDeviceLogoUploadDto bo) { try { Device device = deviceMapper.selectById(bo.getDeviceId()); @@ -322,25 +323,26 @@ public class DeviceBJQBizService { // Map map = new HashMap<>(); // map.put("instruct", combinedData); String[] specificChunk = ImageToCArrayConverter.getChunk2(hexArray, 0, bo.getChunkSize()); - mqttGateway.sendMsgToMqtt(MqttConstants.GLOBAL_PUB_KEY+device.getDeviceImei(), 1 , Arrays.toString(specificChunk)); - log.info("发送点阵数据到设备消息=>topic:{},payload:{}", MqttConstants.GLOBAL_PUB_KEY+device.getDeviceImei(),Arrays.toString(specificChunk)); + mqttGateway.sendMsgToMqtt(MqttConstants.GLOBAL_PUB_KEY + device.getDeviceImei(), 1, Arrays.toString(specificChunk)); + log.info("发送点阵数据到设备消息=>topic:{},payload:{}", MqttConstants.GLOBAL_PUB_KEY + device.getDeviceImei(), Arrays.toString(specificChunk)); recordDeviceLog(device.getId(), device.getDeviceName(), "上传开机画面", "上传开机画面", AppLoginHelper.getUserId()); - } catch (Exception e){ + } catch (Exception e) { e.printStackTrace(); throw new ServiceException("发送指令失败"); } } + public void uploadDeviceLogo(AppDeviceLogoUploadDto bo) { try { Device device = deviceMapper.selectById(bo.getDeviceId()); if (device == null) { throw new ServiceException("设备不存在"); } - if(getDeviceStatus(device.getDeviceImei())){ + if (getDeviceStatus(device.getDeviceImei())) { // throw new ServiceException(device.getDeviceName()+",设备已断开连接"); - log.info(device.getDeviceName()+",设备已断开连接"); - recordDeviceLog(device.getId(), device.getDeviceName(), "上传开机画面", device.getDeviceName()+",设备已断开连接", AppLoginHelper.getUserId()); + log.info(device.getDeviceName() + ",设备已断开连接"); + recordDeviceLog(device.getId(), device.getDeviceName(), "上传开机画面", device.getDeviceName() + ",设备已断开连接", AppLoginHelper.getUserId()); return; } MultipartFile file = bo.getFile(); @@ -351,9 +353,9 @@ public class DeviceBJQBizService { log.info("原始数据大小: {} 字节", largeData.length); int[] ints = convertHexToDecimal(largeData); - RedisUtils.setCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + device.getDeviceImei() +DEVICE_BOOT_LOGO_KEY_PREFIX, Arrays.toString(ints), Duration.ofSeconds(5 * 60L)); + RedisUtils.setCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + DEVICE_BOOT_LOGO_KEY_PREFIX, Arrays.toString(ints), Duration.ofSeconds(5 * 60L)); - String data = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + device.getDeviceImei() + DEVICE_BOOT_LOGO_KEY_PREFIX); + String data = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + DEVICE_BOOT_LOGO_KEY_PREFIX); byte[] arr = ImageToCArrayConverter.convertStringToByteArray(data); byte[] specificChunk = ImageToCArrayConverter.getChunk(arr, 0, 512); @@ -363,18 +365,18 @@ public class DeviceBJQBizService { ArrayList intData = new ArrayList<>(); intData.add(3); intData.add(1); - ImageToCArrayConverter.buildArr(convertHexToDecimal(specificChunk),intData); + ImageToCArrayConverter.buildArr(convertHexToDecimal(specificChunk), intData); intData.add(0); intData.add(0); intData.add(0); intData.add(0); Map map = new HashMap<>(); map.put("instruct", intData); - mqttGateway.sendMsgToMqtt(MqttConstants.GLOBAL_PUB_KEY+device.getDeviceImei(), 1 , JSON.toJSONString(map)); - log.info("发送点阵数据到设备消息=>topic:{},payload:{}", MqttConstants.GLOBAL_PUB_KEY+device.getDeviceImei(),JSON.toJSONString(map)); + mqttGateway.sendMsgToMqtt(MqttConstants.GLOBAL_PUB_KEY + device.getDeviceImei(), 1, JSON.toJSONString(map)); + log.info("发送点阵数据到设备消息=>topic:{},payload:{}", MqttConstants.GLOBAL_PUB_KEY + device.getDeviceImei(), JSON.toJSONString(map)); recordDeviceLog(device.getId(), device.getDeviceName(), "上传开机画面", "上传开机画面", AppLoginHelper.getUserId()); - } catch (Exception e){ + } catch (Exception e) { e.printStackTrace(); throw new ServiceException("发送指令失败"); } @@ -389,13 +391,13 @@ public class DeviceBJQBizService { try { Long deviceId = params.getDeviceId(); Device device = deviceMapper.selectById(deviceId); - if(device == null){ + if (device == null) { throw new ServiceException("设备不存在"); } - if(getDeviceStatus(device.getDeviceImei())){ - throw new ServiceException(device.getDeviceName()+",设备已断开连接"); + if (getDeviceStatus(device.getDeviceImei())) { + throw new ServiceException(device.getDeviceName() + ",设备已断开连接"); } - Integer instructValue = Integer.parseInt(params.getInstructValue()); + Integer instructValue = Integer.parseInt(params.getInstructValue()); ArrayList intData = new ArrayList<>(); intData.add(1); intData.add(instructValue); @@ -404,26 +406,26 @@ public class DeviceBJQBizService { intData.add(0); Map map = new HashMap<>(); map.put("instruct", intData); - mqttGateway.sendMsgToMqtt(MqttConstants.GLOBAL_PUB_KEY+device.getDeviceImei(), 1 , JSON.toJSONString(map)); - log.info("发送点阵数据到设备消息=>topic:{},payload:{}", MqttConstants.GLOBAL_PUB_KEY+device.getDeviceImei(),JSON.toJSONString(map)); + mqttGateway.sendMsgToMqtt(MqttConstants.GLOBAL_PUB_KEY + device.getDeviceImei(), 1, JSON.toJSONString(map)); + log.info("发送点阵数据到设备消息=>topic:{},payload:{}", MqttConstants.GLOBAL_PUB_KEY + device.getDeviceImei(), JSON.toJSONString(map)); LightModeEnum modeEnum = LightModeEnum.getByCode(instructValue); - recordDeviceLog(device.getId(), device.getDeviceName(), "灯光模式", modeEnum!=null?modeEnum.getName():null, AppLoginHelper.getUserId()); - } catch (Exception e){ + recordDeviceLog(device.getId(), device.getDeviceName(), "灯光模式", modeEnum != null ? modeEnum.getName() : null, AppLoginHelper.getUserId()); + } catch (Exception e) { e.printStackTrace(); throw new ServiceException("发送指令失败"); } } - //灯光亮度设置 + // 灯光亮度设置 public void lightBrightnessSettings(DeviceInstructDto params) { try { Long deviceId = params.getDeviceId(); Device device = deviceMapper.selectById(deviceId); - if(device == null){ + if (device == null) { throw new ServiceException("设备不存在"); } - if(getDeviceStatus(device.getDeviceImei())){ - throw new ServiceException(device.getDeviceName()+",设备已断开连接"); + if (getDeviceStatus(device.getDeviceImei())) { + throw new ServiceException(device.getDeviceName() + ",设备已断开连接"); } String instructValue = params.getInstructValue(); ArrayList intData = new ArrayList<>(); @@ -431,10 +433,10 @@ public class DeviceBJQBizService { String[] values = instructValue.split("\\."); String value1 = values[0]; String value2 = values[1]; - if(StringUtils.isNoneBlank(value1)){ + if (StringUtils.isNoneBlank(value1)) { intData.add(Integer.parseInt(value1)); } - if(StringUtils.isNoneBlank(value2)){ + if (StringUtils.isNoneBlank(value2)) { intData.add(Integer.parseInt(value2)); } intData.add(0); @@ -442,25 +444,25 @@ public class DeviceBJQBizService { intData.add(0); Map map = new HashMap<>(); map.put("instruct", intData); - mqttGateway.sendMsgToMqtt(MqttConstants.GLOBAL_PUB_KEY+device.getDeviceImei(), 1 , JSON.toJSONString(map)); - log.info("发送点阵数据到设备消息=>topic:{},payload:{}", MqttConstants.GLOBAL_PUB_KEY+device.getDeviceImei(),JSON.toJSONString(map)); + mqttGateway.sendMsgToMqtt(MqttConstants.GLOBAL_PUB_KEY + device.getDeviceImei(), 1, JSON.toJSONString(map)); + log.info("发送点阵数据到设备消息=>topic:{},payload:{}", MqttConstants.GLOBAL_PUB_KEY + device.getDeviceImei(), JSON.toJSONString(map)); - } catch (Exception e){ + } catch (Exception e) { e.printStackTrace(); throw new ServiceException("发送指令失败"); } } - //激光模式设置 + // 激光模式设置 public void laserModeSettings(DeviceInstructDto params) { try { - Long deviceId = params.getDeviceId(); + Long deviceId = params.getDeviceId(); Device device = deviceMapper.selectById(deviceId); - if(device == null){ + if (device == null) { throw new ServiceException("设备不存在"); } - if(getDeviceStatus(device.getDeviceImei())){ - throw new ServiceException(device.getDeviceName()+",设备已断开连接"); + if (getDeviceStatus(device.getDeviceImei())) { + throw new ServiceException(device.getDeviceName() + ",设备已断开连接"); } Integer instructValue = Integer.parseInt(params.getInstructValue()); ArrayList intData = new ArrayList<>(); @@ -471,15 +473,15 @@ public class DeviceBJQBizService { intData.add(0); Map map = new HashMap<>(); map.put("instruct", intData); - mqttGateway.sendMsgToMqtt(MqttConstants.GLOBAL_PUB_KEY+device.getDeviceImei(), 1 , JSON.toJSONString(map)); - log.info("发送点阵数据到设备消息=>topic:{},payload:{}", MqttConstants.GLOBAL_PUB_KEY+device.getDeviceImei(),JSON.toJSONString(map)); + mqttGateway.sendMsgToMqtt(MqttConstants.GLOBAL_PUB_KEY + device.getDeviceImei(), 1, JSON.toJSONString(map)); + log.info("发送点阵数据到设备消息=>topic:{},payload:{}", MqttConstants.GLOBAL_PUB_KEY + device.getDeviceImei(), JSON.toJSONString(map)); // 1代表开启激光灯,此时主灯关闭,主灯控件为关机状态,为0代表关闭激光灯 - if("1".equals(params.getInstructValue())){ + if ("1".equals(params.getInstructValue())) { recordDeviceLog(device.getId(), device.getDeviceName(), "激光模式设置", "开启激光灯", AppLoginHelper.getUserId()); - }else{ + } else { recordDeviceLog(device.getId(), device.getDeviceName(), "激光模式设置", "关闭激光灯", AppLoginHelper.getUserId()); } - } catch (Exception e){ + } catch (Exception e) { e.printStackTrace(); throw new ServiceException("发送指令失败"); } @@ -489,7 +491,7 @@ public class DeviceBJQBizService { QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("device_imei", params.getDeviceImei()); List devices = deviceMapper.selectList(queryWrapper); - if(ObjectUtils.length( devices) ==0){ + if (ObjectUtils.length(devices) == 0) { throw new ServiceException("设备不存在"); } return RedisUtils.getCacheObject("device:location:" + devices.get(0).getDeviceImei()); @@ -507,8 +509,8 @@ public class DeviceBJQBizService { if (device == null) { throw new ServiceException("设备不存在" + deviceId); } - if(getDeviceStatus(device.getDeviceImei())){ - throw new ServiceException(device.getDeviceName()+",设备已断开连接"); + if (getDeviceStatus(device.getDeviceImei())) { + throw new ServiceException(device.getDeviceName() + ",设备已断开连接"); } try { @@ -521,39 +523,39 @@ public class DeviceBJQBizService { intData.add(0); Map map = new HashMap<>(); map.put("instruct", intData); - mqttGateway.sendMsgToMqtt(MqttConstants.GLOBAL_PUB_KEY+device.getDeviceImei(), 1 , JSON.toJSONString(map)); - log.info("发送点阵数据到设备消息=>topic:{},payload:{}", MqttConstants.GLOBAL_PUB_KEY+device.getDeviceImei(),JSON.toJSONString(map)); + mqttGateway.sendMsgToMqtt(MqttConstants.GLOBAL_PUB_KEY + device.getDeviceImei(), 1, JSON.toJSONString(map)); + log.info("发送点阵数据到设备消息=>topic:{},payload:{}", MqttConstants.GLOBAL_PUB_KEY + device.getDeviceImei(), JSON.toJSONString(map)); UpdateWrapper updateWrapper = new UpdateWrapper<>(); updateWrapper.eq("id", deviceId) .set("send_msg", bo.getSendMsg()); deviceMapper.update(updateWrapper); - if("0".equals(bo.getInstructValue())){ + if ("0".equals(bo.getInstructValue())) { recordDeviceLog(device.getId(), device.getDeviceName(), "解除告警信息", "关闭设备", AppLoginHelper.getUserId()); - }else{ + } else { recordDeviceLog(device.getId(), device.getDeviceName(), "发送告警信息", bo.getSendMsg(), AppLoginHelper.getUserId()); } } catch (Exception e) { - log.info("设备发送告警信息信息失败:{}" ,deviceId); + log.info("设备发送告警信息信息失败:{}", deviceId); throw new ServiceException("设备发送告警信息信息失败"); } messageSending(device.getDeviceImei()); } - } catch (Exception e){ + } catch (Exception e) { e.printStackTrace(); throw new ServiceException("发送告警信息指令失败"); } return 1; } - private void messageSending(String deviceImei){ - String sendMessageIng = GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX + deviceImei + ":messageSending"; + private void messageSending(String deviceImei) { + String sendMessageIng = GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + deviceImei + ":messageSending"; RedisUtils.setCacheObject(sendMessageIng, "1", Duration.ofDays(1)); } private boolean getDeviceStatus(String deviceImei) { - String deviceOnlineStatusRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX+ deviceImei + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX ; + String deviceOnlineStatusRedisKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + deviceImei + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX; return RedisUtils.getCacheObject(deviceOnlineStatusRedisKey) == null; } diff --git a/fys-admin/src/main/java/com/fuyuanshen/web/service/device/DeviceBizService.java b/fys-admin/src/main/java/com/fuyuanshen/web/service/device/DeviceBizService.java index 0aba6f8..0994132 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/web/service/device/DeviceBizService.java +++ b/fys-admin/src/main/java/com/fuyuanshen/web/service/device/DeviceBizService.java @@ -59,8 +59,8 @@ public class DeviceBizService { private final RealTimeStatusEngine realTimeStatusEngine; private final DeviceLogMapper deviceLogMapper; private final AppDeviceShareMapper appDeviceShareMapper; - private final AppUserMapper appUserMapper;; - + private final AppUserMapper appUserMapper; + ; public List getTypeList() { @@ -84,37 +84,37 @@ public class DeviceBizService { } Page result = deviceMapper.queryAppBindDeviceList(pageQuery.build(), bo); List records = result.getRecords(); - if(records != null && !records.isEmpty()){ + if (records != null && !records.isEmpty()) { records.forEach(item -> { - if(item.getCommunicationMode()!=null && item.getCommunicationMode() == 0){ + if (item.getCommunicationMode() != null && item.getCommunicationMode() == 0) { - //设备在线状态 - String onlineStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX+ item.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX); - if("1".equals(onlineStatus)){ + // 设备在线状态 + String onlineStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + item.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX); + if ("1".equals(onlineStatus)) { item.setOnlineStatus(1); - }else if("2".equals(onlineStatus)){ + } else if ("2".equals(onlineStatus)) { item.setOnlineStatus(2); - }else{ + } else { item.setOnlineStatus(0); } - String deviceStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX+ item.getDeviceImei() + DEVICE_STATUS_KEY_PREFIX); + String deviceStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + item.getDeviceImei() + DEVICE_STATUS_KEY_PREFIX); // 获取电量 - if(StringUtils.isNotBlank(deviceStatus)){ + if (StringUtils.isNotBlank(deviceStatus)) { JSONObject jsonObject = JSONObject.parseObject(deviceStatus); item.setBattery(jsonObject.getString("batteryPercentage")); - }else{ + } else { item.setBattery("0"); } - String location = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY +DEVICE_KEY_PREFIX+ item.getDeviceImei()+ DEVICE_LOCATION_KEY_PREFIX); - if(StringUtils.isNotBlank(location)){ + String location = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + item.getDeviceImei() + DEVICE_LOCATION_KEY_PREFIX); + if (StringUtils.isNotBlank(location)) { JSONObject jsonObject = JSONObject.parseObject(location); item.setLatitude(jsonObject.getString("latitude")); item.setLongitude(jsonObject.getString("longitude")); } - String alarmStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY +DEVICE_KEY_PREFIX+ item.getDeviceImei()+ DEVICE_ALARM_KEY_PREFIX); - if(StringUtils.isNotBlank(alarmStatus)){ + String alarmStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + item.getDeviceImei() + DEVICE_ALARM_KEY_PREFIX); + if (StringUtils.isNotBlank(alarmStatus)) { item.setAlarmStatus(alarmStatus); } } @@ -126,11 +126,11 @@ public class DeviceBizService { public TableDataInfo queryWebDeviceList(DeviceQueryCriteria bo, PageQuery pageQuery) { Page result = deviceMapper.queryWebDeviceList(pageQuery.build(), bo); List records = result.getRecords(); - if(records != null && !records.isEmpty()){ + if (records != null && !records.isEmpty()) { records.forEach(item -> { - if(item.getCommunicationMode()!=null && Ints.asList(0, 2).contains(item.getCommunicationMode())){ + if (item.getCommunicationMode() != null && Ints.asList(0, 2).contains(item.getCommunicationMode())) { - //设备在线状态 + // 设备在线状态 // String onlineStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX+ item.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX); // if("1".equals(onlineStatus)){ // item.setOnlineStatus(1); @@ -139,24 +139,24 @@ public class DeviceBizService { // }else{ // item.setOnlineStatus(0); // } - String deviceStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX+ item.getDeviceImei() + DEVICE_STATUS_KEY_PREFIX); + String deviceStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + item.getDeviceImei() + DEVICE_STATUS_KEY_PREFIX); // 获取电量 - if(StringUtils.isNotBlank(deviceStatus)){ + if (StringUtils.isNotBlank(deviceStatus)) { JSONObject jsonObject = JSONObject.parseObject(deviceStatus); item.setBattery(jsonObject.getString("batteryPercentage")); - }else{ + } else { item.setBattery("0"); } - String location = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY +DEVICE_KEY_PREFIX+ item.getDeviceImei()+ DEVICE_LOCATION_KEY_PREFIX); - if(StringUtils.isNotBlank(location)){ + String location = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + item.getDeviceImei() + DEVICE_LOCATION_KEY_PREFIX); + if (StringUtils.isNotBlank(location)) { JSONObject jsonObject = JSONObject.parseObject(location); item.setLatitude(jsonObject.getString("latitude")); item.setLongitude(jsonObject.getString("longitude")); } - String alarmStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY +DEVICE_KEY_PREFIX+ item.getDeviceImei()+ DEVICE_ALARM_KEY_PREFIX); - if(StringUtils.isNotBlank(alarmStatus)){ + String alarmStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + item.getDeviceImei() + DEVICE_ALARM_KEY_PREFIX); + if (StringUtils.isNotBlank(alarmStatus)) { item.setAlarmStatus(alarmStatus); } } @@ -165,6 +165,7 @@ public class DeviceBizService { return TableDataInfo.build(result); } + public int bindDevice(AppDeviceBo bo) { Integer mode = bo.getCommunicationMode(); Long userId = AppLoginHelper.getUserId(); @@ -274,7 +275,7 @@ public class DeviceBizService { if (count == 0) { throw new RuntimeException("请先绑定设备!!!"); } - if(count<2){ + if (count < 2) { UpdateWrapper deviceUpdateWrapper = new UpdateWrapper<>(); deviceUpdateWrapper.eq("id", device.getId()) .set("binding_user_id", null) @@ -291,7 +292,7 @@ public class DeviceBizService { appDeviceBindRecordMapper.deleteById(appDeviceBindRecord.getId())); } AppUserVo appUserVo = appUserMapper.selectVoById(userId); - if(appUserVo != null){ + if (appUserVo != null) { QueryWrapper appDeviceShareQueryWrapper = new QueryWrapper<>(); appDeviceShareQueryWrapper.eq("device_id", device.getId()); appDeviceShareQueryWrapper.eq("phonenumber", appUserVo.getPhonenumber()); @@ -301,7 +302,7 @@ public class DeviceBizService { appDeviceShareMapper.deleteById(appDeviceShare.getId())); } } - }else{ + } else { QueryWrapper bindRecordQueryWrapper = new QueryWrapper<>(); bindRecordQueryWrapper.eq("device_id", device.getId()); Long count = appDeviceBindRecordMapper.selectCount(bindRecordQueryWrapper); @@ -341,7 +342,7 @@ public class DeviceBizService { QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("device_imei", params.getDeviceImei()); List devices = deviceMapper.selectList(queryWrapper); - if(ObjectUtils.length( devices) ==0){ + if (ObjectUtils.length(devices) == 0) { throw new ServiceException("设备不存在"); } return RedisUtils.getCacheObject("device:location:" + devices.get(0).getDeviceImei()); @@ -350,12 +351,12 @@ public class DeviceBizService { public Map getRealTimeStatus(AppRealTimeStatusDto statusDto) { try { // String commandType = statusDto.getTypeName()+"_" + statusDto.getFunctionMode();"FunctionAccessBatchStatusRule" - DeviceStatusRule rule = realTimeStatusEngine.getDeviceStatusRule(statusDto.getTypeName()); - if(rule == null){ + DeviceStatusRule rule = realTimeStatusEngine.getDeviceStatusRule(statusDto.getTypeName()); + if (rule == null) { throw new ServiceException("未匹配到处理命令"); } return rule.getStatus(statusDto); - } catch (Exception e){ + } catch (Exception e) { e.printStackTrace(); } return null; @@ -393,7 +394,7 @@ public class DeviceBizService { long endTime = today.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(); String deviceImei = device.getDeviceImei(); - String a = GLOBAL_REDIS_KEY+ DEVICE_KEY_PREFIX+ deviceImei + DEVICE_LOCATION_KEY_PREFIX + ":history"; + String a = GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + deviceImei + DEVICE_LOCATION_KEY_PREFIX + ":history"; Collection list = RedisUtils.zRangeByScoreDesc(a, startTime, endTime); if (CollectionUtil.isEmpty(list)) { return null; @@ -401,12 +402,12 @@ public class DeviceBizService { Map> map = new LinkedHashMap<>(); - for (String obj : list){ + for (String obj : list) { JSONObject jsonObject = JSONObject.parseObject(obj); Long timestamp = jsonObject.getLong("timestamp"); LocalDate date = LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneId.systemDefault()).toLocalDate(); String address = jsonObject.getString("address"); - if(StringUtils.isBlank( address) || "[]".equals(address)){ + if (StringUtils.isBlank(address) || "[]".equals(address)) { continue; } if (map.containsKey(date.toString())) { @@ -424,7 +425,7 @@ public class DeviceBizService { detailVo.setDate(entry.getKey()); detailVo.setDeviceName(device.getDeviceName()); detailVo.setStartLocation(entry.getValue().get(0).getString("address")); - detailVo.setEndLocation(entry.getValue().get(entry.getValue().size()-1).getString("address")); + detailVo.setEndLocation(entry.getValue().get(entry.getValue().size() - 1).getString("address")); String jsonString = JSONArray.toJSONString(entry.getValue()); List strings = JSONArray.parseArray(jsonString); detailVo.setDetailList(strings); diff --git a/fys-admin/src/main/java/com/fuyuanshen/web/service/device/DeviceDebugService.java b/fys-admin/src/main/java/com/fuyuanshen/web/service/device/DeviceDebugService.java index aa8fa6b..afea485 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/web/service/device/DeviceDebugService.java +++ b/fys-admin/src/main/java/com/fuyuanshen/web/service/device/DeviceDebugService.java @@ -39,6 +39,7 @@ public class DeviceDebugService { private final IAppBusinessFileService appBusinessFileService; private final IAppOperationVideoService appOperationVideoService; private final DeviceService deviceService; + private final FileHashUtil fileHashUtil; /** * 文件上传并添加文件信息哈希去重 @@ -62,26 +63,12 @@ public class DeviceDebugService { Map hash2OssId = new LinkedHashMap<>(files.length); for (MultipartFile file : files) { // 1. 计算文件哈希 - String hash = FileHashUtil.hash(file); + String hash = fileHashUtil.hash(file); - // 2. 先根据 hash 查库(秒传) - SysOssVo exist = sysOssService.selectByHash(hash); - Long ossId; - if (exist != null) { - // 2.1 已存在,直接复用 - ossId = exist.getOssId(); - hash2OssId.putIfAbsent(hash, ossId); - } else { - // 2.2 不存在,真正上传 - SysOssVo upload = sysOssService.upload(file); - if (upload == null) { - return false; - } - ossId = upload.getOssId(); - hash2OssId.putIfAbsent(hash, ossId); - // 2.3 把 hash 写回记录(供下次去重) - sysOssService.updateHashById(ossId, hash); - } + SysOssVo exist = sysOssService.updateHash(file, hash); + // 2.1 已存在,直接复用 + long ossId = exist.getOssId(); + hash2OssId.putIfAbsent(hash, ossId); } // 4. 组装业务中间表 List bizList = new ArrayList<>(bo.getDeviceIds().length * hash2OssId.size()); diff --git a/fys-admin/src/main/java/com/fuyuanshen/web/service/impl/DeviceBJQ6075BizServiceImpl.java b/fys-admin/src/main/java/com/fuyuanshen/web/service/impl/DeviceBJQ6075BizServiceImpl.java new file mode 100644 index 0000000..b88197c --- /dev/null +++ b/fys-admin/src/main/java/com/fuyuanshen/web/service/impl/DeviceBJQ6075BizServiceImpl.java @@ -0,0 +1,598 @@ +package com.fuyuanshen.web.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import com.fuyuanshen.app.domain.AppPersonnelInfo; +import com.fuyuanshen.app.domain.AppPersonnelInfoRecords; +import com.fuyuanshen.app.domain.bo.AppPersonnelInfoBo; +import com.fuyuanshen.app.domain.dto.AppDeviceLogoUploadDto; +import com.fuyuanshen.app.domain.dto.DeviceInstructDto; +import com.fuyuanshen.app.domain.vo.AppDevice6075DetailVo; +import com.fuyuanshen.app.domain.vo.AppDeviceDetailVo; +import com.fuyuanshen.app.domain.vo.AppPersonnelInfoVo; +import com.fuyuanshen.app.mapper.AppPersonnelInfoMapper; +import com.fuyuanshen.app.mapper.AppPersonnelInfoRecordsMapper; +import com.fuyuanshen.common.core.constant.GlobalConstants; +import com.fuyuanshen.common.core.exception.ServiceException; +import com.fuyuanshen.common.core.utils.*; +import com.fuyuanshen.common.redis.utils.RedisUtils; +import com.fuyuanshen.common.satoken.utils.AppLoginHelper; +import com.fuyuanshen.equipment.domain.Device; +import com.fuyuanshen.equipment.domain.DeviceType; +import com.fuyuanshen.equipment.domain.dto.AppDeviceSendMsgBo; +import com.fuyuanshen.equipment.enums.LightModeEnum; +import com.fuyuanshen.equipment.mapper.DeviceLogMapper; +import com.fuyuanshen.equipment.mapper.DeviceMapper; +import com.fuyuanshen.equipment.mapper.DeviceTypeMapper; +import com.fuyuanshen.global.mqtt.config.MqttGateway; +import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants; +import com.fuyuanshen.global.mqtt.constants.MqttConstants; +import com.fuyuanshen.web.service.device.DeviceBJQ6075BizService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.io.ClassPathResource; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.io.InputStream; +import java.time.Duration; +import java.util.*; + +import static com.fuyuanshen.common.core.constant.GlobalConstants.GLOBAL_REDIS_KEY; +import static com.fuyuanshen.common.core.utils.Bitmap80x12Generator.buildArr; +import static com.fuyuanshen.common.core.utils.Bitmap80x12Generator.generateFixedBitmapData; +import static com.fuyuanshen.common.core.utils.ImageToCArrayConverter.convertHexToDecimal; +import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.*; + + +@Slf4j +@Service +@RequiredArgsConstructor +public class DeviceBJQ6075BizServiceImpl implements DeviceBJQ6075BizService { + + private final DeviceMapper deviceMapper; + private final AppPersonnelInfoMapper appPersonnelInfoMapper; + private final AppPersonnelInfoRecordsMapper appPersonnelInfoRecordsMapper; + private final DeviceTypeMapper deviceTypeMapper; + private final MqttGateway mqttGateway; + private final DeviceLogMapper deviceLogMapper; + + + /** + * 获取设备详情 + * + * @param id + * @return + */ + @Override + public AppDevice6075DetailVo getInfo(Long id) { + Device device = deviceMapper.selectById(id); + if (device == null) { + throw new RuntimeException("请先将设备入库!!!"); + } + + AppDevice6075DetailVo vo = new AppDevice6075DetailVo(); + vo.setDeviceId(device.getId()); + vo.setDeviceName(device.getDeviceName()); + vo.setDevicePic(device.getDevicePic()); + vo.setDeviceImei(device.getDeviceImei()); + vo.setDeviceMac(device.getDeviceMac()); + vo.setDeviceStatus(device.getDeviceStatus()); + DeviceType deviceType = deviceTypeMapper.selectById(device.getDeviceType()); + if (deviceType != null) { + vo.setCommunicationMode(Integer.valueOf(deviceType.getCommunicationMode())); + vo.setTypeName(deviceType.getTypeName()); + } + vo.setBluetoothName(device.getBluetoothName()); + + vo.setSendMsg(device.getSendMsg()); + + QueryWrapper qw = new QueryWrapper() + .eq("device_id", device.getId()); + AppPersonnelInfo appPersonnelInfo = appPersonnelInfoMapper.selectOne(qw); + if (appPersonnelInfo != null) { + AppPersonnelInfoVo personnelInfoVo = MapstructUtils.convert(appPersonnelInfo, AppPersonnelInfoVo.class); + vo.setPersonnelInfo(personnelInfoVo); + } + // 设备在线状态 + String onlineStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX); + // 设备在线状态 + if ("1".equals(onlineStatus)) { + vo.setOnlineStatus(1); + } else if ("2".equals(onlineStatus)) { + vo.setOnlineStatus(2); + } else { + vo.setOnlineStatus(0); + } + String deviceStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_STATUS_KEY_PREFIX); + // 获取电量 + if (StringUtils.isNotBlank(deviceStatus)) { + JSONObject jsonObject = JSONObject.parseObject(deviceStatus); + vo.setMainLightMode(jsonObject.getString("mainLightMode")); + vo.setLaserLightMode(jsonObject.getString("laserLightMode")); + vo.setBatteryPercentage(jsonObject.getString("batteryPercentage")); + vo.setChargeState(jsonObject.getString("chargeState")); + vo.setBatteryRemainingTime(jsonObject.getString("batteryRemainingTime")); + } else { + vo.setBatteryPercentage("0"); + } + + String lightModeStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_LIGHT_MODE_KEY_PREFIX); + // 获取电量 + if (StringUtils.isNotBlank(deviceStatus)) { + vo.setMainLightMode(lightModeStatus); + } + + String lightBrightnessStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_LIGHT_BRIGHTNESS_KEY_PREFIX); + if (StringUtils.isNotBlank(lightBrightnessStatus)) { + vo.setLightBrightness(lightBrightnessStatus); + } + + String laserLightMode = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_LASER_MODE_KEY_PREFIX); + if (StringUtils.isNotBlank(laserLightMode)) { + vo.setLaserLightMode(laserLightMode); + } + + // 获取经度纬度 + String locationKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + DeviceRedisKeyConstants.DEVICE_LOCATION_KEY_PREFIX; + String locationInfo = RedisUtils.getCacheObject(locationKey); + if (StringUtils.isNotBlank(locationInfo)) { + JSONObject jsonObject = JSONObject.parseObject(locationInfo); + vo.setLongitude(jsonObject.get("longitude").toString()); + vo.setLatitude(jsonObject.get("latitude").toString()); + vo.setAddress((String) jsonObject.get("address")); + } + + String alarmStatus = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + DEVICE_ALARM_KEY_PREFIX); + if (StringUtils.isNotBlank(alarmStatus)) { + vo.setAlarmStatus(alarmStatus); + } + + String lightBrightness = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + DEVICE_LIGHT_BRIGHTNESS_KEY_PREFIX); + if (StringUtils.isNotBlank(lightBrightness)) { + vo.setLightBrightness(lightBrightness); + } + + return vo; + } + + + @Override + public int sendMessage(AppDeviceSendMsgBo bo) { + List deviceIds = bo.getDeviceIds(); + if (deviceIds == null || deviceIds.isEmpty()) { + throw new ServiceException("请选择设备"); + } + for (Long deviceId : deviceIds) { + Device device = deviceMapper.selectById(deviceId); + if (device == null) { + throw new ServiceException("设备不存在" + deviceId); + } + if (getDeviceStatus(device.getDeviceImei())) { + throw new ServiceException(device.getDeviceName() + ",设备已断开连接"); + } + try { + ClassPathResource resource = new ClassPathResource("image/background.png"); + InputStream inputStream = resource.getInputStream(); + + byte[] largeData = ImageWithTextGenerate.generate160x80ImageWithText2(bo.getSendMsg(), inputStream, 25600); + int[] ints = convertHexToDecimal(largeData); + RedisUtils.setCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + ":app_send_message_data", Arrays.toString(ints), Duration.ofSeconds(5 * 60L)); + + String data = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + ":app_send_message_data"); + + byte[] arr = ImageToCArrayConverter.convertStringToByteArray(data); + byte[] specificChunk = ImageToCArrayConverter.getChunk(arr, 0, 512); + log.info("发送信息第0块数据大小: {} 字节", specificChunk.length); + + ArrayList intData = new ArrayList<>(); + intData.add(6); + intData.add(1); + ImageToCArrayConverter.buildArr(convertHexToDecimal(specificChunk), intData); + intData.add(0); + intData.add(0); + intData.add(0); + intData.add(0); + Map map = new HashMap<>(); + map.put("instruct", intData); + mqttGateway.sendMsgToMqtt(MqttConstants.GLOBAL_PUB_KEY + device.getDeviceImei(), 1, JSON.toJSONString(map)); + log.info("发送信息点阵数据到设备消息=>topic:{},payload:{}", MqttConstants.GLOBAL_PUB_KEY + device.getDeviceImei(), JSON.toJSONString(map)); + + UpdateWrapper updateWrapper = new UpdateWrapper<>(); + updateWrapper.eq("id", deviceId) + .set("send_msg", bo.getSendMsg()); + deviceMapper.update(updateWrapper); + + recordDeviceLog(deviceId, device.getDeviceName(), "发送信息", bo.getSendMsg(), AppLoginHelper.getUserId()); + } catch (Exception e) { + log.info("发送信息设备发送信息失败:{}", deviceId); + throw new ServiceException("发送指令失败"); + } + // 发送消息 + messageSending(device.getDeviceImei()); + } + + + return 1; + } + + /** + * 记录设备操作日志 + * + * @param deviceId 设备ID + * @param content 日志内容 + * @param operator 操作人 + */ + @Override + public void recordDeviceLog(Long deviceId, String deviceName, String deviceAction, String content, Long operator) { + try { + // 创建设备日志实体 + com.fuyuanshen.equipment.domain.DeviceLog deviceLog = new com.fuyuanshen.equipment.domain.DeviceLog(); + deviceLog.setDeviceId(deviceId); + deviceLog.setDeviceAction(deviceAction); + deviceLog.setContent(content); + deviceLog.setCreateBy(operator); + deviceLog.setDeviceName(deviceName); + deviceLog.setCreateTime(new Date()); + + // 插入日志记录 + deviceLogMapper.insert(deviceLog); + } catch (Exception e) { + log.error("记录设备操作日志失败: {}", e.getMessage(), e); + } + } + + + @Override + public boolean registerPersonInfo(AppPersonnelInfoBo bo) { + Long deviceId = bo.getDeviceId(); + Device deviceObj = deviceMapper.selectById(deviceId); + if (deviceObj == null) { + throw new RuntimeException("请先将设备入库!!!"); + } + if (getDeviceStatus(deviceObj.getDeviceImei())) { + throw new ServiceException(deviceObj.getDeviceName() + ",设备已断开连接"); + } + QueryWrapper qw = new QueryWrapper() + .eq("device_id", deviceId); + List appPersonnelInfoVos = appPersonnelInfoMapper.selectVoList(qw); +// unitName,position,name,id + byte[] unitName = generateFixedBitmapData(bo.getUnitName(), 120); + byte[] position = generateFixedBitmapData(bo.getPosition(), 120); + byte[] name = generateFixedBitmapData(bo.getName(), 120); + byte[] id = generateFixedBitmapData(bo.getCode(), 120); + ArrayList intData = new ArrayList<>(); + intData.add(2); + buildArr(convertHexToDecimal(unitName), intData); + buildArr(convertHexToDecimal(name), intData); + buildArr(convertHexToDecimal(position), intData); + buildArr(convertHexToDecimal(id), intData); + intData.add(0); + intData.add(0); + intData.add(0); + intData.add(0); + Map map = new HashMap<>(); + map.put("instruct", intData); + mqttGateway.sendMsgToMqtt(MqttConstants.GLOBAL_PUB_KEY + deviceObj.getDeviceImei(), 1, JSON.toJSONString(map)); + log.info("发送点阵数据到设备消息=>topic:{},payload:{}", MqttConstants.GLOBAL_PUB_KEY + deviceObj.getDeviceImei(), bo); + String logContent = "单位:" + bo.getUnitName() + ",职位:" + bo.getPosition() + ",姓名:" + bo.getName() + ",ID:" + bo.getCode(); + recordDeviceLog(deviceId, deviceObj.getDeviceName(), "人员信息登记", logContent, AppLoginHelper.getUserId()); + if (ObjectUtils.length(appPersonnelInfoVos) == 0) { + AppPersonnelInfo appPersonnelInfo = MapstructUtils.convert(bo, AppPersonnelInfo.class); + appPersonnelInfoMapper.insertOrUpdate(appPersonnelInfo); + + AppPersonnelInfoRecords appPersonnelInfoRecords = new AppPersonnelInfoRecords(); + BeanUtil.copyProperties(appPersonnelInfo, appPersonnelInfoRecords); + appPersonnelInfoRecords.setId(null); + appPersonnelInfoRecords.setPersonnelId(appPersonnelInfo.getId()); + + appPersonnelInfoRecordsMapper.insert(appPersonnelInfoRecords); + } else { + UpdateWrapper uw = new UpdateWrapper<>(); + uw.eq("device_id", deviceId) + .set("name", bo.getName()) + .set("position", bo.getPosition()) + .set("unit_name", bo.getUnitName()) + .set("code", bo.getCode()); + appPersonnelInfoMapper.update(null, uw); + + AppPersonnelInfoVo personnelInfoVo = appPersonnelInfoVos.get(0); + AppPersonnelInfo appPersonnelInfo = MapstructUtils.convert(bo, AppPersonnelInfo.class); + AppPersonnelInfoRecords appPersonnelInfoRecords = new AppPersonnelInfoRecords(); + BeanUtil.copyProperties(appPersonnelInfo, appPersonnelInfoRecords); + appPersonnelInfoRecords.setId(null); + appPersonnelInfoRecords.setPersonnelId(personnelInfoVo.getId()); + appPersonnelInfoRecordsMapper.insert(appPersonnelInfoRecords); + } + return true; + } + + @Override + public void uploadDeviceLogo2(AppDeviceLogoUploadDto bo) { + try { + Device device = deviceMapper.selectById(bo.getDeviceId()); + if (device == null) { + throw new ServiceException("设备不存在"); + } + MultipartFile file = bo.getFile(); + + byte[] largeData = ImageToCArrayConverter.convertImageToCArray(file.getInputStream(), 160, 80, 25600); + + log.info("长度:" + largeData.length); + // 在获取 largeData 后,将其与前缀合并 + byte[] prefix = new byte[]{0x50, 0x49, 0x43, 0x54, 0x55, 0x52, 0x45}; // "PICTURE" + byte[] combinedData = new byte[prefix.length + largeData.length]; + System.arraycopy(prefix, 0, combinedData, 0, prefix.length); + System.arraycopy(largeData, 0, combinedData, prefix.length, largeData.length); + + // 将 combinedData 转换为十六进制表示 + String[] hexArray = new String[combinedData.length]; + for (int i = 0; i < combinedData.length; i++) { + hexArray[i] = String.format("0x%02X", combinedData[i]); + } +// Map map = new HashMap<>(); +// map.put("instruct", combinedData); + String[] specificChunk = ImageToCArrayConverter.getChunk2(hexArray, 0, bo.getChunkSize()); + mqttGateway.sendMsgToMqtt(MqttConstants.GLOBAL_PUB_KEY + device.getDeviceImei(), 1, Arrays.toString(specificChunk)); + log.info("发送点阵数据到设备消息=>topic:{},payload:{}", MqttConstants.GLOBAL_PUB_KEY + device.getDeviceImei(), Arrays.toString(specificChunk)); + + recordDeviceLog(device.getId(), device.getDeviceName(), "上传开机画面", "上传开机画面", AppLoginHelper.getUserId()); + } catch (Exception e) { + e.printStackTrace(); + throw new ServiceException("发送指令失败"); + } + } + + @Override + public void uploadDeviceLogo(AppDeviceLogoUploadDto bo) { + try { + Device device = deviceMapper.selectById(bo.getDeviceId()); + if (device == null) { + throw new ServiceException("设备不存在"); + } + if (getDeviceStatus(device.getDeviceImei())) { +// throw new ServiceException(device.getDeviceName()+",设备已断开连接"); + log.info(device.getDeviceName() + ",设备已断开连接"); + recordDeviceLog(device.getId(), device.getDeviceName(), "上传开机画面", device.getDeviceName() + ",设备已断开连接", AppLoginHelper.getUserId()); + return; + } + MultipartFile file = bo.getFile(); + + byte[] largeData = ImageToCArrayConverter.convertImageToCArray(file.getInputStream(), 160, 80, 25600); + log.info("长度:" + largeData.length); + + log.info("原始数据大小: {} 字节", largeData.length); + + int[] ints = convertHexToDecimal(largeData); + RedisUtils.setCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + DEVICE_BOOT_LOGO_KEY_PREFIX, Arrays.toString(ints), Duration.ofSeconds(5 * 60L)); + + String data = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + device.getDeviceImei() + DEVICE_BOOT_LOGO_KEY_PREFIX); + + byte[] arr = ImageToCArrayConverter.convertStringToByteArray(data); + byte[] specificChunk = ImageToCArrayConverter.getChunk(arr, 0, 512); + log.info("第0块数据大小: {} 字节", specificChunk.length); +// log.info("第0块数据: {}", Arrays.toString(specificChunk)); + + ArrayList intData = new ArrayList<>(); + intData.add(3); + intData.add(1); + ImageToCArrayConverter.buildArr(convertHexToDecimal(specificChunk), intData); + intData.add(0); + intData.add(0); + intData.add(0); + intData.add(0); + Map map = new HashMap<>(); + map.put("instruct", intData); + mqttGateway.sendMsgToMqtt(MqttConstants.GLOBAL_PUB_KEY + device.getDeviceImei(), 1, JSON.toJSONString(map)); + log.info("发送点阵数据到设备消息=>topic:{},payload:{}", MqttConstants.GLOBAL_PUB_KEY + device.getDeviceImei(), JSON.toJSONString(map)); + + recordDeviceLog(device.getId(), device.getDeviceName(), "上传开机画面", "上传开机画面", AppLoginHelper.getUserId()); + } catch (Exception e) { + e.printStackTrace(); + throw new ServiceException("发送指令失败"); + } + } + + /** + * 灯光模式 + * 0(关灯),1(强光模式),2(弱光模式), 3(爆闪模式), 4(泛光模式) + */ + @Override + public void lightModeSettings(DeviceInstructDto params) { + try { + Long deviceId = params.getDeviceId(); + Device device = deviceMapper.selectById(deviceId); + if (device == null) { + throw new ServiceException("设备不存在"); + } + if (getDeviceStatus(device.getDeviceImei())) { + throw new ServiceException(device.getDeviceName() + ",设备已断开连接"); + } + Integer instructValue = Integer.parseInt(params.getInstructValue()); + ArrayList intData = new ArrayList<>(); + intData.add(1); + intData.add(instructValue); + intData.add(0); + intData.add(0); + intData.add(0); + Map map = new HashMap<>(); + map.put("instruct", intData); + mqttGateway.sendMsgToMqtt(MqttConstants.GLOBAL_PUB_KEY + device.getDeviceImei(), 1, JSON.toJSONString(map)); + log.info("发送点阵数据到设备消息=>topic:{},payload:{}", MqttConstants.GLOBAL_PUB_KEY + device.getDeviceImei(), JSON.toJSONString(map)); + LightModeEnum modeEnum = LightModeEnum.getByCode(instructValue); + recordDeviceLog(device.getId(), device.getDeviceName(), "灯光模式", modeEnum != null ? modeEnum.getName() : null, AppLoginHelper.getUserId()); + } catch (Exception e) { + e.printStackTrace(); + throw new ServiceException("发送指令失败"); + } + } + + // 灯光亮度设置 + @Override + public void lightBrightnessSettings(DeviceInstructDto params) { + try { + Long deviceId = params.getDeviceId(); + Device device = deviceMapper.selectById(deviceId); + if (device == null) { + throw new ServiceException("设备不存在"); + } + if (getDeviceStatus(device.getDeviceImei())) { + throw new ServiceException(device.getDeviceName() + ",设备已断开连接"); + } + String instructValue = params.getInstructValue(); + ArrayList intData = new ArrayList<>(); + intData.add(5); + String[] values = instructValue.split("\\."); + String value1 = values[0]; + String value2 = values[1]; + if (StringUtils.isNoneBlank(value1)) { + intData.add(Integer.parseInt(value1)); + } + if (StringUtils.isNoneBlank(value2)) { + intData.add(Integer.parseInt(value2)); + } + intData.add(0); + intData.add(0); + intData.add(0); + Map map = new HashMap<>(); + map.put("instruct", intData); + mqttGateway.sendMsgToMqtt(MqttConstants.GLOBAL_PUB_KEY + device.getDeviceImei(), 1, JSON.toJSONString(map)); + log.info("发送点阵数据到设备消息=>topic:{},payload:{}", MqttConstants.GLOBAL_PUB_KEY + device.getDeviceImei(), JSON.toJSONString(map)); + + } catch (Exception e) { + e.printStackTrace(); + throw new ServiceException("发送指令失败"); + } + } + + // 激光模式设置 + @Override + public void laserModeSettings(DeviceInstructDto params) { + try { + Long deviceId = params.getDeviceId(); + Device device = deviceMapper.selectById(deviceId); + if (device == null) { + throw new ServiceException("设备不存在"); + } + if (getDeviceStatus(device.getDeviceImei())) { + throw new ServiceException(device.getDeviceName() + ",设备已断开连接"); + } + Integer instructValue = Integer.parseInt(params.getInstructValue()); + ArrayList intData = new ArrayList<>(); + intData.add(4); + intData.add(instructValue); + intData.add(0); + intData.add(0); + intData.add(0); + Map map = new HashMap<>(); + map.put("instruct", intData); + mqttGateway.sendMsgToMqtt(MqttConstants.GLOBAL_PUB_KEY + device.getDeviceImei(), 1, JSON.toJSONString(map)); + log.info("发送点阵数据到设备消息=>topic:{},payload:{}", MqttConstants.GLOBAL_PUB_KEY + device.getDeviceImei(), JSON.toJSONString(map)); + // 1代表开启激光灯,此时主灯关闭,主灯控件为关机状态,为0代表关闭激光灯 + if ("1".equals(params.getInstructValue())) { + recordDeviceLog(device.getId(), device.getDeviceName(), "激光模式设置", "开启激光灯", AppLoginHelper.getUserId()); + } else { + recordDeviceLog(device.getId(), device.getDeviceName(), "激光模式设置", "关闭激光灯", AppLoginHelper.getUserId()); + } + } catch (Exception e) { + e.printStackTrace(); + throw new ServiceException("发送指令失败"); + } + } + + @Override + public String mapReverseGeocoding(DeviceInstructDto params) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("device_imei", params.getDeviceImei()); + List devices = deviceMapper.selectList(queryWrapper); + if (ObjectUtils.length(devices) == 0) { + throw new ServiceException("设备不存在"); + } + return RedisUtils.getCacheObject("device:location:" + devices.get(0).getDeviceImei()); + } + + @Override + public int sendAlarmMessage(AppDeviceSendMsgBo bo) { + try { + List deviceIds = bo.getDeviceIds(); + if (deviceIds == null || deviceIds.isEmpty()) { + throw new ServiceException("请选择设备"); + } + + for (Long deviceId : deviceIds) { + Device device = deviceMapper.selectById(deviceId); + if (device == null) { + throw new ServiceException("设备不存在" + deviceId); + } + if (getDeviceStatus(device.getDeviceImei())) { + throw new ServiceException(device.getDeviceName() + ",设备已断开连接"); + } + try { + + ArrayList intData = new ArrayList<>(); + intData.add(7); + intData.add(Integer.parseInt(bo.getInstructValue())); + intData.add(0); + intData.add(0); + intData.add(0); + intData.add(0); + Map map = new HashMap<>(); + map.put("instruct", intData); + mqttGateway.sendMsgToMqtt(MqttConstants.GLOBAL_PUB_KEY + device.getDeviceImei(), 1, JSON.toJSONString(map)); + log.info("发送点阵数据到设备消息=>topic:{},payload:{}", MqttConstants.GLOBAL_PUB_KEY + device.getDeviceImei(), JSON.toJSONString(map)); + + UpdateWrapper updateWrapper = new UpdateWrapper<>(); + updateWrapper.eq("id", deviceId) + .set("send_msg", bo.getSendMsg()); + deviceMapper.update(updateWrapper); + if ("0".equals(bo.getInstructValue())) { + recordDeviceLog(device.getId(), device.getDeviceName(), "解除告警信息", "关闭设备", AppLoginHelper.getUserId()); + } else { + recordDeviceLog(device.getId(), device.getDeviceName(), "发送告警信息", bo.getSendMsg(), AppLoginHelper.getUserId()); + } + } catch (Exception e) { + log.info("设备发送告警信息信息失败:{}", deviceId); + throw new ServiceException("设备发送告警信息信息失败"); + } + messageSending(device.getDeviceImei()); + } + + } catch (Exception e) { + e.printStackTrace(); + throw new ServiceException("发送告警信息指令失败"); + } + return 1; + } + + @Override + public void messageSending(String deviceImei) { + String sendMessageIng = GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + deviceImei + ":messageSending"; + RedisUtils.setCacheObject(sendMessageIng, "1", Duration.ofDays(1)); + } + + @Override + public boolean getDeviceStatus(String deviceImei) { + String deviceOnlineStatusRedisKey = GlobalConstants.GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + deviceImei + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX; + return RedisUtils.getCacheObject(deviceOnlineStatusRedisKey) == null; + } + + @Override + public void batchUploadLogo(AppDeviceLogoUploadDto bo) { + + List deviceIds = bo.getDeviceIds(); + MultipartFile file = bo.getFile(); + if (deviceIds == null || deviceIds.isEmpty()) { + throw new ServiceException("请选择设备"); + } + for (Long deviceId : deviceIds) { + AppDeviceLogoUploadDto dto = new AppDeviceLogoUploadDto(); + dto.setDeviceId(deviceId); + dto.setFile(file); + uploadDeviceLogo(dto); + } + } + +} diff --git a/fys-admin/src/main/resources/application-dev.yml b/fys-admin/src/main/resources/application-dev.yml index 40b7f28..169c4bf 100644 --- a/fys-admin/src/main/resources/application-dev.yml +++ b/fys-admin/src/main/resources/application-dev.yml @@ -52,32 +52,32 @@ spring: url: jdbc:mysql://47.120.79.150:3306/fys-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true username: root password: Jq_123456# -# # 从库数据源 -# slave: -# lazy: true -# type: ${spring.datasource.type} -# driverClassName: com.mysql.cj.jdbc.Driver -# url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true -# username: -# password: -# oracle: -# type: ${spring.datasource.type} -# driverClassName: oracle.jdbc.OracleDriver -# url: jdbc:oracle:thin:@//localhost:1521/XE -# username: ROOT -# password: root -# postgres: -# type: ${spring.datasource.type} -# driverClassName: org.postgresql.Driver -# url: jdbc:postgresql://localhost:5432/postgres?useUnicode=true&characterEncoding=utf8&useSSL=true&autoReconnect=true&reWriteBatchedInserts=true -# username: root -# password: root -# sqlserver: -# type: ${spring.datasource.type} -# driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver -# url: jdbc:sqlserver://localhost:1433;DatabaseName=tempdb;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true -# username: SA -# password: root + # # 从库数据源 + # slave: + # lazy: true + # type: ${spring.datasource.type} + # driverClassName: com.mysql.cj.jdbc.Driver + # url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true + # username: + # password: + # oracle: + # type: ${spring.datasource.type} + # driverClassName: oracle.jdbc.OracleDriver + # url: jdbc:oracle:thin:@//localhost:1521/XE + # username: ROOT + # password: root + # postgres: + # type: ${spring.datasource.type} + # driverClassName: org.postgresql.Driver + # url: jdbc:postgresql://localhost:5432/postgres?useUnicode=true&characterEncoding=utf8&useSSL=true&autoReconnect=true&reWriteBatchedInserts=true + # username: root + # password: root + # sqlserver: + # type: ${spring.datasource.type} + # driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver + # url: jdbc:sqlserver://localhost:1433;DatabaseName=tempdb;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true + # username: SA + # password: root hikari: # 最大连接池数量 maxPoolSize: 20 @@ -177,12 +177,12 @@ sms: access-key-id: LTAI5tJdDNpZootsPQ5hdELx # 称为accessSecret有些称之为apiSecret access-key-secret: mU4WtffcCXpHPz5tLwQpaGtLsJXONt - #模板ID 非必须配置,如果使用sendMessage的快速发送需此配置 + #模板ID 非必须配置,如果使用sendMessage的快速发送需此配置 template-id: SMS_322180518 - #模板变量 上述模板的变量 + #模板变量 上述模板的变量 templateName: code - signature: 湖北星汉研创科技 -# sdk-app-id: 您的sdkAppId + signature: 湖北星汉研创科技 + # sdk-app-id: 您的sdkAppId config2: # 厂商标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分 supplier: tencent @@ -210,7 +210,7 @@ justauth: client-id: 449c4*********937************759 client-secret: ac7***********1e0************28d redirect-uri: ${justauth.address}/social-callback?source=topiam - scopes: [openid, email, phone, profile] + scopes: [ openid, email, phone, profile ] qq: client-id: 10**********6 client-secret: 1f7d08**********5b7**********29e @@ -276,33 +276,20 @@ justauth: redirect-uri: ${justauth.address}/social-callback?source=gitea -# 文件存储路径 -file: - mac: - path: ~/file/ - avatar: ~/avatar/ - linux: - path: /home/eladmin/file/ - avatar: /home/eladmin/avatar/ - windows: - path: C:\eladmin\file\ - avatar: C:\eladmin\avatar\ - # 文件大小 /M - maxSize: 100 - avatarMaxSize: 5 - device: - pic: C:\eladmin\file\ #设备图片存储路径 - ip: http://fuyuanshen.com:81/ #服务器地址 - app_avatar: - pic: C:\eladmin\file\ #设备图片存储路径 - #ip: http://fuyuanshen.com:81/ #服务器地址 - ip: https://fuyuanshen.com/ #服务器地址 # MQTT配置 mqtt: username: admin - password: #YtvpSfCNG - url: tcp://www.cnxhyc.com:2883 + password: fys123456 + url: tcp://47.107.152.87:1883 subClientId: fys_subClient - subTopic: A/# - pubTopic: B/# - pubClientId: fys_pubClient \ No newline at end of file + subTopic: A/#,status/tenantCode/#,report/tenantCode/# + pubTopic: B/#,command/tenantCode/# + pubClientId: fys_pubClient + + + # TTS语音交互配置 +alibaba: + tts: + appKey: KTwSUKMrf2olFfjC + akId: LTAI5t6RsfCvQh57qojzbEoe + akSecret: MTqvK2mXYeCRkl1jVPndiNumyaad0R \ No newline at end of file diff --git a/fys-admin/src/main/resources/application-prod.yml b/fys-admin/src/main/resources/application-prod.yml index 97df444..380503d 100644 --- a/fys-admin/src/main/resources/application-prod.yml +++ b/fys-admin/src/main/resources/application-prod.yml @@ -294,24 +294,3 @@ alibaba: akId: LTAI5t6RsfCvQh57qojzbEoe akSecret: MTqvK2mXYeCRkl1jVPndiNumyaad0R -# 文件存储路径 -file: - mac: - path: ~/file/ - avatar: ~/avatar/ - linux: - path: /home/eladmin/file/ - avatar: /home/eladmin/avatar/ - windows: - path: C:\eladmin\file\ - avatar: C:\eladmin\avatar\ - # 文件大小 /M - maxSize: 100 - avatarMaxSize: 5 - device: - pic: C:\eladmin\file\ #设备图片存储路径 - ip: http://fuyuanshen.com:81/ #服务器地址 - app_avatar: - pic: C:\eladmin\file\ #设备图片存储路径 - #ip: http://fuyuanshen.com:81/ #服务器地址 - ip: https://fuyuanshen.com/ #服务器地址 \ No newline at end of file diff --git a/fys-admin/src/main/resources/josn b/fys-admin/src/main/resources/josn new file mode 100644 index 0000000..4ae9975 --- /dev/null +++ b/fys-admin/src/main/resources/josn @@ -0,0 +1,10 @@ +{ + "requestId": "123456789", + "imei": "864865082081523", +"timestamp": 1761025080000, + "funcType": "1", + "data": { + "mainLightMode": 1, + "mainLightBrightness": 100 + } +} \ No newline at end of file diff --git a/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/vo/AppDevice6075DetailVo.java b/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/vo/AppDevice6075DetailVo.java new file mode 100644 index 0000000..1dfda61 --- /dev/null +++ b/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/vo/AppDevice6075DetailVo.java @@ -0,0 +1,120 @@ +package com.fuyuanshen.app.domain.vo; + +import cn.idev.excel.annotation.ExcelProperty; +import lombok.Data; + +import java.io.Serial; + +@Data +public class AppDevice6075DetailVo { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 设备ID + */ + @ExcelProperty(value = "设备ID") + private Long deviceId; + + /** + * 设备名称 + */ + private String deviceName; + + /** + * 设备IMEI + */ + private String deviceImei; + + /** + * 设备MAC + */ + private String deviceMac; + + /** + * 通讯方式 0:4G;1:蓝牙,2 4G&蓝牙 + */ + private Integer communicationMode; + + /** + * 设备图片 + */ + private String devicePic; + + /** + * 设备类型 + */ + private String typeName; + + /** + * 蓝牙名称 + */ + private String bluetoothName; + + /** + * 设备状态 + * 0 失效 + * 1 正常 + */ + private Integer deviceStatus; + + /** + * 人员信息 + */ + private AppPersonnelInfoVo personnelInfo; + + /** + * 发送信息 + */ + private String sendMsg; + + //"{\"deviceImei\":\"AA\",\"mainLightMode\":\"1\",\"laserLightMode\":\"0\",\"batteryPercentage\":\"60\",\"chargeState\":\"1\",\"batteryRemainingTime\":\"200\",\"timestamp\":1753871635241}" + // 设备主灯档位 + private String mainLightMode; + + // 激光灯档位 + private String laserLightMode; + + // 电量百分比 + private String batteryPercentage; + + // 充电状态(0没有充电,1正在充电,2为已充满) + private String chargeState; + + // 电池剩余续航时间200分钟 + private String batteryRemainingTime; + + /** + * 在线状态(0离线,1在线) + */ + private Integer onlineStatus; + + // 经度 + private String longitude; + + // 纬度 + private String latitude; + + // 逆解析地址 + private String address; + + /** + * 告警状态(0解除告警,1告警) + */ + private String alarmStatus; + + // 灯光亮度 + private String lightBrightness; + + /** + * 海拔高度 + */ + private Double altitude; + + /** + * 相对高度 + */ + private Double relativeAltitude; + +} diff --git a/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/vo/AppDeviceShareDetailVo.java b/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/vo/AppDeviceShareDetailVo.java index fe933ee..2fac8dc 100644 --- a/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/vo/AppDeviceShareDetailVo.java +++ b/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/vo/AppDeviceShareDetailVo.java @@ -45,8 +45,7 @@ public class AppDeviceShareDetailVo implements Serializable { private String phonenumber; /** - * 功能权限(1:灯光模式;2:激光模式;3:开机画面;4:人员信息登记;5:发送信息;6:产品信息) -以逗号分隔 + * 功能权限(1:灯光模式;2:激光模式;3:开机画面;4:人员信息登记;5:发送信息;6:产品信息)以逗号分隔 */ @ExcelProperty(value = "功能权限", converter = ExcelDictConvert.class) @ExcelDictFormat(readConverterExp = "1=:灯光模式;2:激光模式;3:开机画面;4:人员信息登记;5:发送信息;6:产品信息") @@ -83,7 +82,7 @@ public class AppDeviceShareDetailVo implements Serializable { private String typeName; /** - * 蓝牙名称 + * 蓝牙名称 */ private String bluetoothName; @@ -105,19 +104,19 @@ public class AppDeviceShareDetailVo implements Serializable { */ private String sendMsg; - //设备主灯档位 + // 设备主灯档位 private String mainLightMode; - //激光灯档位 + // 激光灯档位 private String laserLightMode; - //电量百分比 + // 电量百分比 private String batteryPercentage; - //充电状态(0没有充电,1正在充电,2为已充满) + // 充电状态(0没有充电,1正在充电,2为已充满) private String chargeState; - //电池剩余续航时间200分钟 + // 电池剩余续航时间200分钟 private String batteryRemainingTime; /** diff --git a/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/vo/AppPersonnelInfoVo.java b/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/vo/AppPersonnelInfoVo.java index bbbabfa..f35ec26 100644 --- a/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/vo/AppPersonnelInfoVo.java +++ b/fys-modules/fys-app/src/main/java/com/fuyuanshen/app/domain/vo/AppPersonnelInfoVo.java @@ -64,5 +64,4 @@ public class AppPersonnelInfoVo implements Serializable { @ExcelProperty(value = "ID号") private String code; - } diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/dto/AppDeviceBo.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/dto/AppDeviceBo.java index 5f440df..0e63112 100644 --- a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/dto/AppDeviceBo.java +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/dto/AppDeviceBo.java @@ -12,6 +12,7 @@ import lombok.EqualsAndHashCode; */ @Data public class AppDeviceBo { + /** * 设备IMEI */ @@ -25,10 +26,11 @@ public class AppDeviceBo { /** * 通讯方式 0:4G;1:蓝牙,2 4G&蓝牙 */ - @NotNull(message = "通讯方式不能为空", groups = { EditGroup.class }) + @NotNull(message = "通讯方式不能为空", groups = {EditGroup.class}) private Integer communicationMode; private String sendMsg; private Long deviceId; + } diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/vo/AppDeviceVo.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/vo/AppDeviceVo.java index 760fc3a..214fd8a 100644 --- a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/vo/AppDeviceVo.java +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/vo/AppDeviceVo.java @@ -86,4 +86,5 @@ public class AppDeviceVo implements Serializable { * 设备详情页面 */ private String detailPageUrl; + } diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/vo/DataOverviewVo.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/vo/DataOverviewVo.java index c4b6d39..c5be92f 100644 --- a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/vo/DataOverviewVo.java +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/vo/DataOverviewVo.java @@ -3,7 +3,7 @@ package com.fuyuanshen.equipment.domain.vo; import lombok.Data; /** - * 数据总览 + * 首页数据总览 * * @author: 默苍璃 * @date: 2025-09-0114:24 diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/vo/WebDeviceVo.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/vo/WebDeviceVo.java index 5aaa405..9f29bef 100644 --- a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/vo/WebDeviceVo.java +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/vo/WebDeviceVo.java @@ -58,7 +58,6 @@ public class WebDeviceVo implements Serializable { */ private Integer deviceStatus; - /**绑定状态 * 0 未绑定 * 1 已绑定 diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceRepairRecordsServiceImpl.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceRepairRecordsServiceImpl.java index 80ff0fe..ecc7007 100644 --- a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceRepairRecordsServiceImpl.java +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceRepairRecordsServiceImpl.java @@ -50,6 +50,7 @@ public class DeviceRepairRecordsServiceImpl extends ServiceImpl impleme private final ISysRoleService roleService; - @Value("${file.device.pic}") - private String filePath; - @Value("${file.device.ip}") - private String ip; - private final DeviceMapper deviceMapper; private final DeviceTypeMapper deviceTypeMapper; private final CustomerMapper customerMapper; @@ -84,6 +80,7 @@ public class DeviceServiceImpl extends ServiceImpl impleme private final DeviceTypeGrantsMapper deviceTypeGrantsMapper; private final DeviceFenceAccessRecordMapper deviceFenceAccessRecordMapper; + private final FileHashUtil fileHashUtil; /** @@ -209,7 +206,8 @@ public class DeviceServiceImpl extends ServiceImpl impleme // 保存图片并获取URL if (deviceForm.getFile() != null) { - SysOssVo upload = ossService.upload(deviceForm.getFile()); + String fileHash = fileHashUtil.hash(deviceForm.getFile()); + SysOssVo upload = ossService.updateHash(deviceForm.getFile(),fileHash); // 设置图片路径 deviceForm.setDevicePic(upload.getUrl()); } @@ -283,8 +281,8 @@ public class DeviceServiceImpl extends ServiceImpl impleme // 处理上传的图片 if (deviceForm.getFile() != null) { - // 设置图片路径 - SysOssVo oss = ossService.upload(deviceForm.getFile()); + String fileHash = fileHashUtil.hash(deviceForm.getFile()); + SysOssVo oss = ossService.updateHash(deviceForm.getFile(),fileHash); // 强制将HTTP替换为HTTPS if (oss.getUrl() != null && oss.getUrl().startsWith("http://")) { oss.setUrl(oss.getUrl().replaceFirst("^http://", "https://")); @@ -301,35 +299,6 @@ public class DeviceServiceImpl extends ServiceImpl impleme } - /** - * 保存设备图片并返回访问路径 - * - * @param file MultipartFile - * @param deviceMac 设备MAC用于生成唯一文件名 - * @return 文件存储路径 URL 形式 - */ - private String saveDeviceImage(MultipartFile file, String deviceMac) throws IOException { - if (file == null || file.isEmpty()) { - return null; - } - - String originalFileName = file.getOriginalFilename(); - String fileExtension = originalFileName.substring(originalFileName.lastIndexOf(".") + 1); - String newFileName = "PS_" + deviceMac + "." + fileExtension; - - File newFile = new File(filePath + DeviceConstants.FILE_ACCESS_ISOLATION + File.separator + newFileName); - - if (!newFile.getParentFile().exists()) { - newFile.getParentFile().mkdirs(); - } - - log.info("图片保存路径: {}", newFile.getAbsolutePath()); - file.transferTo(newFile); - - return ip + DeviceConstants.FILE_ACCESS_PREFIX + "/" + DeviceConstants.FILE_ACCESS_ISOLATION + "/" + newFileName; - } - - /** * 删除设备 * diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/utils/FileHashUtil.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/utils/FileHashUtil.java index 77011b8..1e6666f 100644 --- a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/utils/FileHashUtil.java +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/utils/FileHashUtil.java @@ -1,28 +1,70 @@ package com.fuyuanshen.equipment.utils; import org.apache.commons.codec.digest.DigestUtils; +import org.springframework.stereotype.Component; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; import java.io.InputStream; import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.HexFormat; /** * 文件哈希工具类 */ +@Component // 如果使用 Spring 可以注入 public class FileHashUtil { + /* 算法常量 */ private static final String ALGORITHM = "SHA-256"; + /* 缓冲区大小 8 KB */ + private static final int BUFFER_SIZE = 8192; - public static String hash(MultipartFile file) throws IOException { - MessageDigest digest = DigestUtils.getDigest(ALGORITHM); + /** + * 计算上传文件的 SHA-256 十六进制哈希 + * + * @param file 上传文件;不能为 null,且必须非空 + * @return 64 位小写十六进制字符串 + * @throws IllegalArgumentException 参数不合法 + * @throws IOException 流读取失败 + * @throws IllegalStateException 算法运行时异常(不会触发) + */ + public String hash(MultipartFile file) throws IOException { + validate(file); + + /* 每个请求新建实例,保证线程安全 */ + MessageDigest digest = newDigest(); + + /* try-with-resources 自动关闭流 */ try (InputStream in = file.getInputStream()) { - byte[] buf = new byte[8192]; + byte[] buf = new byte[BUFFER_SIZE]; int len; while ((len = in.read(buf)) != -1) { digest.update(buf, 0, len); } } + + /* JDK 17+ 的 HexFormat,比 Apache Commons 更快且无需额外依赖 */ return HexFormat.of().formatHex(digest.digest()); } + + /* -------------------- 私有辅助方法 -------------------- */ + + private static void validate(MultipartFile file) { + if (file == null) { + throw new IllegalArgumentException("MultipartFile 不能为 null"); + } + if (file.isEmpty()) { + throw new IllegalArgumentException("上传文件不能为空"); + } + } + + private static MessageDigest newDigest() { + try { + return MessageDigest.getInstance(ALGORITHM); + } catch (NoSuchAlgorithmException e) { + /* SHA-256 是 JDK 必现算法,走到这里说明 JDK 实现损坏 */ + throw new IllegalStateException("算法 " + ALGORITHM + " 不可用", e); + } + } } diff --git a/fys-modules/fys-equipment/src/main/resources/mapper/equipment/DeviceMapper.xml b/fys-modules/fys-equipment/src/main/resources/mapper/equipment/DeviceMapper.xml index eb66b48..b57f59e 100644 --- a/fys-modules/fys-equipment/src/main/resources/mapper/equipment/DeviceMapper.xml +++ b/fys-modules/fys-equipment/src/main/resources/mapper/equipment/DeviceMapper.xml @@ -227,6 +227,7 @@ FROM device WHERE original_device_id = #{originalDeviceId} + +